#begin

Next is a short little chapter about Prof. Ousterhout’s view on popular software trends and how they relate to the principles of a Philosophy of Software Design. I remember reading this chapter a long while back thinking Prof. Ousterhout does not understand TDD, but we will come to that later in this blog.

 

Software Trends

Let’s start with the first popular trend in software, which is of course, Object-oriented programming and inheritance. I think if you have read any books, blogs or watched video’s about people explaining OO you also have probably heard the advise not to create deep, massive inheritance trees. This is good advise! You should not create massive inheritance trees. Inheritance is like a double edged sword, it will provide you with polymorphism and flexibility, but it is also the tightest coupling we have in OO. Massive inheritance trees are a sign of bad design and you should look for ways to break it and use composition instead of inheritance. I remember that in a book called Object-Oriented Software Engineering, A Use-Case Driven Approach by Ivar Jacobson a very good description and explanation of inheritance and composition is given.

But alright, Prof. Ousterhout was talking about the impact OO had on our industry. If we use OO principles correctly we can produce better software designs. He says a key element of OO is Inheritance which exists in two forms, Interface inheritance and implementation inheritance. The difference between them is that with interface inheritance we simply define function signatures but no implementation, but with implementation inheritance we do provide implementation details and sub-classes can choose to extend or change the implementation. You might implement this with an interface and an abstract class respectively. Just remember that implementation inheritance can be really problematic and should be avoided as much as you can. You might at some point come to a situation where you need to implement something and choose to inherit from some class, and override some methods but completely change the implementation so it doesn’t even look like the parent class anymore. This will lead to issues in the future, trust me, I’ve been there.

Uncle Bob provides similar advise in Clean Code as well. He says that if you inherit from a class and override functions, you have now created a tighter dependency on the parent class. Furthermore, since you have now overridden the parent function(s) you will most likely also introduce additional dependencies in the actual implementation of that overridden function. Prof. Ousterhout says this as well. Implementation inheritance will lead to information leakage. That’s a really nice way to put it I think. If you override some function and need to provide additional logic to extend the code you will probably create dependencies on protected variables and fields of the parent class, which is information leakage. He also says that in worst case scenarios, inherited classes will need access or knowledge of all the parent classes that came before it, which will result in very complex code. So implementation inheritance should be used with caution. I fully agree. Prof. Ousterhout also specifically mentions that, if you need to use implementation inheritance, you should consider an approach based on composition, which I already hinted at just a minute ago.

Prof. Ousterhout ends this particular section with the following statement, and I quote: “Although the mechanisms provided by object-oriented programming can assist in implementing clean designs, they do not, by themselves, guarantee good design”. I agree, if it only were that simple right!? You really need to put some thought into the code, follow best practices like the advise in Clean Code and this book and also, do not underestimate the role of experience of the developers. Sometimes you will go against the best practices just because you have the experience to do so, but you should always consider the best practices and do go totally guerrilla mode.

So next up is a section about agile development. Agile has penetrated out community very very deeply. I don’t know any people who actively use the waterfall method at this point in time. Agile is a lightweight, flexible and incremental methodology for developing software. Prof. Ousterhout says something interesting here, which I also think is a false statement by the way, but he says: “Agile development is mostly about the process of software development (organizing teams, managing schedules, the role of unit testing, interacting with customers, etc.) as opposed to software design”.

I think this is invalid since true agile, in it’s code is just eXtreme programming, marketed towards project managers. In extreme programming, technical practices are the core of the methodology. Agile was created as a way to battle management and create an approach based on rapid feedback and iteration with the customers. So to say that agile is mostly about the process I think is a false statement. However, agile and SCRUM specifically have evolved this way because they were marketed this way. I mean, project managers will go to courses, pick their nose for 2 days straight in a classroom and go home with a SCRUMmaster certification. As Uncle Bob put’s it very nicely, SCRUM is for the people side of software development, the technical side is mostly ignored.

And I bet. Uhm, let’s have some fun. I want you, the listener, to ask your SCRUMmaster, if you do SCRUM of course to ask him or her what the technical practices of SCRUM are. I bet, he or she won’t know what any of them are. Originally, there are 4 practices, TestDrivenDevelopment, Simple Design, Refactoring and Pair Programming. I also add a 5th practice to this which is Continuous integration and deployment since we cannot live without this practice anymore. We need CI/CD pipelines to be productive nowadays. But really, ask your SCRUMmaster if he can list you the four technical practices of SCRUM and I bet, he or she wont be able to list them, let alone explain what they mean and why they are important. Please let me know in the comments. I wrote some blogs about SCRUM and the technical practices before which you can read right here in this website if you search for it. If you are interested, go read them I had a lot of fun writing them. There’s also another Uncle Bob book, fully focused on agile which is called Clean Agile. It’s a great read and it’s essentially like a 300 page rant about he current state of agile. It’s fun, trust me, if you’re a geek like me at least, you might qualify the book as “fun”.

Let’s continue with the book; Prof. Ousterhout says that the most important element in Agile is the fact that we work in iterations. This is crucial to software development and design as it is absolutely clear that we cannot anticipate everything with big upfront design. Each of these little iterations evaluates and adds new features. We do however need to consider that complexity is incremental as well so we should do our best to battle complexity as much as we can.

John then makes a statement where I absolutely agree with and that is that Agile practices can lead to tactical programming. Agile can focus developers on features and not on abstractions. It encourages not to make “big upfront design” but as Dave Thomas said it: “Big upfront design is dumb, but no upfront design is dumber”. So don’t fall for this, don’t fall into this trap when someone on the team says we will do absolutely do no design because you will run into issues later in time. “So developing incrementally is generally a good idea, but the increments of development should be abstractions, not features”. That’s such a good statement from Prof. Ousterhout. He often has such a nice way to formulate his statements and this one is among them.

The next software trend Prof. Ousterhout wants to discuss is about Unit tests. Prof. Ousterhout explains the two main forms of (automated) testing which are unit and system tests or integration tests. He says that in agile, the practice of testing is put at the center, which is totally true. Remember the technical practices of agile? TDD is one of them! And why do you need tests? Well if you are doing agile, and going really really fast you need something to make sure you are not creating bugs plus you need to be able to adapt and evolve the code as time progresses. Tests facilitate refactoring. Without a test suite, you don’t know if your refactoring broke existing code! You can find out out course by doing a lot of reasoning, reading and manual testing. But why not refactor the code, run that test suite again and see if anything breaks. It’s far more efficient.

The next software trend Prof. Ousterhout wants to discuss is Test-driven development and I can fondly remember this section since even he fell into the trap of misunderstanding the practice of TDD. He says that he’s a big fan of unit testing, but not so much of TDD because and I quote: “The problem with test-driven development is that it focuses attention on getting specific features working, rather than finding the best design”.

I mean, this statement always come up by haters who don’t like TDD but it has been debunked so many times now. Remember that in TDD you first write a failing unit test, then make it pas with the least possible change you can make, but the third step, the most important one is that you refactor the code to fit the current or best design. Since you now have a passing test, you can refactor as much and long as you can as long as the tests pass. If you simply write the test first, and make it pass, but do not do the refactoring step, you will indeed run into the issue that Prof. Ousterhout laid out here. But any serious practitioner of TDD knows that the refactoring step is essential to the practice of TDD.

So Prof. Ousterhout saying that: “The problem with test-driven development is that it focuses attention on getting specific features working, rather than finding the best design”. Is simply false because this happens when people misunderstand it.

I remember that, in one of Uncle Bob’s talks he gives some advise about how to start with TDD. You start to practice, as in start learning TDD at home, not on your job! TDD is hard! First get the hang of it in small projects you do at home because the impact for failing is not that high. Once you gain some skills and confidence you bring the skill to work and start practicing it there. If you learn TDD on the job, make sure you have a mentor, or someone who carefully reviews your code, including your tests because you can really easily run into the “fragile test problem”. We talked about the fragile test problem in earlier blogs while discussing the Clean Code book. The fragile test problem happens when your test code is too heavily coupled to your production code and thus any change to the production code will break lots and lots of tests. I’ll mention a really great talk by Ian cooper again which was called; TDD, where it all went wrong. You should watch it if you are interested in TDD. It will give you some great insights.

Prof. Ousterhout then follows with another software trend which is Design Patterns. And I think we have discussed this in the previous blog as well. You should not sprinkle design patterns all over your game. It will make your code very flexible but also overly complicated and you will probable break domain language since in your domain there’s probably not singletons, observers, visitors or factories. But Design patterns do absolutely have their place in software, just don’t overdo it. When you implement a design pattern, it raises the layer of abstraction. You don’t have to explain the nitty gritty details of how you implemented your EnemySpawner, but you simply tell your colleague that you used an observer pattern which should be enough for him to understand the basics of the implementation.

This is exactly what Prof. Ousterhout says. The greatest risk with design patterns in over-application. Don’t try to force a problem into a design pattern when a custom implementation is cleaner. He’s totally right here! As with many ideas in software, don’t apply them dogmatically, apply them where they make sense!
And the last software trend Prof. Ousterhout wants to dig into is the practice of Getters and Setters in software design. We’ve talked about this in previous blogs during our deep dive into Clean Code as well. Exposing lots of Getters and Setters will lead to fragile code and it will expose the inards of your objects. Remember that objects hide their data and expose operations. When there are lot’s of getters and setters on objects you will violate the Law of Demeter very quickly. Remember that law? The Law of Demeter says that you should only know about your direct associations, and not strangers. So don’t create so called train-wreck functions like PlayerSingleton.Instance.GetPlayer.GetLeftHand.GetWeapon.Fire(). Having streams of getters like this is very fragile since it exposes the innards of your objects and it’s actually part of the ritual to summon the spaghetti monster.

Prof Ousterhout says the same thing, and I’ll quote him: “Exposed instance variables mean that part of the class’s implementation is visible externally, which violates the idea of information hiding and increases the complexity of the class’s interface. Getters and setters are shallow methods (typically only a single line), so they add clutter to the class’s interface without providing much functionality. It’s better to avoid getters and setters (or any exposure of implementation data) as much as possible.” It’s also really nice how he correlates Getters and Setters to concepts in the book, they are indeed often very shallow plus they will pollute the interface of an object.

So that’s it for another chapter. What do you think about all this? Do you agree with Prof. Ousterhout on all these topics? What’s you opinion about Massive inheritance tree’s in Object-Oriented design. How about agile being focused on tactical programming. Or unit tests being essential to software design, but TDD not being the best way to create a proper test suite since it focuses on features and not abstractions. As we have discussed earlier, the refactoring step is essential with each test you add! And what’s you opinion about design patterns and how do you think Getters and Setters impact software design?

If you have any opinions, please let me know!

Bye Bye.

#end

01010010 01110101 01100010 01100101 01101110

Hey, sorry to bother you but you can subscribe to my blog here.

Never miss a blog post!

You have Successfully Subscribed!