Monthly Archives: February 2015

Three letters that change how you think

Solutions feel so much more comfortable then questions; don’t they? Finding a solution makes us feel good. Solutions have power and people are willing to pay real money for solutions. Questions on the other hand cause discomfort. Questions represent problems that need to be solved and cost our money a lot of times.

So it is only natural that we focus on the solution. We jump to how a problem is solved without first understanding why it needs to be solved. We risk missing critical understanding in order to feel the rush of finding the solution.

I am not using the empirical “we” here, I am very much including myself in that “we”. I like solutions also. I like it when I can tie a problem neatly up with a bow and hand the finished package over to solve all that ails someone.

The solution is emotionally powerful but often the why is so much more important. When we understand the why we can better engineer the solution. The solution we will provide will be the correct one, or at least one that better suites the need.

 

As a developer and a problem solver how is always foremost in my mind. How can I solve the problem you are having? How do I alter my code to get the desired result? How…? “How” is powerful, it speaks of solutions and gives guidance. It is also the wrong question most of the time.

I have found that the “how” of something is inconsequential most of the time. When we focus on how we optimize for the solution rather than the issues that need a solution. We start fixing before we understand what it is we are fixing. When we ask the wrong questions we get answers that do not map correctly, even when they answer the questions we are asking.

Now if we knew the correct question we could find answers that have more meaning. The problem is that the correct question is often harder to answer. When we ask why we gain understanding of the root cause. The more we know about an issue, or request the better we can address that request. Why is much more powerful because instead of answers and guidance it leads us to understanding.

How follows why, but how is often disguised. For instance, “What would you like to see on this screen instead?” is not asking “what”. It is really asking “How do you want me to solve the issue you are pointing out with this screen?” Another hidden how is: “What if I changed this?” That question is really: “Is this how I solve the problem?”

Understanding that how can be asked many ways indirectly allows us to change the conversation by refusing to be lured in. We can instead rephrase each of the above examples to why questions. “Why do you want this screen changed?” or “What is it that you are trying to solve?” (Yes this is using “What” to hide a “Why”.)

That is only half the issue. “How” is seductive. Not only do we ask “how” when instead of “why” we are often asked “how” instead of “why”. We need to listen for it, and refuse to answer it prematurely. When we are asked “how” questions we need to change the conversation to focus on why first. We need to make sure both the person asking the question, and us, understands why. Once that understanding exists then how becomes important.

So let’s lead with understanding and follow with results. That is why a three letter word can change how, I mean why you think.

Kerney’s Hierarchy of Good Design

Talking with a friend made me think about what I use to classify my software architecture designs as good designs and why. I realized I have a hierarchy of design I apply to every solution to rate how good of a solution it is. The more it conforms to this list the better the design is. The items at the top are more important than the items at the bottom. Not every design meets all criteria. In applying these criteria to a design I will never give up an upper item to make a design that satisfies a lower item. For example, if in removing duplication I make a class less explicit, I will not remove that duplication until I find a better design.

Here is my hierarchy, my reasons follow below:

  1. Tested Coded is better than untested code
  2. Explicit code is better than non-explicit code
  3. Non-repetitive code is better than duplicated code
  4. SOLID code is better than code that is not SOLID
  5. Uncluttered Code is better than Cluttered Code

The reasons that follow all boil down to one fact: a good design is one that is easily changed to handle new requirements or lessons about how the system should behave.

My Reasons:

A.                 Tested Code is better than untested code

I believe that code under test is inherently better designed than code which is not tested, even if it is badly designed code that is hard to read and inappropriately abstracted. The reason for this is that if the code is tested, I can change it. I have some degree of certainty that my changes do not break intended functionality.

I seldom see the correct architectural solution the first time I do some something. In fact, I seldom have it by the third. However, if I have a complete suite of tests backing me up, I can, and have, changed the architecture drastically based on new understanding and need. The architecture I choose initially seldom resembles what I end up with.

So having tests verifying that the behavior does not change is invaluable to me. It lets me ensure my solution is correct without reliance to the architecture I am using.

B.                  Explicit code is better than non-explicit code

Code that clearly states what it is doing in English, or your native language, is a better design over anything that requires interpretation of commands. If a programmer can read a method as if it was a paragraph and gain insight to its intent, than the programmer is better armed for changing that method.

Being explicit about intent reduces a large number of errors by reducing what a programmer has to keep track of in their head. The more things that someone has to juggle to understand the impact of a change the more likely that person is to make a mistake.

C.                  DRY code is better than duplicated code

DRY stands for “Do not Repeat Yourself” and is about not having duplicated lines of code. Having 100% DRY code is often impossible and striving for that is often a waste of time. However, my general rule is that removing duplication is always better than having it there. I go to great lengths to remove duplication when I find it.

The reason is that duplication often means that my code may change in unexpected ways. If one piece of logic changes and subsequent ones do not, I may not understand the full impact of my change. I may forget something and leave a lingering bug. Worse yet is this bug may take years to find.

When I have all similar logic in a single place then everything that touches that code changes every time that code does. I have a better understanding of the impact of a change. I can ensure that everything changes as needed when all the changes happen in a single place.

D.                 SOLID code is better than code that is not SOLID

SOLID is a quality of “Object Oriented Programming” defined by Robert (Uncle Bob) Martin. Any code that adheres to each of the principles is said to have the qualities that make it object oriented. Each principle has its own reason for being on my hierarchy, but the whole is here as it defines if something is actually well-behaved object oriented design.

Just as with the DRY code, it is not reasonable to expect something to conform 100% of way. But things that do adhere to these principles are better designed in my book.

1.                  Single Responsibility Principle

Single Responsibility Principle (SRP) states that any piece of code should have one and only one reason to change. If the constructor of a class changes that should not cause code using other parts of that class to change.

SRP is about appropriately isolating dependencies. It is used to measure good design because code that has the appropriate level of isolation required by SRP is easier to understand and easier to change.

2.                  Open Closed Principle

Open Closed Principle (OCP) states that an object should be open to extension and closed to modification. The heart of OCP is that if new behavior is required in the system the programmer is able to extend the base objects to get this behavior without modification of that base object.

When a design adheres to the open closed principle then it allows for easier modification that does not ripple through the system. Those changes are isolated to the new subclasses and their introduction can be controlled.

3.                  Liskov Substitution Principle

Liskov Substitution Principle (LSP) states that any class must be able to be substituted with its base class. The easiest way to explain this principle is by giving an example of breaking this principle. If square inherits from rectangle this principle is violated because some calling code may try to set the length and width separately. With a square this is not possible, but with a rectangle it is.

A design that adheres to the LSP is better than one that does not. Since LSP eliminates a large potential for bugs and the code that defends against them. Since defense code disappears the code becomes easier to understand.

4.                  Interface Segregation Principle

Interface Segregation Principle (ISP) states that no class shall accept an interface with methods on it that the class does not use. Simply put it is better to have many specialized interfaces rather than lesser numbers of generic ones.

Many specialized interfaces are better design than a less generalized interfaces as it limits the number of reasons a piece of code may have to change. If a code relies on a more generalized interface, when that interface changes, it may impact that code without reason. It also clearly divides the use cases and makes code more readable.

5.                  Dependency Inversion Principle

Dependency Inversion Principle (DIP) states that classes should not directly depend on other classes, but instead depend on interfaces.

If classes depend on interfaces instead of classes, they are easier to modify and do not change because implementation changes. Instead a change must be made to the interface for a change to affect a piece of code.

E.                  Uncluttered Code is better than Cluttered Code

There are a lot of things that clutter code. Poor formatting, unnecessary comments, bad variable naming along with a whole host of other things. Clutter confuses intent and therefore represents bad design. When code is uncluttered it is easier to understand and therefore easier to change.

F.                  Honorable Mention

An honorable mention needs to be given to design patterns. The reason why they only get honorable mention is that they into of themselves do not represent good design. Instead they are a side effect of good design.

I should probably explain what a design pattern is. A design pattern is a common way people have solved similar problems in software. If the architecture was found in a number of successful projects it is deemed a pattern.

The risk here is that design patterns are a side effect of good design not a measure of a good design. If we identify a problem that has a pattern and then we architect our solution from that pattern we run the risk of over engineering our solution.

However, if we apply the filters listed above and when we are done we notice a design pattern… Well that could be an indication of being on the correct path.

Knowing design patterns is helpful and useful. They allow us to recognize a path once we are on it. They are good for navigation during the journey. We should not use them as the goal of the journey.

 


These represent the measures I use for determining the validity of my designs. As a friend of mine use to say: “Everything in moderation even moderation.” I do not use these like law. Instead I use them like shading in a picture. They are applied with enough vigor to enhance what I am working on and no more.

 

I don’t know

“I don’t know” gives us a lot of power. Using these words open pathways for communication and understanding. Too often though we ignore this phrase and start by jumping to answers that feel right rather than those based on fact.

Those three little words pack a whole lot of punch. In American society saying I don’t know is often very hard to do. In fact at least one study shows that even our children have trouble saying those words. The same study suggests that our very schooling rewards us for figuring out possible answers rather than admitting we do not know.

There is often a perception that logic should be enough to eliminate the uncertainty of not knowing. We should be able to extrapolate from known data to arrive at a logical conclusion as an answer to a question. That is a great technique to gain insight and guidance. The trouble starts when we take that extrapolated point of view as fact.

Fact is something that is. A fact is solid and unchangeable. A fact is also temporal and because things change, what was true before may not be true now. That does not change the validity of the fact or make the fact mutable. Logic can lead us to facts, but does not guarantee them.

Logic is good at leading us to hypotheses. A hypothesis is an idea based on known information. It is not a fact, but may represent one. A hypothesis must be tested and observed before it can be treated as a fact, and in truth it may sometimes never become a fact. That does not make the hypothesis of any less value. The real value of a hypothesis is that it gives us something to learn from.

I bring this up because understanding these differences helps relieve a lot of problems in software development and life in general. If we know what we have is a hypothesis then we can test it for validity. We can discuss it and research it. If we cannot prove it is a fact we can at least prove that it is valid enough. Knowing its validity means we have gained insight and can make a better decision.

Recognizing that we have a hypothesis instead of a fact is an admission that we do not know. This is a very powerful situation to be in. If we do not know something we can learn it, we can change it, and we can grow it to where it needs to be. I am not saying that not knowing something allows us to change the underlying facts, but instead allows us to realize that there may be a different course than we thought when we started. The facts may be different than perceived or even that the facts we thought mattered don’t. Only by testing and researching our hypothesis can we gain this knowledge.

So do not be afraid to say “I don’t know.” Use the power of those three words to unleash potential, find new avenues, and spark creative communication. Repeat after me: “I don’t know.”