26 votes

What trick/pattern/concept/whatever did you adopt that has improved your code quality?

One big thing that has made maintenance of my older code easier has been considering the concept of cyclomatic complexity. In particular, limiting conditional checks to exceptional cases as much as is reasonable has made it easier to focus on the "happy" path of code execution and easily track down the errors, and the limited nesting depth has made things easier to read as well. Overall, my code remains relatively flat and I'm not branching through layers of logic trying to track down a simple bug.

What are some simple things you do to keep your code from being a massive headache long-term?

36 comments

  1. [3]
    zrkn
    Link
    There is quite insightful series of blog posts by Casey Muratori regarding this topic https://caseymuratori.com/blog_0015

    There is quite insightful series of blog posts by Casey Muratori regarding this topic
    https://caseymuratori.com/blog_0015

    9 votes
    1. [2]
      kafkaesque
      Link Parent
      Thanks for this link. This quote toward the bottom of the article is provacative: "I spend exactly zero time thinking about “objects” or what goes where. The fallacy of “object-oriented...

      Thanks for this link. This quote toward the bottom of the article is provacative:
      "I spend exactly zero time thinking about “objects” or what goes where. The fallacy of “object-oriented programming” is exactly that: that code is at all “object-oriented”. It isn’t. Code is procedurally oriented, and the “objects” are simply constructs that arise that allow procedures to be reused. So if you just let that happen instead of trying to force everything to work backwards, programming becomes immensely more pleasant."

      3 votes
      1. vakieh
        Link Parent
        The point behind thinking in objects correctly is about translating that procedural code (because he's right, code is procedural) into the real world environment (which is objects based). It is...

        The point behind thinking in objects correctly is about translating that procedural code (because he's right, code is procedural) into the real world environment (which is objects based). It is quite difficult to think of systems like ERPs for example in terms of chained processes - they're too large, with too many repetitions, and it gets way too messy in regard to data flows. By having objects which own the methods and the data, you get these little easy to understand nuggets that can get kicked around like a football without breaking everything.

        That is the real point of objects, not the reusability or inheritance. You can reuse functions, that was the point behind creating those instead of GOTO coding. It's about the inherent link between the data and the operations which access and mutate that data. THAT is OOP, not the crazy enterprisy inheritance spaghetti that reminds you of a stereotypical rural town's family tree. That is where we get awesome things like dependency injections and easy mockup testability.

        1 vote
  2. [9]
    wingsalt
    Link
    For me the biggest improvement has been thoughtful naming. It’s so important to take time to consider what you are communicating to your coworkers and your future self when you name a class,...

    For me the biggest improvement has been thoughtful naming. It’s so important to take time to consider what you are communicating to your coworkers and your future self when you name a class, method, or variable. It makes all the difference.

    If I’m in a rush or just trying to tesr something I might use the first thing that pops into my head, then refactor later. But my code improves when I think this through. I get it wrong more often than not.

    9 votes
    1. [7]
      Emerald_Knight
      Link Parent
      One thing that a lot of programmers need to get comfortable with is the idea of longer names. Who cares about character length if you can tab autocomplete? Who cares about size of source code on...

      One thing that a lot of programmers need to get comfortable with is the idea of longer names. Who cares about character length if you can tab autocomplete? Who cares about size of source code on disk when disk space is cheap? If adding that extra word or two to the function will make its purpose and behavior more clear, then do it. Sure, there's a point where it can end up becoming too verbose, but if you're running into verbosity issues then you're probably not separating out the behavior enough, anyway.

      6 votes
      1. [3]
        ABC
        (edited )
        Link Parent
        This is incredibly true. In C I'll often write function names that are really 3-4 names separated by underscores, like ModuleName_SubModuleName_FunctionName. The hardest part is picking good...

        This is incredibly true. In C I'll often write function names that are really 3-4 names separated by underscores, like ModuleName_SubModuleName_FunctionName. The hardest part is picking good names, but if done right it can make code actually understandable. Same idea for variables.

        I'm also very explicit if I need to write a complex conditional statement, use lots of whitespace, use multiple lines with one condition per line, indent to group the different levels of the condition together for clarity etc.

        if
        (
            A == B
            &&
            (
                A == C
                ||
                (
                    A == D
                    &&
                    E == True
                )
            )
        )
        {
            // Stuff
        }
        
        4 votes
        1. [2]
          Emerald_Knight
          Link Parent
          Often if I have multiple conditions, I'll instead opt to separate the individual conditions out into variables that describe the condition. Sometimes I'll separate out e.g. condition_a and...

          Often if I have multiple conditions, I'll instead opt to separate the individual conditions out into variables that describe the condition. Sometimes I'll separate out e.g. condition_a and condition_b and combine them into condition_c = condition_a && condition_b;. In the end, I'll have a quick and easy if statement that contains maybe one or two conditions that are human-readable and really easy to understand at a glance.

          Your approach certainly works, I just prefer to avoid long complicated conditionals as much as possible in favor of simpler named conditions :)

          4 votes
          1. Elusive
            Link Parent
            This is what I do too. Instead of adding a comment explaining what a sub-condition does, just use the language itself. Comments become outdated without anyone ever noticing. It's a lot easier to...

            This is what I do too. Instead of adding a comment explaining what a sub-condition does, just use the language itself. Comments become outdated without anyone ever noticing. It's a lot easier to refactor when it's just code and the compiler tells you if you messed up a reference somewhere. It being self-documenting not only aids in understanding of what it does, but often implicitly the rationale, too.

            Edit: A typo.

            3 votes
      2. Elusive
        Link Parent
        I often find myself choosing longer and more explicit names as the scope of the thing I'm naming increases. Single-character variable names are only ever used for very tight loops or one-liner...

        I often find myself choosing longer and more explicit names as the scope of the thing I'm naming increases. Single-character variable names are only ever used for very tight loops or one-liner functions. Variables with scopes spanning across multiple "pages" (on an average screen) tend to receive significantly longer names.

        1 vote
      3. [2]
        crius
        Link Parent
        Oh yes, twoThousandTimesYes. I had to work with a old-time java developer, turned js developer some time ago... and while there were much bigger issue with his code quality or even software design...

        Oh yes, twoThousandTimesYes.

        I had to work with a old-time java developer, turned js developer some time ago... and while there were much bigger issue with his code quality or even software design quality, the thing that most bothered me was that when I was going down to fix his code, it was impossible to understand a single thing. variable written like they were message sent in the '90s and zero comments.

        I ended up rewriting everything most of the time (and be also accused of not respecting his work for it).

        1 vote
        1. Emerald_Knight
          Link Parent
          That's not entirely surprising. Egos often run rampant in tech. Luckily I've not had to deal with much of that myself yet, but I recall there being once instance of a guy blowing his lid in a...

          That's not entirely surprising. Egos often run rampant in tech. Luckily I've not had to deal with much of that myself yet, but I recall there being once instance of a guy blowing his lid in a college operating systems class on the chat page for the class. He was apparently pissed off that a lot of people in the class weren't understanding the complex shit--in terribly documented, funky C code--as quickly as he was. Even the professor was a bit of an elitist, but he at least had some semblance of composure.

          2 votes
    2. Shahriar
      Link Parent
      Make it a habit for yourself and your team and it'll make fantastic improvements in readability.

      Make it a habit for yourself and your team and it'll make fantastic improvements in readability.

      1 vote
  3. [7]
    jgb
    Link
    Recently I’ve moved away from overly-OOPifying my code - learning Rust was one key catalyst for this, and I now apply these ideas in my Python code. Sometimes it’s ok to just pass around a Tuple...

    Recently I’ve moved away from overly-OOPifying my code - learning Rust was one key catalyst for this, and I now apply these ideas in my Python code. Sometimes it’s ok to just pass around a Tuple instead of creating a whole new class - and readability and maintainability is improved simply because the resultant program has fewer lines.

    7 votes
    1. [3]
      Comment deleted by author
      Link Parent
      1. jgb
        Link Parent
        My preferred university course goes quite deep into Standard ML, as I understand it, so I expect I'll end up diving into the deep end at some point in the vague future. Thanks for the book...

        My preferred university course goes quite deep into Standard ML, as I understand it, so I expect I'll end up diving into the deep end at some point in the vague future.

        Thanks for the book recommendation, I've bookmarked it.

        2 votes
      2. deleted
        Link Parent
        I really like this book so far. Thanks for the link!

        I really like this book so far. Thanks for the link!

    2. [2]
      Deimos
      Link Parent
      Python has some pretty good "in-between" options too, that are nicer than a tuple but still a lot simpler than a full class. A few examples: namedtuple (in the standard library) The attrs library...

      Python has some pretty good "in-between" options too, that are nicer than a tuple but still a lot simpler than a full class. A few examples:

      5 votes
      1. jgb
        Link Parent
        Dataclasses are definitely neat - I played around with them in a recent project and liked them a lot. I'm not actually familiar with attrs - though looking at it, I'm not sure it's nice enough to...

        Dataclasses are definitely neat - I played around with them in a recent project and liked them a lot. I'm not actually familiar with attrs - though looking at it, I'm not sure it's nice enough to justify the extra library. Even though __init__ is ugly as hell, everyone who ever reads my code will understand what it does, and for that reason alone it's worth sticking with.

        4 votes
    3. Emerald_Knight
      Link Parent
      Objects have their place, but I agree that sometimes they're a bit overused. In PHP, for instance, rather than wrapping many arguments in a dedicated object, I just place them into an associative...

      Objects have their place, but I agree that sometimes they're a bit overused. In PHP, for instance, rather than wrapping many arguments in a dedicated object, I just place them into an associative array and pull values out by key. Serves the same purpose while saving on time and effort. But if I need to validate the associative array (e.g. inserting a MongoDB document), I'll just extend a validator object to handle that particular document type.

      2 votes
    4. Social
      Link Parent
      In Python you can also use `collections.namedtuple() from collections import namedtuple employee = namedtuple("employee", ["name", "salary", "age"]) foo = employee(name="DrFaceless", salary=42,...

      In Python you can also use `collections.namedtuple()

      from collections import namedtuple
      
      employee = namedtuple("employee", ["name", "salary", "age"])
      foo = employee(name="DrFaceless", salary=42, age=-1)
      

      Then you can use foo.name, foo.salary and foo.age to access each.. tuple variable(?).

  4. [2]
    Manfred
    Link
    Maintenance becomes a lot easier when you take the time to come up with great names for concepts in your application and consistently apply them everywhere. For example, a great database scheme...

    Maintenance becomes a lot easier when you take the time to come up with great names for concepts in your application and consistently apply them everywhere. For example, a great database scheme makes sense out of the context of the application code and when the class handling accounts is named Account the database table should be called accounts and the UI should address them as accounts too.

    4 votes
    1. [2]
      Comment deleted by author
      Link Parent
      1. ABC
        Link Parent
        That's proper design though. If you need to write something new that isn't trivial, it's best to plan it all out. If it's going to be 100+ lines of code, my process tends to be something like...

        That's proper design though. If you need to write something new that isn't trivial, it's best to plan it all out. If it's going to be 100+ lines of code, my process tends to be something like spend some time laying out the goals, break things down into groups, name the concepts/modules, and write a paragraph or two about each one at a high level, and maybe draw a nice block diagram to lay it all out with the interfaces in between. It takes some time but it ends up being the majority of the hard work done at that point. Write clean code, name things well, sprinkle with comments, ezpz.

        3 votes
  5. [2]
    hightrix
    Link
    For me, it's been focusing on separation of concerns along with single purpose classes/methods. If, when describing a class/method, I use the word "and" then I probably need to rethink the...

    For me, it's been focusing on separation of concerns along with single purpose classes/methods. If, when describing a class/method, I use the word "and" then I probably need to rethink the solution. I try not to use this as a strict rule but more of a rough guideline.

    4 votes
    1. Emerald_Knight
      Link Parent
      Absolutely. Pretty much all "rules" in programming are guidelines more than anything. Your example with "and" would just be a red flag saying "something is probably wrong here, so let's review it...

      Absolutely. Pretty much all "rules" in programming are guidelines more than anything. Your example with "and" would just be a red flag saying "something is probably wrong here, so let's review it and make sure we shouldn't separate things out a bit more".

      2 votes
  6. panic
    Link
    Taking the time to finish my work. Tying up the loose ends for each piece of code means I don't have to worry about them later (or, more likely, forget about them). If there's an issue with that...

    Taking the time to finish my work. Tying up the loose ends for each piece of code means I don't have to worry about them later (or, more likely, forget about them). If there's an issue with that code later on, I don't have to wonder, was this just something I forgot to finish, or is this a real bug in the design? It can feel slower to keep refining a piece of code after you've just gotten it to work, but it pays off in the long term.

    4 votes
  7. [8]
    chewbacca
    Link
    Comment everything. Nothing is more confusing than when you abandon your project for a month, come back to it, and struggle to figure out how something you wrote yourself works. Also, it was...

    Comment everything. Nothing is more confusing than when you abandon your project for a month, come back to it, and struggle to figure out how something you wrote yourself works.
    Also, it was already mentioned earlier, but it ties into this: descriptive variable naming.

    3 votes
    1. [7]
      Emerald_Knight
      Link Parent
      Absolutely! But an important note: comments should rarely ever document how something works, but why. Documenting intent, or the functionality of a section of code rather than a line, makes a lot...

      Absolutely! But an important note: comments should rarely ever document how something works, but why. Documenting intent, or the functionality of a section of code rather than a line, makes a lot of difference. Unfortunately a lot of people treat comments like pseudo-code, which is just redundant and doesn't actually help anyone. I don't need you to tell me that you're "filtering the users array", the fucking code tells me that because you literally just wrote users.filter(function(user) { . . . });!

      9 votes
      1. [6]
        zowesiouff
        Link Parent
        can we vote more than 1 time? I want to invite myself to create an alt and upvote you a 2nd time :D I'll add that having a "how" comment is even more terrible than you make it sound: it's more...

        can we vote more than 1 time? I want to invite myself to create an alt and upvote you a 2nd time :D

        I'll add that having a "how" comment is even more terrible than you make it sound: it's more likely to get stale if the code changes, and if you start having discrepancies between the comments and the code, headaches are coming :)

        When I realise I'm starting to write a "how" comment, I'll almost always wrap whatever logic I'm documenting in a function, properly name that function and I end up with something far smaller, more descriptive and easier to reuse / compose with.

        2 votes
        1. [5]
          Emerald_Knight
          Link Parent
          Fuuuuuuck. An excellent point, and one that I often forget about. I've run into this exact problem at times and it's always been a massive headache to deal with because I'm never sure if it's the...

          it's more likely to get stale if the code changes

          Fuuuuuuck. An excellent point, and one that I often forget about. I've run into this exact problem at times and it's always been a massive headache to deal with because I'm never sure if it's the comment or the code that's right. Even worse is if I discuss it with my team (non-programmer QA/support and my ex-programmer boss who doesn't even touch the code base) and neither of them is certain either. Ultimately we end up having to make a judgment call, and I believe there was one time when we got it wrong.

          1 vote
          1. [4]
            vakieh
            Link Parent
            This is why proper version control is required for pretty much all maturity models and certifications. If you check the history of a chunk of code, you can see when the code was changed, when the...

            This is why proper version control is required for pretty much all maturity models and certifications. If you check the history of a chunk of code, you can see when the code was changed, when the comment was changed, and most importantly what the commit and change logs say about why. That will tell you (working alone, no need to waste anyone else's time) which one is up to date.

            There are some incredible possibilities coming out of the finally more open Microsoft developments related to this like XML documentation comments in C#. They will enable active and smart linting that could be linked in with whatever VCS you're using to ensure your comments can't go stale - associate a piece of code with a comment, force a review of it on commit.

            1 vote
            1. [3]
              Emerald_Knight
              Link Parent
              One important point I'm going to make here: this only works if you don't need to change version control systems. It's a pretty uncommon case, but I had this exact scenario occur earlier this year....

              If you check the history of a chunk of code, you can see when the code was changed, when the comment was changed, and most importantly what the commit and change logs say about why.

              One important point I'm going to make here: this only works if you don't need to change version control systems. It's a pretty uncommon case, but I had this exact scenario occur earlier this year. I had to migrate from SVN to Git, so all of the previous project history was lost.

              Additionally, the history may not be correct. It's possible that a commit was made without the appropriate note for that section of code, or that the code was modified with an incorrect assumption and that older behavior was desired. There are a lot of various edge cases that could apply, and I've run into quite a few of them. Commit history isn't really authoritative.

              . . .associate a piece of code with a comment, force a review of it on commit.

              Neat! I wasn't aware of this! :)

              1. [2]
                vakieh
                Link Parent
                You are 110% correct that nothing can stop a determined lazy (or externally rushed) developer. However I would point out that changing VCSs and not maintaining backward links should involve a top...

                You are 110% correct that nothing can stop a determined lazy (or externally rushed) developer. However I would point out that changing VCSs and not maintaining backward links should involve a top to bottom code review, otherwise you're basically not using VCS at all.

                1 vote
                1. [2]
                  Comment deleted by author
                  Link Parent
                  1. vakieh
                    Link Parent
                    Solution there is migrate a cold storage copy over to the same VCS on a different provider (or self-host) so you can migrate the history, while simultaneously migrating to your new chosen system....

                    Solution there is migrate a cold storage copy over to the same VCS on a different provider (or self-host) so you can migrate the history, while simultaneously migrating to your new chosen system. Means when you get super stuck after the migration you at least have the history to dig through as a worst case scenario. 20/20 hindsight though.

                    1 vote
  8. [2]
    MrHen
    Link
    Keep code that does similar things visually similar. The way I read code gets more and more about quickly identifying patterns of curly braces, indentation and keywords. I barely read variable...

    Keep code that does similar things visually similar. The way I read code gets more and more about quickly identifying patterns of curly braces, indentation and keywords. I barely read variable names during the first skim. What I want to learn quickly is:

    • How long is this function / file / class
    • How many calls to other functions does it have
    • How many logical branches does it have

    I spend a lot less time re-reading stuff by keeping code visually organized. It also helps highlight really weird code at a glance -- if something has a unique shape to it then it is probably the most complicated part of the code.

    2 votes
    1. Emerald_Knight
      Link Parent
      Sounds interesting. It's a bit vague to me, though. Got any examples off the top of your head?

      Sounds interesting. It's a bit vague to me, though. Got any examples off the top of your head?

      4 votes
  9. [2]
    Keeyzar
    Link
    I had big improvements in really short time while using entity component systems. Jumping to possible 1,5 million entities placed on the phone, sure, not all at once. (While now having only...

    I had big improvements in really short time while using entity component systems. Jumping to possible 1,5 million entities placed on the phone, sure, not all at once. (While now having only possible 5000-6000.)

    Was great fun to play with that and understanding a new concept regarding game design gave me a new perspective on things. Plus understanding a bit of the huge performance gains coming from the nature of ECS (speaking of locality of reference).

    2 votes
    1. Emerald_Knight
      Link Parent
      I've never heard of ECS before, but I've also only lightly dabbled in game programming. I'll have to take a look into that sometime!

      I've never heard of ECS before, but I've also only lightly dabbled in game programming. I'll have to take a look into that sometime!