Describe What You Want Not How to Get It


So much of good software design
comes down to separating the WHAT from the HOW.





WHAT we want should be expressed in
the interfaces of the services that we create. It should clearly state WHAT the
service provides, the parameters that it needs to take in, and the value that
it returns. Our services should provide strong contracts that guarantee a range
of specified behaviors.





Think about the result that the
client wants. Think about being your own customer. This is how we want to think
when we design APIs. We want to take our callers perspective because this is
how we designed well-encapsulated systems that are straightforward to interact
with.





One of my working definitions of
the key code quality called encapsulation is about hiding HOW we do something
by only saying WHAT we do. This is a form of hiding implementation details and
we want to do this in the software that we create because when we do, it
lessens the impact of change when it happens in our code.





Most software is written in such a
way today that it is intertwined with itself and this makes it very difficult
to extend software and add new features. According to several studies that I
reference in my book, Beyond Legacy Code, it cost twice
as much to make minor enhancements to existing software than it took to create
that software in the first place.





When I see statistics like that I
realize that we have to build software differently as an industry. It’s not
like we don’t know what to do. We’re not like doctors were in the Middle Ages,
without germ theory or a good understanding of biology to draw upon.





We have the practices of Extreme Programming and good design principles and practices that are known throughout our industry. But the knowledge of good programming practices throughout our industry is quite uneven. One of the main reasons for this is that our industry is growing so rapidly. Software developers are some of the most in-demand professionals today and the supply of available developers can’t keep up.





Uncle Bob Martin says that the base
of professional software developers doubles every five years and has done so
for decades. If he’s right, then it means that more than half of the people on
every team have less than five years of experience. Couple this with the
barrage of frameworks and languages and tools and methodologies that people are
confronted with daily and we begin to see why there is a big gap in
understanding of exactly what software development is or should be as a
profession.





But regardless of the standards and
practices that we use to actually build our implementations, one of the most
valuable practices that I have found as a developer is to find ways of hiding
the details of how I implement a feature from my callers. That way my caller won’t
depend on those details so I’m free in the future to change them without affecting
my callers.





That’s the real payoff of being
implementation independent. When we can hide implementation details it means
that we can change them later without affecting other code. However,
encapsulating implementation details is a subtle business. We have to be
careful about the assumptions that we make.





I remember I was working with a
team of developers and teaching them one of my very favorite techniques for giving
code greater extensibility by providing a class with a static method to new itself up. I called this method getInstance().
A lead developer saw calls to getInstance() in my code and asked me why I was
using so many Singletons.





“Why do you think I am using Singletons?”
I asked.





He pointed to the getInstance() method calls in my code and said that they were creating Singletons. But my getInstance() method wasn’t doing that, it was just newing up an instance of itself.





Why did he think that it was creating a Singleton? Because the Gang of Four used that method name in their book, Design Patterns: Elements of Reusable Object-Oriented Software, when explain the Singleton design pattern. Is this a valid reason for me to treat that name as always invoking a Singleton?





From the client’s perspective it
simply wants to get an instance of an object and it should not have to care
whether it’s being given a Singleton or not. What happens when we realize that
just one single instance isn’t enough to service all of our callers, so we
refactor to a Doubleton or Tripleton or an object pool. When I do this do I
tell my clients they have to change the name of the getInstance() method
because it is no longer invoking a Singleton?





Clearly, this is a slippery slope.
It’s not the clients concern how I manage the instance internally. The client
simply wants to get an instance of an object and leaves it up to the object to
decide how it should fulfill that requirement in the best way possible.





This is what we mean by a separation of concerns. Client’s don’t need to be concerned with the details of their caller’s work. I also refer to this as assertive code where objects are responsible for themselves and the state they manage. Giving objects the ability to be responsible for themselves, including instantiation, lets them be more autonomous so we build software that’s more functionally independent and straightforward to reason about.





Note: This blog post is based on a section in my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software called Seven Strategies for Product Owners.

 •  0 comments  •  flag
Share on Twitter
Published on January 30, 2019 08:50
No comments have been added yet.