Looking back over 2019 I realized I've had the privilege to work on a diverse set of software projects:
- Architecting and coding an Enterprise Transform and Load (ETL) project in Python and Django
- Building an SFTP platform using AWS lambda, Node, and Vue
- Adding major features and refactoring a long-term enterprise Java project
While reviewing these projects one common thing stuck out as to why these projects were considered a success, it was due to their object-oriented design.
A key feature of each of these projects was the loose nature of the specific requirements and how details of inputs and behaviors would change as we learned more about the domain. Having a good design made making changes and testing a breeze. For example, by designing the ETL pipeline to use a canonical, a requirement change in the Python ETL project that should have taken a week to implement could be made and tested in less than a day.
This got me thinking about how I learned object-oriented design. Some of the answers are obvious, but others are less so. I want to share these approaches with you.
My earliest object-oriented design training was from taking an employer-sponsored training course with Training Hott. The course covered the most common Gang of Four design patterns. It went on to teach how to organize a set of requirements into components and analyze them to see what design patterns could be used to build an application. To be honest, I don't remember much from this course, as I didn't have much opportunity to use the techniques and patterns in my daily job.
Today there are a ton of different online resources for learning design patterns. Going the online route is cheaper than live training and often is more hands-on, but requires self-discipline to finish the course. Lastly, the barrier to entry for creating an online course is low and sometimes the quality of the course may suffer.
Another obvious way of learning object-oriented design is from books. Books are not only a great way to learn, but make great reference material when you've forgotten details and need a reminder. In my opinion, the secret of using books is to understand how the material is going to be presented and how you learn. The canonical design patterns book is the Gang of Four book, Design Patterns: Elements of Reusable Object-Oriented Software. However, it can be a tough read, especially for beginners.
In my experience, I found the Head First books an excellent place to start or to refresh yourself. They are broken down in digestible chunks with coding and thought exercises at the end of each section. Sort of like a Highlights for Coders. Two great books to start with are
O'Reilly also publishes great books on the subject and often teaches the subjects by building a sample application with the concepts.
3. Reading and Mimicking Code
One of my favorite methods of learning new design patterns is digging into the source code of my favorite frameworks and libraries. The Spring Framework has taught me more about design than any course or book. This method may be difficult for the beginner as some frameworks, such as Spring, are highly abstracted and it can be difficult to understand why classes are broken apart.
A great way to begin to dive into an abstract framework is to try and extend a portion of the framework. Often frameworks are set up to allow users to extend interfaces and abstracts in order to modify the behavior of a particular component. The Spring documentation is very detailed and often will walk the reader through the how and why of a component's design.
Another way is to read and extend the code of your team. One of my biggest jump in understanding how to create reusable components was reading and mimicking the code of the smartest people on my team. Seeing how and why code is abstracted and asking them questions about the code will often give you insight into a different way of thinking and designing.
Picking up a refactoring task or refactoring your own code before you commit is a great way to improve your understanding of design patterns. As you read the code you can begin to see where code is duplicated, confusing, or hard to test. Refactoring causes you to remove yourself from the actual code and think abstractly about how it fits into the application. Asking questions such as
- When this is refactored how can I verify it behaves the same way?
- What tests are missing from the original code?
- How can I componentize the code?
- How can I eliminate multiple or nest ifs and loops?
- How can I combine two methods or classes?
- How can I test a particular piece a logic inside a long method or function with minimum set up?
- If I was to support this code 3 years what would make this code easier to support?
- If the requirements were to change or the business wanted to change the behavior, how can I make it configurable?
I believe that proper design allows developers to easily maintain, extend, change, and test code and is often overlooked in many components. On top of becoming a better coder and creating better code, I believe you also begin to appreciate coding aesthetically and get more satisfaction from the work.