Today is the beginning of my third week at Makers Academy. We will now try building web apps, which means that we’re about to start work with very concrete (in a sense) and immediately verifiable results. It also means that we have now completed ‘the ruby part of the course’, which feels a little odd. After spending two weeks intensively programming in ruby, I almost feel like I know less than when I started, given how much I am now aware that I have to learn. I nevertheless appreciate how I can start to use Ruby as a tool in my arsenal as we progress into more applied and integrated work. As such, this post is a reflective piece on some of the OOD principles I have picked up in the last two weeks, how well I feel I understand them, and how important they seem at this stage.
The two principles we have explored in most depth since the start of the course are the single responsibility principle, and the dependency inversion principle. I feel like I now understand both of these ideas well, although it took me a couple of days to wrap my head around dependency inversion, which I initially thought was much more complex than it actually is. At its heart, it is concerned with removing explicit references to and instantiations of classes within classes. This is to ensure that when one class changes, it does not break another class which is dependent on it; a problem which would be disastrous and costly to fix in a large software application.
The programmes we have made so far are all too small to really see the importance of these principles play out, however we have definitely encountered pitfalls which the principles are intended to mitigate. The most clear example of this is chaining of methods (a violation of the law of demeter, as I discovered today). Even in a contrived programme recording takeaway orders, I made upwards of four classes, and before I knew it I was dealing with a method call that went three levels deep. My initial intuition was that this was fine, as long as I could keep track of them in my head for long enough to make the code work. My programme was small, and sticking to best practices seemed on the face of it like an unnecessary hassle that prevented my classes from working together as I would like.
I started to change my mind when considering how to write tests in rspec that would require doubles that nested inside each other three times. I also observed that many of my test cases would fail for multiple classes when I made a small change to one of my methods. The strong focus we maintain on TDD ensures that I am constantly aware of the extent to which I am violating the best OOD practices, and the impact that this has on the rest of the programme as a result of minor tweaks. I believe this is making my skills as a developer stronger than they would be otherwise.
I feel like I am encountering a lot of new terminology all of a sudden, and often when I hear a new expression, I realise I have already been applying the idea for a few days. For example, duck-typing, the idea that type is irrelevant when invoking a certain method on an object; or encapsulation, the idea of isolating variables in a method to expose a safe means of using them outside of the class in question. Both ideas, it turns out, are key ideas in OOD best practice; the first encourages the use of methods that are not reliant on a certain class of object to work. The second ensures that variables are readable without being writable, and adheres to the principle of keeping methods short with single responsibilities.
One of my favourite quotes from Practical Object Oriented Design in Ruby is: “Pretend for a moment that your classes are people. If you were to give them advice about how to behave you would tell them to depend on things that change less often than you do”. As well as making me briefly reflect on my own life choices, this was a nice introduction to the idea that if dependency is necessary, it is apt for more concrete classes to depend on more abstract classes or principles. If a class or idea is not wed to any specific instances or objects, it is less likely to change than a class which is tied to specific instances. They represent common, stable qualities, and will therefore pose less of a risk to the programme as a whole, were more concrete classes engineered to depend on them. The world of abstractions is at about the limits of my current understanding of ruby and OOD in general, but I am looking forward to exploring it in greater depth.
I believe I have yet to fully grasp how important the principles of OOD are, however the first two weeks of Makers Academy have given me an appreciation for how they ensure that code is elegant and apt to be modified. The focus on TDD is particularly useful, as is keeps me aware at all times of the effects that changing my code is having on the programme as a whole. Understanding what it’s like to see little changes rippling through my classes will stand me in good stead for when I am dealing with much more complex systems, and need to be fastidious with my own application of design principles.