Understand the Pitfalls of Complex Solutions
Here's a cautionary tale from the American and Soviet space programs. Think about a solution to this problem: How do you write in a zero-G environment? The Americans and Soviets had different answers.
American engineers went to work on a self-pressurized pen.
The Soviets opted for a pencil.
Over-engineering is a trap you could fall into. š
Initial over-engineering is not the only problem you can encounter. Software systems grow in complexity all the time. Users want new features, and you must deliver. But adding those features can lead to bad designs if you are not careful.
Here's how you run into problems. The first feature is easy to write. You figure out what needs to be done, design it, and put the code in place.
Now comes another feature, which is a lot like the first one -but a bit different. How do you put in this new feature? Well, there's always copy/paste. Take the code that exists, copy and paste it in, then fix it up a little to do the new thing. Then repeat the process for subsequent features. In the long run, this code becomesĀ difficult to maintain.
Or add the new feature by addingĀ more complexityĀ to an already existing class. Since the class is already doing most of the work, what's a bit more?
The problem is really twofold.
First, the solution gradually gains complexity. Fewer peopleĀ may understand how it works.
Second is the mentality it brings with it. The team begins to accept less than quality work, for the sake of delivering a feature. So, it's more than just poor architecture; it's the view that poor architecture is OK and inevitable.
How do you avoid writing solutions that go too far? Or ones that become difficult to understand and modify? š¤
Keep it simple. A simple design has several advantages. Just ask any mechanic if they would rather work on a 1950's V-8, or an engine of today (answer: a V8). One advantage is, it isĀ easier to understand. If it's easier to understand, then it'sĀ easier to modify. Plus, you can be more confident that the modification won't break anything.
Another is that it is easier to test. If something isĀ difficult to test, it probably means it is not simple. One fix would be to split the test, and the subsequent code, into simpler-to-test pieces.
This is easier said than done. Fortunately, you can leverage the knowledge of those who came before and found a better way of doing things. SOLID design principles capture this handful of ideas.
Identify the SOLID PrinciplesĀ
Each letter in SOLID represents an excellent idea to keep in mind when architecting your system. We will examine each one in-depth as the course progresses. We'll also put them into practice by building a simple card game application. Let's get an overview of these key ideas:
"S" is for Single responsibility
A class should do one thing, and do it well. It should only have one reason to change."O" is for Open/closed principle
A class should be open to extension, but closed to modification.
What on Earth does that mean?
Well, whenever you add a new concept to the system (an extension), you shouldn't have to go back and make a bunch of changes (modification) to support it.
"L" for Liskov substitutability
Adding a subtype through inheritance should not break the existing code. I call this the "no surprises" principle. That is, if the system is working and I add a new class that is derived from another, the system should still work."I" for Interface segregation
Essentially the single responsibility principle, applied to interfaces."D" is for Dependency inversion
High-level classes shouldn't have to change when a low-level class is modified. High-level classes should define an abstraction that the lower-level class conforms to.
We will be implementing every one of these principles in Java. But first let's look at how they are incorporated into a larger structure: model-view-controller (MVC). We choose MVC asĀ the structure to build on since it aligns well with the SOLID principles.
Let's Recap!Ā
Cleaner designs are easier to understand, maintain, modify, and test.Ā
Following the SOLID principles leads to cleaner design.Ā
The SOLID principles are:
Single responsibility
Open/closed principle
Liskov substitutability
Interface segregation
Dependency inversion
Meet me in the next chapter and we'll starting putting this together with MVC!