#begin
Next-up is a chapter about modifying existing code. And from what I can remember, this is very focused on, well… comments, again. John puts in a real effort to make it abundantly clear that comments are really important for good software design. I remember thinking differently about this, but ever since we’re making these blogs about it I think comments do actually hold value when they are in a supported format for documentation generation and intellisense. So let’s dive in and see what Prof. Ousterhout tells us about how to modify existing code.
Modifying Existing Code
He starts of by restating that software development is an incremental process and this often includes increments in complexity. A system’s design is constantly evolving and thus is it impossible to conceive the right design right at the beginning of the project. The design of a mature system is determined more by changes made during the system’s evolution than by any initial conception.
This is all so true, and exactly why the waterfall methodology turned out be such a big disaster. For those who don’t know; the waterfall methodology is a software development methodology where you work in predetermined phases, like requirements elicitation and analysis, software design, development, testing, deployment and at last maintenance. So you first gather all the requirements and analysis of what needs to be build. Then in the next phase you create the software design for the entire system. Next you implement that design and actually write the software and follow that with a phase of testing. Last you deploy it and do maintenance.
This process is really out of touch with reality since the design you made of some system, will almost never end up as the actual design of the system. In abstract matters it might be, but when as the design gets more detailed, you will see you divert from. When you implement the actual design you will find out about things you did not anticipate or things you can simply do better. So you change the design while implementing the software. But enough about the waterfall method. Software development methodologies are a blog topic of its own and we will dive into them in the future because they are important but that’s not the subject of this blog. So let’s continue.
Prof. Ousterhout continues chapter 16, modifying existing code with a section about staying strategic in these modifications. In earlier chapters we discussed the mindsets programmers tend to have while writing software, the tactical and the strategic mind. While in the tactical mindset we fully focus at the task at hand, trying to implement a feature or fixing a bug as quickly as we can, not thinking about additional complexity we introduce or anticipating future changes. However with the strategic mindset we do focus our efforts on anticipating future changes, code reusability and fighting against incremental complexity. So tactical programming focuses on getting thins working, but strategic programming also includes keeping the design of your game or system maintainable and simple.
John believes that many programmers have a tactical mindset when they have to adapt or extend existing code. He thinks developers just want to make the smallest change possible to implement something because they might be afraid they break something else and introduce bugs. And I guess, he’s right, it’s also one of the main themes of the clean code book. Uncle Bob always talks about how programmers make such a great mess that they are afraid to change the code because, and I’ll quote Uncle Bob directly; “If you break it, it becomes yours”! This sounds so stupid, but it is true. I bet some of you listening have been blamed some time when you changed some existing code, which needed to be changed in order to implement some requirement, but then you broke the code since it was a horrible mess without any tests. I certainly have in the past! And I’ll probably run into this in the future as well. Sometimes when you start or help other developers in existing codebases you simply do not know the code well enough, or the domain well enough to be 100% sure nothing will break when you change things. Yes, this is a symptom of dirty code but still this can happen some times. We do our absolute best to circumvent these kinds of problems by employing the practices we learn from this book; A philosophy of Software Design and Clean Code.
But Ok, let’s continue with the book. Prof. Ousterhout was explaining that lot’s of developers are afraid to modify existing code because they are afraid to break things. This leads to developers wanting to make the smallest possible change in order to implement a feature. But this will also lead to them adding in lots of minimal changes, with some very special-purpose cases, dependencies or other forms of complexity. As a result, the system design gets just a bit worse, and the problems accumulate with each step in the system’s evolution. This is the perfect example of tactical programming and is also the exact opposite of Uncle Bob’s boy scout rule which says, leave the camp ground cleaner than you found it and translates to: you should always check the code in cleaner than you checked it out.
Prof. Ousterhout says that if you want to maintain proper and clean software design you must take a strategic approach when dealing with modifications to an existing system. He then again makes a very bold statement which says, and I quote: “Ideally, when you have finished with each change, the system will have the structure it would have had if you had designed it from the start with that change in mind”. Which is so very true, but also pretty difficult sometimes. He says you can achieve this by not giving into the temptation to make an easy fix, but instead think about how you can fit the requirement in the current design and if it does not fit how can you adapt the system’s design to make it so, and come up with the best possible alternative. You should not be afraid to refactor the system to fit in the new requirement.
So this way you align your work with the strategic mind set and take an approach aimed towards investment rather than doing things tactical and quickly. It’s OK to take a bit more time to implement a feature or fix a bug because you will end up with a cleaner system. John then says something that highly correlates to Uncle Bobs Boy scout rule which is: If you are not making the system better, you are making it worse. And, I mean, he’s right, the design can go either way so we do our absolute best to make it better, not worse.
But Prof. Ousterhout also admits that sometimes, taking the quick and dirty road is the best one to take. If the cleanest way to fix an issue is to do 3 months worth of refactoring, but an easy fix can be made in 2 hours. You are probable better off taking the quick fix, make your deadline and then start refactoring the system to the cleaner solution. I’ve talked about this in previous blogs as well. Sometimes, just to please some manager or another stakeholder who promised something to a client, you hack some feature in. But once it is released, you refactor the code or you even just revert the code back to the state before the release and start over. This is not very efficient, I admit, but it is the sad reality sometimes. But then again, these edge cases don’t occur often.
Prof. Ousterhout then also says something interesting which I think contrasts with Uncle Bob’s advise in Clean Code and that is he thinks that every company should plan and spend a small fraction of time on refactoring and clean up. On the other hand, Uncle Bob says you should never ask, or put refactoring on a schedule. It’s part of your job, this is the way you do practice your profession. You are a professional, remember that. Personally, I think it’s somewhere in the middle, I agree with Uncle Bob that refactoring is part of your job, you do it constantly and never ask permission for refactoring. But when you find out, some refactoring which should absolutely be done is going to take a lot of time, you should put it on the schedule since the impact on the code, and the planning is large. This way you can battle technical debt, and everyone is aware of the issues at hand. So I think both Uncle Bob and Prof. Ousterhout have a valid point here.
The next section of the book is about keeping the comments near to the code. And I think this is a very good idea. If you start refactoring code and comments start to drift away from the original code, they will become outdated and misleading. These are the comments I will gladly delete from your codebase. It’s easy to forget to update comments when you are updating existing code but with a little discipline you can keep these comments up to date. And btw, note that we are talking about summaries here. So if you for example change the number of arguments of a function, don’t forget to update the summary to include that additional argument as well! Interestingly, the remainder of this chapter is about how to keep comments up to date, and not so much about modifying existing code. Here we can see again how much emphasis Prof. Ousterhout puts on comments.
He says that and I quote: “The best way to ensure that comments get updated is to position them
close to the code they describe, so developers will see them when they change the code.” This is surely true. Summaries to are always close to the thing they describe, just make sure your are not referencing seemingly random other code in summaries. This will only create confusion. He then again repeats some very important comment about comments which is: “users should not need to read either code or header files; they should get their information from documentation compiled by tools such as Doxygen or Javadoc. In addition, many IDEs will extract and present documentation to users, such as by displaying a method’s documentation when the method’s name is typed. Given tools such as these, the documentation should be located in the place that is most convenient for developers working on the code.”
Soo.. yeah.. this is totally true and what I’ve been ranting about a lot in the previous blogs, excuse me for that by the way. He also says you should not put all the information about a method in a comments that can be used for generating documentation. You should take that comment apart and put the comments near the implementation of the code inside the method. I’m not a great fan of this as I thing you as a listener might know by now, but yeah it’s kind of clutter when you put all the implementation details inside a summary comment. There will be far too much information in such a comment, and it will become very large, which will definitely reduce the chance that anyone will ever read the entire damn thing.
He then gives an example on how to comment a function that consists of three phases. He says he would put a block comment at the top of the function that explains there are three phases. And then also add additional details in comments when a new phase is started in the function. I really don’t like this. If a function consists of three phases, abstract these functions out, and if necessary extract the entire function, including the extracted functions for the phases out into its own object. That’s what I would do. But what do you think? Would you prefer to take up Profs. Ousterhout’s advise and make a massive function with inlined comments, or would you take up Uncle Bob’s advise and extract the phases out into private functions, and if the class grows too large, extract the total out into an entirely new object? Let me know, I’m really curious about your opinions.
Next Prof. Ousterhout describes a common mistake while modifying existing code which is that comments belong in the code, not the commit log. And, yeah I’ve seen this before. Sometimes the commit logs have really detailed information that could have perfectly been described in a summary above some class, interface or function. And these logs are not really read much. Maybe during code review or once you need to find a specific commit later in time. I’ll often check the commit logs on a Monday morning to remind myself what the last couple of things were that were merged to dev or master or whichever branch I checked out. But just remember that if there are really important, low level implementation details that require documentation, summaries are the way to go in c# context. These will show up in your IDE through intellisense and documentation tooling.
And next there is also a short section about avoiding duplication while maintaining comments. Sometimes when extending or maintaining existing code, it’s really tempting to simply copy paste some code and fiddle it into working for your new requirement. But you also copied the comment but it’s not entirely true anymore, plus there are now two duplicate comments but they describe code that do something different. If you do this, also make sure to update comment since it can be very confusing and misleading to keep these duplicated comments in the code. Uncle Bob talks about this in his Clean Code book as well. This especially happens when comments or summaries are mandated by management or someone else. People will simply copy paste the code, including the summary but not change the summary because they already fit the requirement of; “there must always be a summary above public facing entities.”
But also, don’t re-document one module’s design decisions in another module. For example, don’t put comments before a method call that explain what happens in the called method. If readers want to know, they should look at the interface comments for the method. Prof Ousterhout then also says: If information is already documented someplace outside your program, don’t repeat the documentation inside the program; just reference the external documentation. Which makes total sense to me and I agree here fully.
And next he also gives the good advise to check the commit diffs before merging things into develop or master. Read the code, including your comments and summaries to make sure they still make sense even after your pull-request has been accepted and merged. Also don’t forget to remove any commented code and ToDo comments. I’ve talked about these ToDo comments that almost always turn into Don’t Do comments. Just make tickets for these ToDO’s in the project management software your company uses. This way the ToDo’s get tracked in the software and they can follow the normal process of software development plus everyone is aware that something still needs to be done in order to complete a specific requirement or feature.
And the final thought in this chapter is that higher level comments are easier to maintain. This is because they do not reflect implementation details and thus remain true for a long time if the domain language and the design overall is correct.
And that’s it for chapter 16, modifying existing code. I thought it was a rather interesting take on modifying code since Prof. Ousterhout speaks more about comments than anything else. He hasn’t spoken much about how to actually modify code, what best practices are there and how do you fight complexity creep. But yeah, he started with a small section in the beginning of the chapter where he talked about how you should always take a strategic mindset to modifying existing code. That’s totally true of course.
#end
01010010 01110101 01100010 01100101 01101110
Recent Comments