Settings

Theme

Qualities of clean code

blog.goyello.com

192 points by neokya 9 years ago · 165 comments

Reader

ewjordan 9 years ago

Over the years I've seen many more unmaintainable atrocities caused by diligent adherence to these principles than I ever have because of ignorance of them.

All the horrid Java libraries that we hated working with 10 years ago were created because of slavish devotion to the single responsibility principle, short methods, DRY, and testability. The absolute worst codebases I've ever seen sprung from an overaggressive concern for extensibility.

I do agree with the guiding principle, that when you're writing code, it should be written for other people to read and work with. But sometimes that actually does mean that a class should represent an object that does more than one thing, and you shouldn't fight it. Sometimes a gritty algorithm really does make the most sense if it's laid out as a 40 line function in one place rather than spread across 5 different classes so each part is independently swappable and testable. Sometimes you really don't need extensibility, you know that up-front, and building it in just pisses off everyone that ever has to touch your code because now they have to go through five or six "Find implementing classes" dances to find the actual code that runs when your interface methods (of which, of course, there's only a single implementation) are called. Don't even get me started on abuses of dependency injection when it's not necessary...

Part of me is glad that these concepts are so commonly discussed, because they really are good things to consider, and can make code much tidier and easier to work with in the best case. But it takes a lot of experience to know when and where you should and shouldn't follow these "rules", and it tends to be much easier to unwind a novice's spaghetti code and tidy it up than it is to pick apart a poorly conceived tangle of abstraction and put it back together in a way that makes sense.

  • highCs 9 years ago

    So I have a theory that may explains things here. Here it is.

    There is 3 levels of programmers.

    Level 1 is the beginner. A level 1 programmer is barely able to make a complete app or lib. His work simply rarely works. The code has no sense, is full of bugs, it's a complete mess, and the user has a very poor experience (if an experience at all).

    Then comes the level 2 programmer. The novice. The novice learnt about OOP, design patterns, DRY, single responsability principle, importance of testing, etc. The only problem with the level 2 programmer is that he overdoes everything. He is victim of overengineering. He is able to make a complete app with a decent UX and the quality of the code is dramatically better, but his productivity is low. Really, really low. Everything takes month. Every single change is a project. 10 actual lines of codes need to be changed? That's 10 classes, 250 lines of unit tests, it requires 3 classes to be refactored, and on and on.

    Finally, there is the level 3 programmer. The level 3 programmer is a programmer that does level 2 programming in a smarter way. His first principle is less code. That doesn't mean the code must be complete shit, but the level 3 engineer understand the real enemy and that all problems grow with it exponentially: code. The level 3 programmer knows, understand and apply the principles of the level 2 programmer, but he just does the right amount of them. Not too much.

    If he has to, the level 3 programmer gonna err on the side of the level 1 code and will avoid as much as he can level 2 code. That's because level 1 code cost less to fix than level 2 code.

    Now here comes my point: a level 2 programmer read and write articles that is about how to not be a level 1 programmer.

    • whatever_dude 9 years ago

      > If he has to, the level 3 programmer gonna err on the side of the level 1 code and will avoid as much as he can level 2 code. That's because level 1 code cost less to fix than level 2 code.

      I've been doing this recently and had a hard time justifying it even to myself. It just felt right. And you've got it - it's easier to fix dumb code, than refactor an overengineered mess.

      > Now here comes my point: a level 2 programmer read and write articles that is about how to not be a level 1 programmer.

      You're making me understand the current programming "scene" much better, especially the plethora of self-aggrandizing blog posts I tend to see today.

      I wish I could upvote you twice.

      • Jtsummers 9 years ago

        http://www.willamette.edu/~fruehr/haskell/evolution.html

        I disagree that level 1 programmers necessarily produce poor code. But they're stuck at such a low level of understanding of abstractions that they either abuse abstractions to hell (but not in a level 2 sense) or don't use them at all.

        The good level 3 programmer understands that there are times to call a function, times to create class hierarchies, times to create generators, times to use high level abstractions. But they generally err on the side of lower abstractions, or higher abstractions only where they aid clarity, reduces true redundancy, or similar.

        But the most important thing about a level 3 programmer is that they aren't dogmatic. Dogma both frees and constrains the developer. It frees them from the requirement to think, because dogma says "thou shalt" and "thou shalt not". It constrains them because when things fall outside the dogma, they want to make the heretical code conform, or they discard it and start over.

      • mariobertschler 9 years ago

        > it's easier to fix dumb code, than refactor an overengineered mess

        Very True!

        • V-2 9 years ago

          That depends on circumstances really. Yeah it's easy to fix dumb code... unless there's 10 tons of it

          I once worked with about 1.5 million LOC worth of "naive" PHP code. It was one big e-commerce system. The SSOT principle wasn't followed, certain assumptions were scattered all over the place.

          For example the fact that a product could only ever belong to a single size group. The task we were given was to remove this constraint. It took a few man-years of work, because it was hardcoded EVERYWHERE, from database scripts to frontend JS. And don't even get me started on how many bugs angry customers encountered before it got kind of stable.

          It wasn't overengineered, just dumb, and a lot of it. I'd much prefer having to deal with some matryoshka OOP abstractions - they could be merged, simplified etc. In such case there are certain tricks in our disposal. Tricks that scale. If it's just a big ball of mud: not much you can do. It's pretty much a physical job, like counting grains of sand on the beach.

          • qznc 9 years ago

            When you design a system, you always have a tradeoff between flexibility and simplicity. Extreme flexibility means over-engineering and complexity. Simplicity means less flexibility, because of a lot assumptions are hard-coded. The best design is the one which hits the sweet spot: As simple as possible, as flexible as necessary. That requires knowing the future, though.

            If you want to increase flexibility later, like "remove the constraint that a product could only ever belong to a single size group", it inherently means to hunt down all the places where this assumption has been hard-coded.

            Should you err on the side of flexibility or simplicity? Simplicity means the assumption hunt is costly, but maybe you never need it (YAGNI). Err for flexibility, you pay the constant cost of dealing with the API complexity, but you surely avoid some costly assumption hunts.

            Usually, startup prefer simplicity because they will pivot anyways. In contrast, enterprise prefers flexibility, so they can plan years ahead and things stay in the budget.

            • alephnil 9 years ago

              > As simple as possible, as flexible as necessary. That requires knowing the future.

              Knowing the future in this case should usually mean that you have requests for a feature from customers, but you don't have time to do it in this version. At least that is something I find useful as a rule of thumb. If that is not the case, you should really think twice before making it flexible rather than simple.

            • nicholasjon 9 years ago

              > As simple as possible, as flexible as necessary.

              That really resonates with me.

          • ultramancool 9 years ago

            Well said.

            I was recently passed off a project from someone who didn't have a development background but had been working on C++... the amount of copy-paste, repetitive if statements and fixed length arrays makes the original code almost completely unusable and I was forced to suggest a total rewrite.

          • taneq 9 years ago

            > If it's just a big ball of mud: not much you can do. It's pretty much a physical job, like counting grains of sand on the beach.

            You can refactor as you go. It doesn't save you from sifting through the entire ball of mud, but at least it means you won't have to do it again in quite such a bad way.

        • collyw 9 years ago

          I have had nightmares doing both. One of them ongoing.

      • edem 9 years ago

        Same here. I started applying LEAN lately and I'm more productive than ever. I just stopped creating interfaces and as-atomic-as-possible components in favor of simple but sometimes dumb classes which do the heavy lifting and can be easily replaced by more robust code when it is needed.

    • bunderbunder 9 years ago

      There's another dimension that I think you're missing, which is having sensible levels of abstraction.

      A good, easy to understand codebase is one that has a minimal number of components that interact with each other in a well-organized and easty-to-understand manner. Those components, in turn, should each be made of a minimal number of sub-components that interact with each other in a clear, well-organized manner. And on down until you hit bedrock. Doing this is essential because it sets up boundaries that limit the amount of code and interactions that you need to juggle in your head at any one moment.

      A programmer who doesn't understand this will produce horrible, tangled, tightly-coupled code regardless of whether they're doing it with a boiling soup of global variables or a boiling soup composed together from tiny "well-factored" classes that all implement interfaces containing only a single CQRS-compliant method.

      I'd submit that there's another level of programmer, let's call it the SubGenius programmer (because the term tickles me) who thinks that levels 1, 2 and 3 programmers all share a sloppy work ethos and need to spend more time stepping back to keep an eye on how the forest looks instead of obsessing about trees all the time.

    • blowski 9 years ago

      I have to confess that I am probably a level 2 programmer, and the only thing that stops me is pair programming and code reviews. I always start out with good intentions, but the little "what if?" devil on my shoulder whispers things like "What if you need to change that dependency?" and off I go creating an AbstractFactoryFactoryManagerServiceInterface. At the time, his comments just sound so sensible and wise. The only way for me to snap out of it is when the "good programming fairy" is on my other shoulder (probably my colleague) saying "Do you really think that's necessary?"

      • qznc 9 years ago

        Finding the right balance between those is the Art of Design.

        Since ageism is a hot topic now: This is one point where experience pays off. The graybeard has acquired a better gut feeling when something is necessary and when it is not.

      • ultramancool 9 years ago

        This is why I frequently ask up the chain to confirm requirements in a "is it ever possible we might want to do X?" way quite often. Getting outright "no"s will often help to simplify your design and if it comes back to bite you in the ass, you just tell them you asked and will now need additional time to redesign and refactor.

    • 6t6t6t6 9 years ago

      In other words:

      The level 2 programmer knows that the tomato is a fruit. The level 3 programmer knows that it is not a good idea to put it in a fruit salad.

    • the_other 9 years ago

      Please consider replacing all the "he"s with a word less gender-defining ("they", "s/he", "ve" etc). The entire gender spectrum can code if they want to and they should feel included rather than excluded.

      • VarFarYonder 9 years ago

        > Please consider replacing all the "he"s with a word less gender-defining ("they", "s/he", "ve" etc). The entire gender spectrum can code if they want to and they should feel included rather than excluded.

        The vast majority of programmers are male, so (ignoring that he can be used in a gender neutral way) it's natural to use he in such a situation. I'm not saying it's right or wrong -- I'm not sure what influence using gender-specific pronouns has. Although I will say that if someone used she when discussing a field that is dominated by women, like veterinary science, as a man I wouldn't feel excluded or put off from exploring the field if I had an interest in it. It's also interesting to note that the same furor over gender inequality in subjects like computer science isn't replicated when the shoe is on the other foot.

        I think there is a tendency in western culture at the moment to confuse factual differences in behaviour between men and women with ethical issues about equal opportunity. Equal opportunity doesn't necessarily result in a 50/50 gender split in all fields. Christina H. Sommers puts it better than I can: https://www.youtube.com/watch?v=l-6usiN4uoA

        • blowski 9 years ago

          Please please please, for the love of programming, let's not turn this into another one of _those_ conversations. Use it, don't use it, just don't start flame wars.

        • didibus 9 years ago

          Your hypothetical doesn't apply. There's no way for you to know the subconscious impact in the long term that everything being referred with "she" would have on your interest in Veterinary work, if you did have one. It's not something you can mentally put yourself in, and know for sure it would not bother you.

          Also, I think this was kind of apropos. Seems like the English language isn't using the right levels of abstractions. There should be a true gender neutral pronoun, one that should be used when the gender specificity isn't relevant and should be hidden away behind the pronoun's abstraction. Its just not something we're familiar with, and that's really the only problem. Its hard to force language on people, when everyone learns language effortlessly as they grow up, nobody is used to putting effort in how they talk.

          • VarFarYonder 9 years ago

            > Its just not something we're familiar with, and that's really the only problem. Its hard to force language on people, when everyone learns language effortlessly as they grow up, nobody is used to putting effort in how they talk.

            I don't think that's the only problem here. Consider this story: http://www.foxnews.com/opinion/2016/08/03/student-facing-50-...

            These sorts of situations are a direct result of the battle "to force language on people", and they are having a big effect on our society. Sethi paid a high cost for a single tweet that wasn't intended to be malicious in any way. And people who read such stories note this, and as a result feel like they must tread on eggshells, because, even though they aren't racist or sexist or any other ist, one small slip up may result in their entire education or career being put at risk.

            A populous that is scared to say anything is much easier to control. And I think the powerful are going to get what they want with this. In a couple of decades, I think free speech will be a distant memory, and people like yourself will be questioning the future you helped bring about.

      • rascul 9 years ago
      • bobthechef 9 years ago

        This is just silly. Besides, grammatically, "he" is a gender neutral pronoun when referring to a person of unspecified gender (as in other languages). "They" is plural. "Ve" is not a word. "S/he" is awkward and unnecessary (and hey, we can argue that it is misandrous because you're capitalizing the "S" and prioritizing "She" over "he"; if you argue that it doesn't matter, then the same can be said about "he").

        • dragonwriter 9 years ago

          > Besides, grammatically, "he" is a gender neutral pronoun when referring to a person of unspecified gender (as in other languages).

          No, grammatically, "he" always has masculine gender [0]; its historically-accepted (though increasingly-less-so) semantics include use in reference to a person of unspecified (socially-ascribed) gender (classically, use of personal programs in English maps best to socially-ascribed gender, which has not taken gender identity much into account -- recently, there's been a move to align socially-ascribed gender with gender identity, but pronoun use basically follows the former which just happens to have a growing norm of also aligning with the latter.)

          > "They" is plural

          "They" is grammatically plural and gender-neutral, but has a very long history of accepted use with semantics of referring to an individual of unspecified (socially-ascribed) gender. This acceptance was somewhat reduced by the Victorian fad of Latin-inspired prescriptivism in English, but this reductions is among those of that fads effects that have been fading over recent decades.

          [0] Note that grammatic gender is a distinct concept from either socially ascribed gender of a person, gender identity of a person, or biological sex of a person.

        • the_other 9 years ago

          > This is just silly

          Given an HN reader took the trouble to email me their thanks for my comment, I respectfully disagree. To do this, they had find my email address by following some of my other comments, linking to a website, following through to github... The email they wrote was articulate. They put in real effort to say "thanks".

          > "he" is a gender neutral pronoun when referring to a person of unspecified gender (as in other languages).

          In some dictionaries, yes. A possible counter-argument to this is that the tradition of that usage comes from cultures with significant inbuilt misogyny.

          > "They" is plural.

          Sometimes. - https://en.oxforddictionaries.com/definition/they - http://www.merriam-webster.com/words-at-play/singular-nonbin...

          > "Ve" is not a word.

          I can read it, write it, say it and find other like usages in numerous places. To me, that reflects most of the necessary facets of "a word". - https://genderneutralpronoun.wordpress.com - http://vevemvir.tumblr.com - http://www.aleph.se/Trans/Cultural/Art/eganrev.html - http://www.dictionary.com/browse/etymology - http://www.wikihow.com/Create-a-Made-Up-Word

          > "S/he" is awkward and unnecessary

          Agreed. I dislike this form. A similar option is to alternate use of "he" and "she". This form is common, and probably the simplest. I wish I'd suggested it.

          > we can argue that it is misandrous because you're capitalizing the "S" and prioritizing "She" over "he"

          That was you, not me.

        • aninhumer 9 years ago

          > "They" is plural.

          Singular "they" is a widely recognised usage.

          And the idea that "he" is gender neutral always seemed to me like a post-rationalisation for people's androcentrism than any kind of well founded rule.

      • cjcenizal 9 years ago

        Thanks for making this suggestion! This is a good habit to fall into. It has no downside for you as a writer; only upside.

      • zild3d 9 years ago

        Singular they or s/he would be fine, but personally I've never heard of "ve", which I had to look up and doesn't even appear on the first page of google.

      • triplesec 9 years ago

        This is a really good point. We really do want to encourage women in this field, and it's a shame that dudes are downvoting this (and I'm male).

        • witty_username 9 years ago

          How do you know dudes (male people right?) are downvoting this?

          • grotsnot 9 years ago

            I'm a dude, he's a dude, she's a dude, we're all dudes

          • triplesec 9 years ago

            It's far less likely a woman or nonbinary would downvote this for I should think obvious reasons

          • tzakrajs 9 years ago

            Dude is unisex these days, and i think the original claim is also ignoring non-binary people who conform neither to male or female gender stereotypes (wrt wanting more women in tech). we should also want to increase visibility of non binary people

        • ManlyBread 9 years ago

          If such a small thing is enough to discourage women from entering the field, then by all means it should be done at this stage rather than after several years of college or in a workplace.

          • aninhumer 9 years ago

            "If just one straw can break a camel's back it must have been a weak camel."

      • gone35 9 years ago

        As a woman in (academic) CS, thank you. It is a small thing, but all those tiny slaps in the face do end up adding up at the end of the day...

      • alistproducer2 9 years ago

        I hate to pile on the downvote-fest here but I don't understand how some people have come to a place where they believe the world would be a better place if used the correct pronouns. Good intentions, I'm sure, and your comment wasn't rude, but seriously stop telling people how to live their lives.

        • the_other 9 years ago

          I fail to see how contributing to a downvote is "hating to pile on the downvote-fest".

          To defend my point a little: I invited them to consider their use of language, not tell them how to live their life.

          I can tell you how I came to this view: I read around through philosophy, pop-psychology/self-help, nlp, linguistics, religion and science-fiction; I spoke with feminists; I spoke with trans-folk and their admirers; I looked at my assumptions as a younger person and found them wrong.

          • blowski 9 years ago

            I agree with what you're saying, but I don't think this was the post to say it. It is possible to over-egg even the most valid arguments.

        • gugagore 9 years ago

          "Live their lives". Sounds like an exaggeration for something as inconsequential (as you suggest) as pronouns.

          • deong 9 years ago

            This topic does bring out a fair amount people who get very upset over something they themselves claim is not worth worrying about.

      • ManlyBread 9 years ago

        Am I being trolled?

  • wyldfire 9 years ago

    > Sometimes a gritty algorithm really does make the most sense if it's laid out as a 40 line function in one place rather than spread across 5 different classes so each part is independently swappable and testable.

    I agree with you, but it feels a little like a false dichotomy. You can pretty easily decompose a long function into multiple smaller ones, within the same file. ~40 lines is close to the breaking point IMO. If it grows much beyond that, you can probably see groups of 10+ lines of code that have some sane subset of inputs/outputs. Toss those lines in another function, give it a name, make sure it's not exported outside of this file. If the 40+ line function gets reduced to a 10-20 line one with a few more stack frames, it is probably worth it.

    • jblow 9 years ago

      What size of codebase are you talking about?

      If it's 100,000 lines of code, and you break stuff every 40 lines, you have now introduced 2500 procedures many of which don't really need to exist. But because they do exist, anyone who comes along now has to understand this complex but invisible webbing that ties the procedures together -- who calls who, when and under what conditions does this procedure make sense, etc.

      It introduces a HUGE amount of extra complexity into the job of understanding the program.

      (Also you'll find the program takes much longer to compile, link, etc, harming workflow).

      I regularly have procedures that are many hundreds of lines, sometimes thousands of lines (The Witness has a procedure in it that is about 8000 lines). And I get really a lot done, relatively speaking. So I would encourage folks out there to question this 40-line idea.

      See also what John Carmack has to say about this:

      http://number-none.com/blow/blog/programming/2014/09/26/carm...

      • bdavisx 9 years ago

        I realize you're in the gaming world, and that might be much different; but in the business application world (and I don't mean simple CRUD applications) anytime I've seen code like you describe, 1,000+ lines in a single class, let alone a single method, it's a complete mess.

        • jblow 9 years ago

          When you factor it into a bunch of 40-line things, is it really less of a mess, or is it just that you can't see the mess any more -- maybe it looks clean, but if you pick up the rug, the room is filled with dust?

          I think also what you're talking about is a function of programmer skill. I think if you have a good programmer write a 1000-line procedure, and a bad programmer write a 1000-line procedure, you are going to get drastically different things ... just like with anything.

        • lj3 9 years ago

          If you were to take a poorly written 1000+ line function and split it up into 25 functions, you still have a complete mess AND you don't know where to find anything. If you look closer at those 1000+ line functions that are a dumpster fire you'll see the issue is probably more to do with tight coupling and/or hidden state changes to "global" variables than it is the length of the function itself.

          A good example of a 1000+ line function I've written for business applications was for processing JSON for the initial state of a web app. You have a lot of data coming in, you need to do a lot of verification and transcribing backend data structures to frontend data structures. It's easier to do it all in one place than it is to break it into many little functions that only get called once anyway.

          • chimprich 9 years ago

            However, if you have a 1000+ line function that you split into small functions you can pretty easily write a few unit tests per function to see which, if any, of those chunks have problems and then need to be fixed. It's pretty much impossible to write unit tests that can sensibly test a non-trivial 1000+ line function. You might get away with it if it's doing something very straightforward but I wouldn't be very confident in it.

            • jblow 9 years ago

              This is fine if you believe that unit testing every 40-line chunk of code is remotely worth the time and effort. I don't think that is true for most applications.

              How long does it take you to write and test all those tests? Could you have been doing other things with that time? At 40 lines of functionality, the tests are going to be at least as big as the things you are testing (??), so what kind of a multiplier are you taking just on lines of code written? How much does that cost?

              [I run a software company where I pay for the entire burn rate out of my own pocket. So these questions are less academic for me than they are for many people.]

              • chimprich 9 years ago

                It's true that there's a non-zero cost for each test, but overall I think tests speed up development rather than slow it down (unless you go crazy with the tests, and providing you're fairly decent at writing tests). I don't believe it's worth testing all paths through the code, but I'd aim for significantly over 50% coverage to have any degree of confidence in the codebase.

                I estimate I write about 2:1 unit tests to code in terms of tests to functions but tests should be quite a bit faster to write than the code they're testing. I think I'm at the low end of how much I test my code compared to other engineers, however.

                Perhaps it is different in game development. One of the big advantage of writing tests is that you can aggressively refactor with confidence; if you're planning to stop improving your codebase once the game is released maybe this isn't an issue? Plus bugs are perhaps less of an issue if you inconvenience the gamer rather than lose someone cash, and maybe you aren't expecting to hand code over to new developers.

                • jblow 9 years ago

                  It sounds like you use web languages or other bad programming languages? Aggressive refactoring is not a problem in statically typechecked languages, in fact it is common.

                  We test the hell out of our stuff, and it works way more reliably than most web sites I have ever seen. But we don't do it with unit tests, because unit tests are not very useful in complex systems, because they do not test anything hard!

                  • RotsiserMho 9 years ago

                    That's quite the blanket statement. Refactoring is just as much of a problem in statically typechecked languages. I write unit tests for a large C++ codebase and find them incredibly valuable when refactoring. Typically each class has a responsibility. The unit tests verify they are carrying out that responsibility correctly. Acceptance tests validate behavior across multiple units (the hard stuff). I fail to see how unit testing in languages like C++ wastes time. We spend far less time finding and fixing bugs than when we didn't have them.

                  • chimprich 9 years ago

                    I've used a lot of languages, both statically and dynamically typed, and found unit testing to be very useful in both.

                    The idea that unit tests are not very useful in complex systems is very controversial and goes against established best practice in software engineering, the advice of pretty much every authority in the field and empirical studies.

                    Only testing hard stuff is only half the battle. Unit tests also test basic assumptions and have other benefits like documenting intent. See /Code Complete/ for evidence for the need for multiple angles of testing.

          • Jtsummers 9 years ago

            So you have a massive switch/case like:

              switch(JSON.someparam) {
                case A: //code to translate A_server -> A_client
                case B: //code to translate B_server -> B_client
                ...
              }
            
            Check all your cases have breaks? That you didn't accidentally introduce a new variable into your scope or clobber a variable already in scope?
        • kayamon 9 years ago

          It's usually the same in the gaming world too.

      • chimprich 9 years ago

        Carmack in that link isn't exactly giving unqualified support to your position. The first sentence links to where he's now a big fan of functional programming and supports programming using combinations of pure functions.

        • jblow 9 years ago

          Obviously, he's a different person and has a different opinion.

          My experience has been that people on HN tend to interpret that part of the posting a little more extrapolatingly than I do. I think he is saying something pretty obvious, which is that when you can structure things in terms of pure functions, you don't have to worry about the side-effects that are one of the main issues you need to contend with when factoring things apart.

          This is different from being a "fan of functional programming", i.e. believing you should use current functional programming languages to build your projects, or whatever.

      • pvg 9 years ago

        I'm curious about the 8000 line procedure and what made it the best approach in your case. Also, how do you navigate inside it?

        • jblow 9 years ago

          It's the procedure that constructs most of the puzzle panels in the game.

          Usually I just search for the name of the puzzle I want to edit (which is also how you'd do it if it were a ton of different procedures).

          • pvg 9 years ago

            Hah, that's cheating! I'm not trying to defend an 'N-lines' rule which seems too obviously silly to even argue about but people do often break out chunks of code into procedures to give them logical, navigable names. You have names inside your big procedure.

      • RotsiserMho 9 years ago

        I don't think it's a given that breaking it down introduces complexity. I've found that creating a sub-function for the sole purpose of just giving it a name does wonders for making it easier to understand the code. Names describe intent and are easier to remember than lines of code by themselves.

    • halostatue 9 years ago

      That mostly depends on where the algorithm is used. If it’s in a tight loop, those extra stack frames are deadly and completely not worth it.

    • peterloveslucy 9 years ago

      40 lines is excessive, I prefer simple methods that take care of the if's and link them together serially. AFAICS this is the way the brain works.

        /**
         * get the leaf node as a string
         * @param obj the json object to operate on
         * @param path the dot path to use
         * @return the leaf node if present <b>and textual</b>, otherwise null
         */
        public static String leafString(ObjectNode obj, String path) {
          JsonNode leaf = leaf(obj, path);
          return leaf != null && leaf.isTextual()
              ? leaf.asText()
              : null;
        }
  • makapuf 9 years ago

    I agree about the dangers of over abstraction but you're implying it derives from the principles, however the lines

      The KISS principle states that most systems work best if they are kept simple rather than made complex
      Therefore, simplicity should be a key goal in design, and 
      unnecessary complexity should be avoided. YAGNI is a 
      practice encouraging to purely focus on the simplest 
      things that make your software work.
    
    made me think that it clearly warns against overengineering.

    (edit:formatting)

    • catnaroek 9 years ago

      Sounds good, but what concrete, objective measure of simplicity do you use? And how do you justify your choice?

      • ThrustVectoring 9 years ago

        I've got an extensional definition but not an intensional one. That is, I can look at two programs that do the same thing and tell you which one is simple, but I'm not sure what all goes into it at what weight.

        One thing is code execution paths for later debugging. All else equal, code is simpler if everything you need to figure out what something does is in one place. Basically, minimizing the distance you need to travel in order to get related information. Keep variables closer to where you use them, etc.

        There's some programming language specific stuff. A for loop that does a mapping is more complicated than calling a map on the collection. More generally, a program is simpler if it uses more specific abstractions, rather than using a very general abstraction in a highly specified way.

        Likely, there's more than I'm completely forgetting but will recognize as general principles that I use.

      • arethuza 9 years ago

        Excellent point - I've had disagreements with people who thought their code was beautifully simple while I thought it was an over-engineered mess.

        Who was right?

        [NB Obviously, I was right, but it would help if there was some objective measure of complexity to justify it ;-)]

      • nickpsecurity 9 years ago

        Let's take a page from the Orange Book days. Simplicity means you can:

        1. Clearly map the code/functions to the specs of what it does almost line by line.

        2. The code is expressed in a way simple enough for one person to understand it and verify it by hand.

        3. The code is expressed in a way simple enough for a machine to verify it should someone want to try.

        4. Minimal to no global effects/state happening in the local code.

        These principles tend to result in code that's correct and easy to modify. I say they're a start on some objective measure of simplicity. We could empirically [dis]prove them as well with tests of various coding styles on people and tooling.

    • marcosdumay 9 years ago

      I've seen complex atrocities created by blindly following KISS and YAGNI. It just takes a non-obvious path, and a few months of code and requirements evolution.

      • Mtinie 9 years ago

        I'll counter that comment with the following:

        Blindly following anything -- especially nuanced, process-driven ideological frameworks -- is a recipe for a disaster.

        KISS and YAGNI are examples of processes that require the person who is using them to actually think through the implications within the context of the problem being solved.

        KISS and YAGNI did not cause the atrocities that you've seen. Those complex beasts of code existed because the team fundamentally didn't understand what they were doing.

        It's like "agile" software development. Just declaring that you're following an agile methodology and scheduling stand-ups does not mean that you're going to be successful. It takes someone (and usually, many someones) who understand how to iteratively design and develop to be successful.

        > It just takes a non-obvious path, and a few months of code and requirements evolution.

        Can you expand on this comment? I'm interested in understanding what you mean by "non-obvious path".

        • marcosdumay 9 years ago

          > Blindly following anything -- especially nuanced, process-driven ideological frameworks -- is a recipe for a disaster.

          Yep. That's the point, that's why I pointed it was blind.

          Many people blindly follow and impose that kind of ideology. Most people that even mention YAGNI outside of a classroom are blind followers (for DRY things are more diverse).

          By non-obvious path I mean things (requirement, underlining systems, user base size) changing in a way that was not unquestionably and blatantly obvious.

          • Mtinie 9 years ago

            > By non-obvious path I mean things (requirement, underlining systems, user base size) changing in a way that was not unquestionably and blatantly obvious.

            I can't agree with you more. Thank you for the follow-up.

      • philipov 9 years ago

        If "Keep It Simple Stupid" causes one to make something complex, they have failed to keep it simple, and can't blame the principle for their failure to adhere to it.

        • qznc 9 years ago

          Marcosdumay did not state that "complexity" was the problem, but "requirements evolution".

          Following KISS and YAGNI means you hard code lots of assumptions. When the requirements change, it means you have to fix all those subtle hard-coded assumptions everywhere and that is usually hard.

          • ThrustVectoring 9 years ago

            Also, if a single concept pops up as something that's needed once every month for six months, it's way easier to have that get re-implemented six times rather than abstracted.

  • shados 9 years ago

    yeah, DRY and "less code is better" are to concepts that should be very loose guidelines and nothing more.

    "The wrong abstraction is worse than no abstraction" comes to mind here. Very simple, repeated code that is unlikely to change (or unlikely to change everywhere at once because things are unrelated and just happen to do the same thing... -for now-) is much easier to read and maintain than short, clever, DRYed up code.

    • leetrout 9 years ago

      I agree with this 100%. Nothing wrecks my mental model of code like poor abstractions and even bad naming choices, too.

      I'm big on linting code though... For me the more everyone's code looks the same the easier it is to read without doing mental gymnastics.

  • k2xl 9 years ago

    Couldn't agree more.

    One of the reasons I enjoyed learning and writing Go was that it sort of encouraged keeping things "tight"

    Often times programmers look at lines of code or number of classes written as a source of pride, when we really should be looking at these things as expenditures.

    • blakecaldwell 9 years ago

      Agree. I like Go for the same reason. With Java, there's a weird pressure to spend a week designing class hierarchies and to set up all the factories and abstract factories. In Go - uh, you can do it, but you're going against the grain.

      • vonmoltke 9 years ago

        I have been writing Java for 4.5 years and have never felt such pressure. In fact, I have never written a factory and use inheritance sparingly. The problem of Java is the culture of the enterprise bros who worship at the altar of the Holy OOP, not the language itself.

      • fh973 9 years ago

        Aren't class hierarchies just 90s OOP code and not specific to Java.

        • ptero 9 years ago

          Probably. But Java, growing up as a language at this time, was IMO influenced by this fad more than other (older or newer) languages.

        • arethuza 9 years ago

          I don't think they are specific to Java technically but they do seem to be part of Java culture.

    • collyw 9 years ago

      I agree, I take more price these days in removing lines of code while keeping the same functionality. Less to maintain. Less places for bugs to hide. Again its a principle and there are exceptions, but provided you realize that its a good one to follow.

  • crdoconnor 9 years ago

    >All the horrid Java libraries that we hated working with 10 years ago were created because of slavish devotion to the single responsibility principle, short methods, DRY, and testability. The absolute worst codebases I've ever seen sprung from an overaggressive concern for extensibility.

    Slavish adherence to these principles (with the exception of DRY) violates one of my core principles: write the least code possible to solve a problem.

    The single responsibility principle in particular isn't what I'd consider a fundamental principle of good code since it often can lead to writing an awful lot of unnecessary boilerplate. Short methods are similar (if a method is called only once I often consider that a code smell).

    I think the culture of Java is also partly responsible for this: grand architectural designs are valued over terseness and simplicity. A system with stack traces as high as your arm are seen as something to be proud of.

    • riboflava 9 years ago

      I go back and forth on the singly-called function as a code smell. It really depends. What annoys me are the private method refactors that then can't be unit tested unless the 'private' keyword is removed.

      For an instance of how it depends, see the classic Forth example for implementing a washing machine driver:

              ...
          	: RINSE  FAUCETS OPEN  TILL-FULL  FAUCETS CLOSE ;
              ...
          	: WASHER  WASH SPIN RINSE SPIN ;
      
      Then a single call to WASHER is all that happens when the user presses the start button.

      Function calls should make things clearer, not less clear because of some other principle (like DRY or single responsibility or testability etc.). That's ultimately where I think the JavaLand culture has gone wrong, all these abstractions (many of them caused by being forced to live in a Kingdom of Nouns) that are sometimes quite useful in the large are always a pain in the small, but many times the small is all that is needed. Big projects are slowly learning they don't need to be so big, they can instead be a set of independent smaller projects, but it'll take more time.

    • chimprich 9 years ago

      >if a method is called only once I often consider that a code smell

      Well I certainly disagree; it often makes sense to separate out a singly-called function if for no other reason than to be able to unit test that functionality individually.

  • lamontcg 9 years ago

    Lately I've been ripping out crappy abstractions that were all about creating DRY code but instead made the code incredibly hard to follow. Even though the resultant code has a bit of duplication, its much easier to read, reason about, test and maintain. The redundant parts are typically in areas that are unlikely to change. I might try to come up with a really clean abstraction later in order to re-DRY the code, but lately my experience is that a shitty abstraction created entirely for the purpose of DRY'ing code is vastly worse than just allowing a bit of code duplication. DRY only for the sake of DRY is terrible.

  • phn 9 years ago

    I think the problem is guidelines and principles are just that, guides. You cannot turn off your critical thinking just because you read somewhere that you should do things a certain way.

    The problem, of course, is that your critical thinking needs experience before you truly become capable of deciding if a particular principle should be followed or broken in a particular case.

    In short, I think guidelines help, but you have to walk the path to know the path.

  • amai 9 years ago

    This explains most of these horrible Java libraries: http://product.hubspot.com/blog/bid/7271/premature-flexibili...

  • ap22213 9 years ago

    Which libraries are you talking about? It would be fun to check them out.

    Anyway, it's all about UX. Certain types of programmers will want a certain types of interfaces. A well designed library will have been crafted to meet those programmers specific use cases.

  • chimprich 9 years ago

    A lot of those problems are quite dependent on your choice of language. Java, and similar languages, implicitly bias programmers in favour of building multi-layered abstracted monstrosities. Inheritance and interfaces can be powerful weapons for evil. Lots of the original Java libraries pushed people in the wrong direction.

    I'd agree that finding the right level of abstraction is hard, easy to misjudge even for an experienced programmer with YAGNI in mind, and that you can do more damage by over-abstracting than not abstracting. Most programmers experience this the hard way sooner or later.

    I'd disagree that having objects/functions do more than one thing or not be able to be pulled apart into individually testable units can be a good thing - except in very rare cases, or to compromise with existing legacy code.

    Would you mind giving an example of where an object should do more than one thing?

  • ArkyBeagle 9 years ago

    It really sounds like you're proposing(?) or objecting to the lack of (?) code locality - feature X is all in one or two or three nicely isolated places.

    Over-concern for extensibility is just a really big problem.

  • blakecaldwell 9 years ago

    Nailed it.

gravypod 9 years ago

I've often wanted to talk to people about things like these and I'm often pushed back by people saying "This is simple, we all know this" but I don' think that's the case. If anything I think we know very little about how to keep software clean and simple. I've been trying to change that in my works by having people comment on my code that I've recently written for homework but people aren't really up for the idea.

I've had one discussion that stood out. We were talking about functional programming and I said that the idea of functional programming was the segregate state to the smallest unit of computation that must operate on it. I was met with my "friend" just blindly telling me to "stop saying that". I asked for a counter argument to that statement but they just said that I should stop saying that.

We as a community are horrible at speaking about code quality , evaluating each others work, and even just sifting out opinions from facts. It's crazy and it's something that needs to change if we want to take our field to a future where we can all be happy with the code we are writing.

I've got some suggestions I'm happy to talk to others about. My email is in my about page on this website. Please comment here or email me and I'd like to talk about this!

  • hyperdeficit 9 years ago

    This is a real problem in our industry. We all like to think that we 'know' how to write good code, after all we read 'Clean Code' once. That, combined with either overconfidence in our abilities or the negative perception that comes with not knowing the answer to every problem leads to a lot of software that has applied 'good' coding practices and architecture to produce a mess of awful code.

    In reality it is probably a lot more like learning how to apply any other concept, it takes practice, yet we don't spend enough time practicing our craft. This is particularly a problem because in the course of developing a product you will only get to implement a new solution to a problem a few times at best, or once more likely. This means we don't get enough experience with the different possible approaches to really internalize what a 'good' solution looks like.

    We spend much more time learning the software development approach du jour, XP, Scrum, Kanban, Lean, etc. It doesn't matter what software development approach you use if the output is an unmaintainable mess of code.

    • gravypod 9 years ago

      Honestly the best way to go about this, in my mind, is to make criticism ok in our industry. I've been trying my hardest to get someone I know to comment on my implementation of a CS280 homework I've been working on. I want to get to the point where I can properly write this code so it is readable to everyone. It seems like every time I ask someone to do this I'm told "Why would you want me to tell you how to code"

      That's insane! I think that a goal of any programming course around the world should instill the idea that getting your peers to modify and read your code is a must in our industry. People need to be able to com along, see what you've done, and understand it.

      If anyone want's to comment on my code that I'm talking about in this example it can be found here:

      Implementation: https://git.gravypod.com/gravypod/school/tree/master/cs280/h...

      Assignment: https://web.njit.edu/~gwryan/CS280/CS280-Program-1-Fall-2016...

      I've attempted to live up to what I think is "good code" but no one want's to tell me if I'm right or wrong or even discuss this for fear of hurting my feelings I presume. I always get "run valgrind or a linter on it" and I've done that and come up with no ways for improvement. Everything is all opinion and no fact in this business of code cleanliness although this should be a cornerstone topic for the software development industry.

      • l0b0 9 years ago

        Have you tried codereview.stackexchange.com? I find it can be a nice way to learn what others prefer and get tips for improving clarity especially in languages that I'm new to.

      • ThrustVectoring 9 years ago

        That's a hard thing to get. A lot of people will play shitty status games and make feedback to try to prove they're more clever than you. And since people do that, genuine feedback can often get interpreted that way.

        • chiefalchemist 9 years ago

          That's a good point. There's bad code. And then there's that's not how I would do it code. Too often, in public the latter gets treated like the former. When you're still open to learning this is confusing. That is, do I suck? Or is that feedback coming from an asshole?

    • collyw 9 years ago

      The thing that taught me the most was writing an application and having to maintain it for 4 years. You see where the pain points are (as you end up revisiting them often), and you have no one to blame but yourself. You learn from your own mistakes.

      I also learn from other mistakes as well. I has a habit of inlining conditionals in python -

         if False : continue 
      
      until I noticed that the same style made reading someone elses code harder. I didn't notice it in my own code as I was more familiar with it. When I did notice I stopped doing that.

      Keeping the logic as close to the data as possible helps as well (ideally in the data schema if possible). I think Linus's quote about bad programmers worry about the code, good programmers worry about the data and their relationships is true for most of not all levels of the stack.

  • pikzel 9 years ago

    It's -presented- in a very simple way. The list doesn't give any real insight or even a single code example. That's why they say it's too simple, and you say we know very little about it, and you're both right.

    • gravypod 9 years ago

      The problem is we don't have much in the ways of examples.

      I'd say one of the few people in the world who has given grade-a examples is Rob Pike. That said I don't agree with him on much but I do very much respect his talent for simplicity. I'm directly referring to his Regex parser. It's amazing work although I'd much rather see him implement it live from scratch.

      Something like the SICP lectures on youtube. It's amazing what they go over and do in that class and how they teach you about abstracting your problem domain.

  • witty_username 9 years ago

    My email is maniandram01@gmail.com

    You can discuss it with me.

taneq 9 years ago

Something that lists like this always seem to miss is locality of reference. You shouldn't have to jump around all over a file (much less through several files) to follow the code that does a single thing.

The single responsibility principle should really be "exactly one" rather than "not more than one". If a function is responsible for less than a whole thing, it shouldn't be a function on its own.

  • morbidhawk 9 years ago

    > locality of reference. You shouldn't have to jump around all over a file (much less through several files) to follow the code that does a single thing

    This is something I was learning when I was working in Swift, in a WWDC video they called it local reasoning; being able to reason about the code in one particular function without having to worry about state changes elsewhere. Now working in C# it seems to be a common thing to pass an object by reference to a bunch of different functions to fill in it's values and map properties. If you do too much of that it can become a maintenance and debugging nightmare when a property didn't map up the way you wanted it to.

    I also agree with what was said in a different comment about not breaking functions up too much if it's not necessary and that would help eliminate this need to modify state in so many places.

keithb- 9 years ago

>> Can be easily extended by any other developer

This is a tenet that will lead inexperienced developers astray. This "rule" is just too ambiguous. Extensibility is a fascination for object-oriented programmers but in my experience doesn't have a lot of successful examples. Typically I have seen this manifest itself in either a Command+Composite style where every meaningful class is a composite of other SRP classes, or in a proliferation of interfaces that seldom have method definitions and are instead used to enforce coding standards or dependencies.

KISS is incompatible with this rule and you should kill this rule with fire because simple is not extensible. Perhaps when the goal is extensibility then should you consider other developers, but if you are developing a "beige" application then you should not consider extensibility. Instead, just assume that release management will handle changes, i.e. another developer will update rather than extend your class and that will be released in version 1.1.

Of course, to do this also means admitting that version 1.0 of your class was pretty much garbage and that it needed to be "extended". Tough pill to swallow for some.

  • js8 9 years ago

    I somewhat disagree. Interestingly, one of the most extensible SW systems ever is Unix shell, which is completely opposite to the OOP idea.

    The idea in Unix is that data are the interface, in case of Unix the data are unstructured text, but I think it can be generalized to systems with structured data. So contrary to OOP, most extensible systems seem to be the ones that (self)document their data structures as interface and leave it at that.

    • hxegon 9 years ago

      Clojure agrees with this philosophy IMO. Paraphrasing, but "100 functions on 1 data structure is better than 10 functions on 10 structures"

      • js8 9 years ago

        True. I think in general it's a philosophy of functional programming, where data structures are types, and type signature of functions are their APIs.

mosselman 9 years ago

While some of these points have something to do with 'clean' code or maintainable code or whatever, this copy-pasted list of very very shallow statements about code isn't really useful. I expected there would at least be a few examples on how to implement these principles, perhaps in a 'before and after'.

Maybe there should be a 'click-bait' button on HN with which we can report things as such, along with posts such as 'Why I won't be using popular-technology-x ever again' and '10 things I hate about SQL'

  • Can_Not 9 years ago

    I was definitely looking for something more insightful and/or deeper to share with my colleagues. Any recommendations would be appreciated.

pyrale 9 years ago

> 3. It should not be redundant

Not sure I agree with this one. While abstractions are a great way to reduce the length of code, sometimes they break readability. When you read code, sometimes, you feel like you don't read a solution to your problem, but a way to solve your problem masked behind abstractions far removed from the domain concepts.

That's why, sometimes, redundancy is better than the wrong abstraction.

  • taneq 9 years ago

    I've seen some very good arguments about 'redundancy' that's actually the same lines of code performing a different function in different places. In this case, naive de-duplication just adds unnecessary interdependencies between otherwise unrelated parts of the codebase.

z5h 9 years ago

I believe an important quality is that code should TELL A STORY.

Consider a biography: you could simply collect facts about a person and write them in an arbitrary order and call it a biography. It could be a complete and accurate account, and still be impossible to read or follow.

Well written code is not only complete, but it also guides the reader through the logic.

Consider the difference between:

  statuses = []
  reporter = Reporter.new
  jobs.each do |job|
    statuses << job.complete && !job.error
  end
and

  job_statuses = jobs.map do |job|
    job.complete && !job.error
  end
  job_status_reporter = Reporter.new
In the first case, we see statuses declared. Statuses of what? Not yet clear. And the code that updates it is separated by unrelated code. Also, what will reporter be reporting? In the second case, map and better naming are used making it clear that we are getting a status for every job. Aha! I don't even need to look at the implementation of the do block to understand what's happening.
  • bruxis 9 years ago

    Personally, I would rather see the first version with better variable names.

    I always find that map() methods tend to obscure the purpose of the values whereas a simple appears more explicit.

    • z5h 9 years ago

      "map", "select", "reduce", "flat_map" and the like make your intention visible upfront. "each" just tells me you're doing "something" with each item.

      Not sure how giving less information is preferred over being explicit, but hey, whatever works for you.

k2xl 9 years ago

Clean code isn't always the most efficient code, but I think that's fine. Many times in my career I've found that you don't always need the most optimal, efficient, and performant solution to get the job done, and that sometimes you need to sacrifice those attributes for clear, readable, understandable code. Good architecture usually supercedes speed of individual algorithms. Hence why you see almost every major language under the sun has been used at scale.

I remember when looking into neural nets, the basic python code to get one running was super easy for me to understand. However, I also realize that the optimal, most efficient methods of neural network libraries are way more complicated (and for good reason).

baron816 9 years ago

Most of all, clean code should be easy to reason about.

  • todd8 9 years ago

    > Most of all, clean code should be easy to reason about.

    This one sentence should be guiding principle for any set of recommendations. Programmers should tape it to the top of their monitor. Programs difficult to reason about are hard to get working and hard to debug and hard to maintain.

    In my opinion, this is the key requirement of "good" or clean code. Likewise, programming languages that facilitate this are "better" programming languages.

    Depending upon the goals of a program there can be other important requirements (for example, efficiency), but however the program is constructed it should be as easy to reason about as possible given the constraints imposed by these other requirements.

    Recognizing this, I tend to pick programming languages that make my programs easier to reason about and tend to program in a style that makes informal reasoning easier. For kernel development, programming in C was appropriate (back when I was doing it) because I needed to know exactly what was going on in the machine in response to the code. At the other end of the scale, straightforward Python code often results in such short programs that they fit entirely on one screen and are consequently easy to understand and reason about.

    This style of programming has led me to be very impatient with the "keep debugging" until you think it works style of development. I tend to think that each bug found is evidence of the presence of more bugs.

    • rimantas 9 years ago

          >> Programs difficult to reason about are hard to get
          >> working and hard to debug and hard to maintain.
      
      Actually reasoning and maintaining often are at the opossing ends. The code which is easy to reason about tends to be low on abstractions and tightly coupled, so changes become much more difficult. More modular code is harder to reason about but the changes can be introduced easily.
      • todd8 9 years ago

        I believe that I agree with you. Good modularity and good abstractions allow easier reasoning about the program. I like the word reasoning because it covers thinking in a Dijkstra like way about tight pieces of code and Liskov like ways about larger systems.

    • moreoutput 9 years ago

      "This style of programming has led me to be very impatient with the "keep debugging" until you think it works style of development. I tend to think that each bug found is evidence of the presence of more bugs."

      Well said (currently programming by dead reckoning).

    • asciihacker 9 years ago

      >> This one sentence should be guiding principle for any set of recommendations.

      Therefore write everything in Prolog.

      • todd8 9 years ago

        I was excited about prolog when it first gained popularity in the 1970s for exactly this reason. Then I discovered that real programming in prolog hides some of the reasoning necessary for programming (like the time needed for a computation to finish) behind abstractions of the language. (I.e. The cut operator ruined for me)

  • moreoutput 9 years ago

    This is my first requirement in deciding if a program itself is well written. One of the best ways to achieve this, if your design isn't evident, is solid documentation that covers not only API issues but reasoning for context and perhaps a little history.

kasey_junk 9 years ago

Extensibility is important in some cases and a detriment in others. Most of the rules about extensibility came from environments where the code was running in many places at the same time (ie delivered to customers).

In a SaaS environment the code needn't be extensible as there is only 1 copy of it. It is much more important for the code to be changeable, rather than extensible and in many cases the things you do to make code extensible make it harder to alter fundamentally.

Its important to understand that how you deliver your software is one of the biggest guiding factors in how you design your software and take that into account.

pif 9 years ago

If written by someone else, clean code is: all and only the code that I personally won't have to maintain :-)

swalsh 9 years ago

Something I've noticed, in bad code if you need to learn something, or change something... Simply "searching" the code isn't enough. Maybe there are multiple places that do a similar thing, maybe the names are weird, maybe it's so condensed as to be unreadable. Whatever the cause... The only way to find the piece doing the thing is to step though it.

Good code, you can search it... even if the majority of it is unfamiliar. Find a piece, and say "oh this is probably the spot" with out ever executing it.

pif 9 years ago

I recommend "What Could Possibly Be Worse Than Failure?" by Alex Papadimoulis (http://thedailywtf.com/articles/What_Could_Possibly_Be_Worse...).

An excerpt: We are practically the only industry where completion and success are synonymous. If the foundation of a one-year-old home is crumbling and its roof is plagued with leaks, would anybody actually call that a success? Despite being filmed and produced on budget, is there anyone who would not be ashamed to have Gigli on their filmography? Of course not! So why are the products we create – complex information systems that should last at least fifteen years – be held to a different standard?

Now think back those projects of yours. How many would you say are maintainable by someone with less business knowledge and a weaker grasp of the system’s design? How many will not snowball into an unmaintainable mess? How many do you truly believe could last fifteen years? I’ll bet that number is quite a bit lower than all of them.

  • _pmf_ 9 years ago

    > How many would you say are maintainable by someone with less business knowledge and a weaker grasp of the system’s design? How many will not snowball into an unmaintainable mess? How many do you truly believe could last fifteen years? I’ll bet that number is quite a bit lower than all of them.

    Coincidentally, the number of projects where the client offers to pay for tens of man years is also quite low. This is something I'd recommend to be taken into consideration by armchair philosophers portraying the state of the software industry.

    • pif 9 years ago

      I've seen this worshipping of "ship soon" many times. It always ended with a buggy and messy software, an unhappy customer and a stressed development team.

      • nickpsecurity 9 years ago

        It also turns people into millionaires and billionaires. It's how the top hardware and software companies got their market share. So, one should always assess on given project or company the First Mover & time-to-market for feature sets advantages vs quality or user perception.

        • pif 9 years ago

          Well, the article was about "clean code", not about "most efficient for business" code :-)

erlich 9 years ago

Being able to simulate amnesia is my goal.

I write code that I come back to and don't understand, and realise its terribly complex because I understood everything at the time, but could not imagine what it would be like coming back after a month to make a change, or for someone new to try to understand it.

Code is for people to understand.

Some people think its for being able to write good tests, eliminating all side-effects and shared state, for the computer to be able to run quickly and optimise, to be easy to read.

But its really just about being able to be understood. Most time will be spent in maintenance.

When you modify and debug, you are diving into the middle. You are not walking through the code base from the beginning and reading all the comments.

It needs to be understandable from all locations.

I'm a strong believer in micro-modules. Left pad et. al. I try to create small modules which do one thing well that I can trust and not have to think about.

drakonka 9 years ago

If I'm remembering correctly this article seems to mostly paraphrase what the various developers Robert C. Martin interviewed for this book ("Clean Code: A Handbook of Agile Software Craftsmanship") said...in mostly the same order.

abhas9 9 years ago

Someone very experienced once told me: "For one change in requirement there should me one change in your code. That's a clean code. If you can achieve it without any change in code, it's even better."

This quote always sticks in my mind :)

antoaravinth 9 years ago

>> 5. Can be easily extended by any other developer

I can remember a instance, when I started my carrier. I was a JS developer. I wrote a module with Functors, Compose, Partial etc.

In code review my team told they didn't understand anything and reading such a code is not pleasant for them. I was upset, I was thinking why my team is not happy with it.

Today I can make lot of sense; stick to the pattern/design of your team. If your team follows / loves functional programming in your project, stick to it. If not try to advice them why functional programming would be better than normal approach.

End of the day, all it matters is writing simple, elegant code which others can understand.

textmode 9 years ago

With the exception of shell scripting which I'm writing every day, I remove "code" more than I write it. C is the language I deal with.

The easier it is to remove code from someone else's program, the "cleaner" the code.

That's my definition of "clean code".

For example, I just had to edit the code for a text-only browser to remove a few "features". For example, the author recently decided it would be a good idea to non-interactively access no-content refs in a page such as "prefetch" and other garbage.

  • mmarx 9 years ago

    > The easier it is to remove code from someone else's program, the "cleaner" the code.

    But then, contrary to intuition, a program becomes less clean by actually removing code (since now there is less code to remove, hence it is more difficult to remove code). A minimal (in the sense that no more code can be removed) program would be maximally unclean, whereas, intuitively, should it not be considered clean?

    Also, adding code always makes a program cleaner, since the newly added code can always be removed easily.

    • textmode 9 years ago

      "... in the sense that mo more code can be removed"

      Or else what happens?

      "... should it not be considered clean?"

      It should be considered finished.

      "... since the newly added code can always be removed easily."

      Not true in my experience. Unfortunately.

      Sometimes it's necessary to add some code, e.g., a new driver for a new item of hardware. I have nothing against adding, per se.

      • mmarx 9 years ago

        > Or else what happens?

        In the extreme case (the empty program), there is no more code left to remove. It suffices that any proper subset of the code is insufficient to provide the needed functionality, though.

        > It should be considered finished.

        And yet you obtain a cleaner version of the finished program by adding superfluous code to it. In fact, every unfinished version (a version where you can still remove code) of the program is cleaner than a finished version (where there is no code left to remove) of it.

        > Not true in my experience. Unfortunately.

        Removing the code is reverting back to the previous version. How is that not easy to do?

        > Sometimes it's necessary to add some code, e.g., a new driver for a new item of hardware. I have nothing against adding, per se.

        But that changes the requirements, and thus changes which code can be removed.

        However, the point was that you could obtain an arbitrarily clean version of a program by adding redundant code to it—since it's easy to remove that code, it is cleaner than the irredundant version of the program.

        • textmode 9 years ago

          "How is that not easy to do?"

          1. The author does not provide access to his/her source code repository, only compressed tarballs.

          2. The author's code is not clean.

          You appear to have some issue with my "definition" of clean code. I do not follow your points but maybe I can state it another way: Code that is easy to edit is clean code. If that definition is still giving you trouble, you think it's unreasonable, etc., let me know.

k__ 9 years ago

The thing I learned from working with absolute beginners to mediocre developers is: good modularization/isolation is the key to success.

Yes, most things in the article are nice to have, but you can't teach everything in a month and people need to be prodcutive to be worth their money.

partycoder 9 years ago

A piece of code should not know a lot about the system and should work under a restricted set of assumptions and preconditions.

When this rule is not respected:

1) You end up with lot of coupling

2) Unit tests end up with a lot of overhead

caub 9 years ago

in the background image, the code would be better with arrow functions, or object shorthand methods

  • kevindqc 9 years ago

    I don't think it's an example of clean code (all the arguments are a and b for example).

    Also the article is from 2013, did these exist then?

JustSomeNobody 9 years ago

A "Top X" post on HN. And can there really be anything new said about qualities of clean code now that hasn't already been said many ... many times before? Given that it is a "Top X" post, I don't feel confident there will be.

I'm passing on this article.

  • noxToken 9 years ago

    Mods, can you change the title of the article to Stuff About Clean Code We Already Know? This way, we can let the new users and new programmers know that everyone in the world has already seen this content? Thanks!

    Just because you know it doesn't mean everyone else does.

    • JustSomeNobody 9 years ago

      There a thousands(!) of articles on clean code. And at least one _really_ good book on it. I would bet dollars to doughnuts that this articles has NOTHING more to add on the subject based solely on the title.

      • noxToken 9 years ago

        I know that. You that. I'm sure 99% of the commenters of the article[citation needed] know that. But there are people who haven't read Clean Code or the bevy of of other articles on this topic.

        The point of a forum (usually) is to promote discussion. I click on article written about stuff I know all the time. Reading the article might not tell me anything new, but the comment discussion can bring up new points or challenge existing norms that make me reconsider why I do the things I do.

  • cLeEOGPw 9 years ago

    There are tons of people who haven't read the articles that were before.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection