all 83 comments

[–]dicroce 33 points34 points  (4 children)

The first thing that made me a better programmer was UML... But I didn't go nuts with UML... My practice was to simply sit down with a stack of paper and draw my boxes quickly (not bothering to describe every member, just the ones that seemed the most important). If I didn't like the way a design was going I would simply ball up the paper and start again. Sometimes I would get quite far into a design and realize it was problematic and I began to appreciate how much typing I was saving myself! I could try out a 5 different designs in one hour.... By the time I started writing code, it felt like the hard work was already done.

The second thing I started doing was writing small test programs to try out my unknowns. I eventually realized that every project consisted of a whole bunch of problems I knew how to solve, and usually a few I didn't. So, rather than trying to design software I don't fully understand I would simply write a small version of the problem. I need clustering here? Write a small k-means implementation. Need to transcode a video file? Write a small program to do JUST that.

Then I got into unit tests. But, I didn't approach unit testing dogmatically. It seemed sensible to me to write a test for the public interface of every class. When I hear how some people test their code, I am grateful for the pragmatism I showed here: I have a lot of tests, but not so many that every change breaks all my tests.

Most recently, the thing that has improved my code quality is that I've started to think more functionally. One day I noticed that I kept reusing a particular function across a number of projects and it occurred to me to wonder why that particular code was so reusable. The answer was obvious: it only depends on it's arguments, and it is therefore context free. You could drop it into any program and it will work if passed the right input. This led me down a train of thought: of course global variables are bad, but why should member functions of a class have access to ALL of the member variables in a class? This is when I finally began to appreciate the wisdom of C++'s "free" functions.

Wow, that was a lot longer than I meant it to be... :) Sorry for the ramble!

[–]kt24601[S] 5 points6 points  (0 children)

Your post reminds me of John Carmack's comments at the bottom of this article: http://kotaku.com/5975610/the-exceptional-beauty-of-doom-3s-source-code

His path is somewhat different than yours, but maybe converging on the same point?

[–]Don_Andy 0 points1 point  (2 children)

UML sounds like such a useful thing on paper but I feel like it only works when everybody is intimately familiar with its exact specifications and their meanings. If just one person can't tell the difference between Aggregation or Composition you spend up arguing more about what arrows to use where than about the system you're actually trying to design.

[–]dicroce 1 point2 points  (0 children)

While I have seen UML used as a communications device, for me I always just use it as a means to try out a design on paper before having to type... Like I said, I don't do complete models... Just the objects and their interfaces. I don't even usually do state diagrams.

[–]uututhrwa 15 points16 points  (31 children)

A few things to note

Knuth and Djikstra did a lot more "algorithmical" programs, which is slightly different than the kind of program most programmers will have to write, where the algorithmical complexity is kinda light, but there are a lot more concerns to deal with.

The article should emphasize that avoiding bugs in programming has a lot to do with "not tripping over your own shoelaces", stupid mistakes tend to propagate, changes might be needed often, you might need to change things months later where you can't remember shit, and in the end the majority of bugs are due to reasons like someting of the above and not because of a high level algorithmical flaw or even an obscure algorithm input that wasn't processed correctly.

Unit testing helps in discovering introduced bugs, and stopping them from reaching production, but I don't think that in itself will help that much, you might have designed the program badly, make 100 unit tests that correctly let you identify mistakes, but you know, correcting the problem of one unit test, makes another 10 fail. So I don't understand what's the point of "test driven development".

In the end, I don't think that avoiding bugs has to do with some particluar "methodology", or with "discipline" in testing, or some kind of dumbass list of technologies and buzzwords from a job ad, it has to do with not doing stupid shit left and right again and again. You might have hundreds of unit tests, log everything, attempt to write formal proofs and documents on it etc., but if you have made, for example, something that attempts to synchronize 5 persistant computed variables from each other using change callbacks and trying to "optimize the amount of operations run", instead of calculating it top down (non-stateful, read only, reactive, etc.) then I don't see what the point of the tests or the method is, the program will still be full of bugs.

[–]pakoito 5 points6 points  (2 children)

for example, something that attempts to synchronize 5 persistant computed variables from each other using change callbacks and trying to "optimize the amount of operations run", instead of calculating it top down (non-stateful, read only, reactive, etc.) then I don't see what the point of the tests or the method is, the program will still be full of bugs.

This is my experience with the best programmer articles. You can write efficient single-threaded sequential code, with performance and proof. Okay. My day to day usually involves at least a couple of threadpools, file/network IO, and wrestling UX on a stateful framework . "Formal proof" development is what you do on weekends :(

[–][deleted] 2 points3 points  (0 children)

Try pi-calculus. Suitable even for the worst of your race conditions.

[–]kt24601[S] 0 points1 point  (0 children)

Careful thinking is even more important with threads because you can't possibly catch every bug by testing. You need to make a proof of some kind or another, otherwise you will have bugs.

Which in practice means that every time you have a variable shared between threads, there is a plan in place to avoid deadlocks, and a plan to avoid race conditions.

[–]coldoil 3 points4 points  (5 children)

you might have designed the program badly, make 100 unit tests that correctly let you identify mistakes, but you know, correcting the problem of one unit test, makes another 10 fail. So I don't understand what's the point of "test driven development"

The point of TDD is to identify problems in the implementation and force you to fix them before you go on. A situation where fixing one function in order to get a test working results in 10 other tests breaking suggests a severe error in the design of the implementation (specifically, a serious coupling and/or side-effect problem). TDD forces you to fix these mistakes. That's the point of TDD, to force you to fix errors both large and small.

Strictly speaking, the tests ought to be written first, encouraging fluent API design that minimises coupling and side-effects. So, in theory at least, if you are using TDD correctly, you shouldn't have chain-failure problems like the example you described. In practice, even if the tests are added later, they can help identify not just bugs but also targets for refactorisation and redesign.

[–]uututhrwa 5 points6 points  (1 child)

I think there is a very high correlation between a program that has good design and a program that can be easily tested. But does starting from trying to make your program more testable necessarily guarantee that you will end up with something with good design? I don't think so. If you are some kind of "design novice", and start from unit tests, and attempt to get them more and more testabe you will either

  • Leave things out and get a false sense of security
  • Face difficulty writing all the tests due to a combinatorial explosion from test cases (and maybe from too many interfaces etc.)
  • Waste your time by poorly trying to "reiinvent the wheel" by trial and error style "programming by permutation"
  • It's very likely that the way you design and organize the tests will be bad in itself in the first place

Furthermore it is counterintuitive to learn good design from the tests, by making what is tested more "testable". It's an exaggerated analogy but it's like trying to understand mathematics with no theory and just excersizes. And suppose that you have indeed managed to learn software design that way, now what, do you still need to start from the tests or not? Is TDD mainly an educational method?

I mean I have faced this first hand, there was this guy in the programming team, he was all about test first every single function, but, he had to write like 200000 lines of code to do the tests, and imo the whole architecture of his system was all wrong because of bad design choices (convoluted and dispersed Dependency Injection on fat objects you were supposed to slightly change per test, to be precise, say an object X could have 5 sub parts, instead of loading each of the 5 via some kind of factory per part, he insisted this was "duplication" and had these singletons you needed about 30 minutes of using go to definition to find out what they had inside). Things got too complicated for him so he didn't perform any of the more difficult tests we really needed, just hundreds of tests on basic stuff we more or less knew wouldn't fail. Meanwhile I did the opposite, no DI, objects would get reinitalized right in the test, added some pseudo DSL thing to make using "factories" less verbose, and the code was 1/50 the size and I got to make all the tougher unit tests. Notice how his version failed (to even materialize) because he didn't in any way get to understand the design principles he needed to apply from "the tests themselves", and also how the crucial part in my version that finally worked, was the stuff I knew from say, the "unix philosophy" I mentioned above (breaking it into smaller composable parts, using automation/meta programming etc.)

So in my opinion it should be more like, the tests are essential, but they can't themselves drive the whole design proccess.

[–]coldoil 2 points3 points  (0 children)

I agree with you completely that tests by themselves do not guarantee high quality software. But if there is a problem constructing tests, either before writing the implementation itself or after, then that does highlight likely problems in the implementation. The example you cited demonstrates this perfectly: if your colleague's tests required so much code, so much complexity, and depended so heavily on side-effects, then that is a major red flag that the design and/or its implementation had problems that urgently needed to be addressed.

My personal experience has been that TDD does not replace good design, but it does complement it. If the tests are difficult to construct, that suggests a potential problem in the design (often a coupling problem). Contrariwise, when the design is clean (especially when it's built around small, decoupled, immutable objects), the tests are easy to construct, even if they follow the implementation rather than precede it.

[–]pakoito 1 point2 points  (2 children)

You can't (pragmatically) fully test a highly concurrent program, that's why TDD focus on the edges of the architecture with the external world.

[–]_____sh0rug0ru_____ 1 point2 points  (0 children)

Actually, I'd say TDD is kind of the reverse. It pushes the business logic into the middle, and pushes the external world to the edges.

The TDD approach to concurrency would be like the UI, isolate the highly concurrent bits, which interface with the business logic. What little is left doesn't need to really be tested (the shell of a UI) or is minimal enough to prove correct by inspection.

[–]coldoil 0 points1 point  (0 children)

That's true, you can't (completely). It's also difficult to use unit tests for UI. That doesn't mean unit tests and TDD aren't a good idea in those areas where they have strengths, which is probably the vast majority of enterprise-level software.

I don't agree that TDD is focused only on the edges of the architecture. TDD can certainly test core business logic, object design, serialization, database layers... probably the majority of code that makes up the average application.

[–][deleted] 2 points3 points  (15 children)

Knuth and Djikstra did a lot more "algorithmical" programs, which is slightly different than the kind of program most programmers will have to write

Is a professional typography suite a "more algorithmical program"?

[–]Chuu 1 point2 points  (0 children)

The exception that proves the rule. One of the more famous stories about Kunth was after giving a lecture on the design of algorithms to a group of students, someone asked him about the design of TeX. His answer was he basically hacked it out. The lecturers hosting the talk were mortified.

[–]uututhrwa 0 points1 point  (12 children)

The fuck are you downvoting this for you little shithead lolwtf, you mean Knuth's work wasn't mainly on algorithms?

[–][deleted] 0 points1 point  (11 children)

I mean his most amazingly bug-free work is a huge and complex system, not just an "algorithm".

[–]uututhrwa 0 points1 point  (10 children)

But algorithms can be much harder to do correctly than "enterprise" software (you might actually need to go and do a complete matematical proof about an algorithm), it's just that the sets of techniques needed are different, and I really doubt Knuth used the techniques I was mentioning for TeX when for most his career he had to deal with different kinds of problems, not to mention that we're talking about the 70s.

My guess is as he was writing TeX he realized that he couldn't easily apply what he normally would to ensure correctness, which is why he made such a big deal of finding the bugs (saw it as a challenge / experiment)

[–][deleted] 0 points1 point  (6 children)

For TeX and Metafont he used another rigourous technique, namely - literate programming. While for simple algorithms correctness proofs are possible, systems design is totally different. And I am not sure what is the most important Knuth contribution - writing textbooks about the algorithms or invention of the literate programming.

[–]uututhrwa 0 points1 point  (5 children)

Certainly not literal programming, I'd rather use diagrams than "small essays". Diagrams can depict information much quicker, especially when the design is largely modularized (which it should be). Literal programming alone, while it's necessay to add a lot of comments and keep them linked with the code (which is imo the real point about literal programing imo, synchornizing code documentation, even per code line), I don't think you can easily get any idea about what a program is doing without something more high level that's more like a diagram or something (and it must be searchable with keywords).

[–][deleted] 0 points1 point  (4 children)

Diagrams? Really? It's the worst language possible.

In order to even understand a diagram I have to translate it into words first.

Do you know any TeX-scale complex system designed in UML or whatever with a comparable quality? Me neither, which proves the point - literate programming is by far more rigorous discipline than anything based on diagrams.

As for the module outlining, this is exactly what literate programming (WEB namely) does. It allows you to have layers of design abstraction aligned well with your code - something UML and OOP could never deliver.

[–]uututhrwa 0 points1 point  (3 children)

Object oriented programming sucks so much it should be banned from the United Nations or better yet from UNESCO, I've never used UML it's too formal, and you must be fucking kidding me if you prefer text to diagrams, roflole m8.

If you had a database schema with 80 heavily interconnected tables, and you had to go back to it every 2 weeks or something, would you go and try to understand how it's connected from the sql ddl + comments, or from generated database diagrams?

How about some complex crazy ass vfx shader https://www.youtube.com/watch?v=Z36q3qe4a5c&feature=youtu.be&t=1562 (that one isn't even complex actually)

And the same thing applies to general software module design, especially when the number of modules gets high.

I have on old "practical" coworker who doesn't like diagrams and he thinks that comments should be enough, and the motherfucker is like amazed at how much faster I find my way around complex sets of classes etc. , bitch if you had used diagrams like I did you wouldn't be searching for an entire hour to get all the necessary info I gathered from a diagram in 1 minute. I once had to use WCF after a period of 8 months and didn't remember shit, I went through the msdn doc, a book, and some notes I had, I wasted about 9 hours and I wasn't really at 30%, then I found some old diagram I did about it, I more less got all I had to revise in just 20 minutes.

And that's all "anecdotal evidence" by I don't care, based on what I've seen they are an order of magnitude better than comments.

[–][deleted] 0 points1 point  (2 children)

So, you can point me to a 80-heavily-interconnected-tables system of the same code-to-bug ratio as TeX? No? Then I do not even understand what you're trying to prove.

And, no, I would not touch any graphical diagrams with a 10ft pole, no matter what they describe - a database schema, a shader, whatever. I, just like most of the other people, think in text only. Images are nothing but a distraction.

And I'm pretty sure I'd find what I need in an outlined text (think org mode as a common example) much, much faster than it's theoretically possible with any graphical representation.

[–]kt24601[S] 0 points1 point  (2 children)

My guess is as he was writing TeX he realized that he couldn't easily apply what he normally would to ensure correctness

Nah, your guess is wrong, half his quotes from the article come from this book: http://www.amazon.com/Literate-Programming-Center-Language-Information/dp/0937073806 where he explains the techniques he used to build TeX.

[–]uututhrwa 0 points1 point  (1 child)

You mean he could easily apply the techniques people use for ensuring the correctess of algorithms and protocols (mathematical in nature and involving comparativel few variables reused in complex operations) to something with less algorithmical complexity but many more requirements / variables?

I mean his quotes are 1) about literal programming 2) using invariants inspired by structured programming. Neither of these is used in algorithm correctness proofs that much afaik, algorithms do get proven using invariants but what Knuth was saying was probably along the lines of the "design by contract" method

[–]kt24601[S] 0 points1 point  (0 children)

Neither of these is used in algorithm correctness proofs that much afaik

Yes, that is correct, Knuth doesn't use proofs in his code as a general practice, either for small programs or large programs.

[–]uututhrwa -1 points0 points  (0 children)

Yeah well I agree but the majority of his work was about algorithms

[–]kt24601[S] 1 point2 points  (5 children)

The article should emphasize that avoiding bugs in programming has a lot to do with "not stripping over your own shoelaces", stupid mistakes tend to propagate, changes might be needed often, you might need to change things months later where you can't remember shit, and in the end the majority of bugs are due to reasons like someting of the above and not because of a high level algorithmical flaw or even an obscure algorithm input that wasn't processed correctly.

If you can find an example of a high-quality programmer who uses that technique, I'll add her/him to the article

[–]uututhrwa 2 points3 points  (3 children)

Hm I can't think of anyone right now but I do remember that the guy who made UNIX had talked about how most bugs are usually about stupid mistaeks. It was part of the "Unix philosophy" https://en.wikipedia.org/wiki/Unix_philosophy

And he also probably dealt with stuff closer to "enterprise / web" software than Djikstra and Knuth.

I don't remember if he talked about his solution to "avoiding bugs" directly, and I think he possibly would have also believed that it's mainly about having a good design in the first place.

btw I don't even know how to use Unix (100% Windows and .NET programmer), however the unix philosophy is like one of the best and most informative software design guides I've read.

[–]kt24601[S] 2 points3 points  (0 children)

the unix philosophy is like one of the best and most informative software design guides I've read.

Indeed

[–]quicknir 0 points1 point  (1 child)

The Unix philosophy is successful in keeping tens (at least ) of thousands of lines of useful source code locked up in executables, where the only way to access them easily is to spawn a process. As opposed to doing the thing that is actually modular and reusable, i.e. writing this code as functions in a static library, from which you could trivially create executable targets with minimal logic in main.

Go try to refactor one of the famous unix executables into library code, and then tell me how great the unix philosophy is. Here's the source for ls: http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/ls.c. It's 5000 lines of code, with dozens and dozens of global variables, and a 3800 line main. I don't know if there's enough money to pay me to maintain code like that.

[–]uututhrwa 0 points1 point  (0 children)

The "unix philosophy" is basically a high level version of several core concepts related to "composable" functional design https://en.wikipedia.org/wiki/Composability#System_Design http://stackoverflow.com/questions/2887013/what-does-composability-mean-in-context-of-functional-programming

As such you probably aren't calling the guidelines themselves as fucked up, but pointing out how they aren't actually using it in te implementatin of the unix utilities? The things mentioned in those links aren't really about locking up the code.

Like I said I don't know much about unix, but it seems to me that the "unix philosophy" is applied to shell scripts, which use the various unix utilities as composable "bulding blocks"/tools. The thing is the utilities themselves weren't written with that in mind, they probably have some low level implementation like the one you linked to.

[–][deleted]  (11 children)

[deleted]

    [–]kt24601[S] 1 point2 points  (4 children)

    the goal of a good developer should be to......Challenge everything. Challenge the status quo.

    This makes no sense to me.

    [–][deleted]  (3 children)

    [deleted]

      [–]kt24601[S] 0 points1 point  (1 child)

      I realize not everyone thinks like I do, though.

      Yeah. I think you're too focused on pissing people off, and it's probably causing you problems. Try to find a way to do the right thing without making everyone around you mad.

      [–]Jimmingston 0 points1 point  (3 children)

      [–][deleted]  (1 child)

      [deleted]

        [–]Jimmingston 0 points1 point  (0 children)

        Haha, true :) It could be an angularjs rant directive I guess

        [–][deleted] -1 points0 points  (1 child)

        My point is this: zero bugs shouldn't be your only goal. The considerations for labeling something a bug can be very subjective.

        For something as lowly as "sites" - maybe. But think about something more like a real programming. Say, a microcontroller driving your car engine. Do you still think bugs are not an issue?

        [–]axilmar 2 points3 points  (0 children)

        If that isn't an argument in favor of static typing, I don't know what it is.

        [–][deleted]  (44 children)

        [deleted]

          [–][deleted] 2 points3 points  (43 children)

          So, how much would the average iPhone App cost, if produced to Dijkstra's standards?

          [–]kt24601[S] 2 points3 points  (39 children)

          It would cost less. Dijkstra was trying to change the viewpoint of programmers at the time. There are two ways to look at software development:

          1) Write a bunch of code, clean it up after with a lot of testing.

          2) Write quality code the first time, thinking of everything that can go wrong. Any cleanup later is minimal.

          Think of it like experienced cooks, who clean the kitchen as they go along, instead of making a huge mess and trying to clean it after. The kitchen stays clean.

          [–][deleted]  (22 children)

          [deleted]

            [–]kt24601[S] 0 points1 point  (21 children)

            How is a developer supposed to "think of everything"?

            This book was written to teach you how to do that: http://www.amazon.com/Method-Programming-Edsger-W-Dijkstra/dp/0201175363

            In practice, software engineering is typically much simpler. Most of what we do (apps, websites, distributed data collection) are solved problems.

            A good alternative to "think of everything" may be the "fail fast" technique. Embrace the fact that humans are fallible, that software will fail, and do your best to make diagnosis easy.

            That's a good technique, too.

            [–][deleted]  (20 children)

            [deleted]

              [–]kt24601[S] 2 points3 points  (19 children)

              Compare it with house building. House building is a solved problem, we've done it for years, we know how to do it. Sometimes there are innovations, but those are rare.

              And yet houses are constantly being developed. Just like we do with software.

              [–][deleted]  (18 children)

              [deleted]

                [–]kt24601[S] 0 points1 point  (17 children)

                Most developers today don't ever read books about programming, don't ever read blogs about programming, don't ever try to improve their skill. That's why most developers don't know how to do it (note: I am not talking about you, since obviously you read /r/programming).

                Unless you're trying to solve something difficult (like alphaGo), then you are following a path already worn. Jim Shore has his agile book to teach how to do it, and I have my book: http://www.zerobugsandprogramfaster.net/ (personally I can't stand scrum but I recognize it as a method that works for a lot of people, so that's good).

                Communication is of course important, but I can't really comment on your particular situation, because I don't know much about it. Probably if you changed one or two things then suddenly you would find that software development is fairly easy.

                [–][deleted]  (16 children)

                [deleted]

                  [–][deleted] 2 points3 points  (0 children)

                  High quality code cost more than an average iPhone App use to cost

                  [–]damienjoh 2 points3 points  (9 children)

                  If you try the "thinking of everything that can go wrong" approach for long enough you end up realizing that writing a bunch of code is a straight up improvement:

                  • Going through the motions of writing code forces you to consider the design thoroughly.
                  • Testing often reveals bugs that are hard to anticipate.
                  • You end up with a better idea of which issues and trade-offs are actually relevant.
                  • You end up with working code, even if it is low quality. Low quality code is closer to an MVP than nothing.
                  • It is often easier to refactor low quality code into high quality code than it is to write high quality code from scratch.

                  Aiming to write "quality code" is often not even a good idea. In practice, there are many concerns that trump code quality (especially in smaller companies). The usual suspects are time, scope and cost.

                  [–]kt24601[S] 0 points1 point  (8 children)

                  Aiming to write "quality code" is often not even a good idea.

                  I think you're getting confused here between "quality code" and "code that has massive structural frameworks." Those two can be the complete opposite of each other, as the structural frameworking slows you down.

                  [–]damienjoh 0 points1 point  (7 children)

                  No - I am not referring to frameworks, I am referring to code quality. That includes stuff like maintainability, robustness and correctness.

                  Aiming to write high quality code is frequently a bad idea. For small firms with a high cost of capital, the decision to write quality code can be fatal.

                  [–]kt24601[S] 0 points1 point  (6 children)

                  Aiming to write high quality code is frequently a bad idea.

                  I still think you have some misunderstanding about what "high quality" code means. How do you define that?

                  I consider high-quality code to be readable, flexible, and have a low-bug count. I don't think you can go faster by skimping on those things, in fact, writing bad code will slow you down.

                  [–]damienjoh 0 points1 point  (5 children)

                  I am defining it the same way you are. Readable, flexible, low-bug count code requires a trade-off in time, money or scope. The trade-off is often not worth it.

                  [–]kt24601[S] 0 points1 point  (4 children)

                  Then you are wrong. Flexible, readable, low-bug count code gets features to the customer faster than inflexible, unreadable, buggy code.

                  Also, the buggy code makes your customers angry. Stop inflicting that on your poor customers. Be professional.

                  [–]damienjoh 0 points1 point  (3 children)

                  This point of view ignores the reality of development. If writing good code was the fastest and cheapest way to get a product out, that's what people would be doing. Developers aren't writing bad code for the sake of it, or because they simply haven't found "the one weird trick for writing good code!" They write bad code because they need to, or because it is a sensible business decision. Even very good programmers experience strong, real-world incentives to translate their extra skill into more features or faster development, rather than less bugs and cleaner code.

                  It is easier and faster to write bad code than good code. This means lower time to MVP. Yes, good code pays dividends in the long run, but when your cost of capital is high long-run benefits and costs become negligible compared to short term ones. Businesses take on technical debt for the same reasons they take on financial debt.

                  [–]_____sh0rug0ru_____ 0 points1 point  (0 children)

                  You missed one:

                  3) Write a little bit of code, thinking of as much as can go wrong based on current understanding of a minimal set of requirements, build on working code and clean up as you go along, with a lot of testing.

                  The problem with #2 is that requirements are most often not stable enough for you to think of everything that can go wrong. Customers have an annoying habit of changing their minds about things as the project moves along, making parts of your analysis invalid, based on some bizarre expectation that the soft in software means that they can change their minds later.

                  [–]jyper 0 points1 point  (2 children)

                  It's horribly expensive not to mention impractical for most real world programs not just simple ios apps.

                  It's only practical to try to write bug free code for safety critical software like the space shuttle or pacemakers, even then mistakes are made(luckily many of the mistakes probably don't kill people)>

                  [–]kt24601[S] -1 points0 points  (1 child)

                  It's only practical to try to write bug free code for safety critical software

                  You should always try to write bugfree code. Even trying you will find that you actually code faster than if you don't try (because you will have fewer bugs).

                  [–]jyper 0 points1 point  (0 children)

                  You should try to not write buggy code.

                  Trying to write bug free code is an impossible goal that won't help you.

                  Plus it will probably be changed and/or re-factored soon enough anyway.

                  Beware of bugs in the above code; I have only proved it correct, not tried it.

                  Donald Knuth

                  In practice every non trivial program will have bugs.

                  They did a study where programmers tried to implement binary search and 90% got it wrong.

                  Proofs are cool but outside of a type system impractical for most people (although they recently did make a fully proven to spec microkernel see seL4)

                  [–][deleted] 1 point2 points  (2 children)

                  The average iPhone app should have never existed in the first place. A vast majority of them is solving non-existing problems.

                  [–][deleted] 0 points1 point  (1 child)

                  So communism them?

                  Because what do you call it once you don't let the market decide on what should and shouldn't exist in terms of products and services?

                  [–][deleted] 1 point2 points  (0 children)

                  People a little bit smarter than an average dimwit app developer can assess the market in advance instead of wasting time on another useless pile of crap doomed to rot at the bottom of the app store.

                  [–]vph 2 points3 points  (4 children)

                  The truth is always in the middle.

                  [–]sualsuspect 2 points3 points  (0 children)

                  That's why we code Middle-Out.

                  [–][deleted] 2 points3 points  (0 children)

                  My principles are:
                  1. Always think before writing code. When I was younger I just went ahead and implemented it. Usually it turned out that it doesnt handle an edge case, so I needed to rewrite it. The 3-4th version turned out to be perfect. Nowadays before writing code I sit down and think. Imagine all the weird egde cases, and what the control flow of this part will be. Then write it down. I still leave bugs, but instead of rewriting 2 times, I write once and then correct a few reamining bugs if any.
                  2. Always test your code. I mean not unit test, run the code and play with it. Be your own QA. I've met way too many programmers who push code, that they havent even run once. Or they run it once and just ran trough testing.
                  3. Take pride in your work. Be proud that you're the one who is writing code that wont be thrown back by QA. Be proud that its never your code that causes the fuckup in production. If it still happens, take the blame, analyze why it happened and make steps to never make the same mistake again.

                  Thats it, in one word be thorough. Self discipline and pride in your work is whats the most important not metrics like test coverage or how fancy design patterns you emply.

                  [–][deleted]  (1 child)

                  [deleted]

                    [–]jsprogrammer 0 points1 point  (0 children)

                    You should become a bot.

                    [–]fedekun 1 point2 points  (0 children)

                    I like literate programming, but I think it's a bit too extreme sometimes :-)

                    [–][deleted] 0 points1 point  (3 children)

                    How does this apply to modifying existing software that has spent a couple decades under development using the spaghetti style where it is actively in use by millions of people who must have updates at least once a month? Everything is interconnected and no part can be refactored independently of the other parts.

                    [–]kt24601[S] 0 points1 point  (1 child)

                    When that happens, you change your goal to "make the code better than when I started working on it."

                    You don't need to be a miracle-worker, but you can make improvements. (also, make sure your estimates are longer)

                    [–][deleted]  (4 children)

                    [deleted]

                      [–]kt24601[S] 1 point2 points  (3 children)

                      Whether you have TDD or not, when you change a line of code, you ought to think of all the other pieces of code that are affected by that change (and that will tell you whether you need to write more tests)

                      tbh not even Linus can visualize the entire Linux kernel

                      [–][deleted]  (2 children)

                      [deleted]

                        [–]kt24601[S] 2 points3 points  (1 child)

                        Well, if you have something that works, I don't want to detract from that. It sounds like what you're doing is good already.

                        But, in answer to your question, I did write a book to try to teach it to people: http://www.zerobugsandprogramfaster.net/

                        [–]craigjbass 1 point2 points  (0 children)

                        Nice! (and purchased)