In the year 9 CE three Roman legions, a combat strength of over 20,000 men, were annihilated in a surprise attack in Roman-occupied Germania. A coalition of rebel Germanic tribes had planned for months to lead the Romans down a narrow forest path where they would be ambushed and picked off. The plan had worked out.
Rome’s loss was so complete they would never occupy Germania again.
This event was a rare setback for the old Roman emperor, Caesar Augustus, a thoughtful and deliberate man. The Teutonic moves had thrown his ideas for extended Germanic conquest into disarray.
By the time Augustus died, he had been in office for 41 years, the longest of all Roman emperors. During his reign, he had outmanoeuvred rivals, charmed the Roman populace with buildings and art, and expanded Roman territory into an immense empire.
It’s come down to us that one of Augustus’s saying was ‘Well done is quickly done’. It’s a one-liner that served him well.
A good job is quick because it does not require fixing up. On the other hand, shoddy work has the appearance of speed but will need to be reworked. Any savings on the hack are an illusion and evaporate later when someone has to repair it. Often additional costs are incurred leaving us wishing we’d done it properly from the beginning. Well done is quickly done.
This insight is nothing new—it’s at least 2000 years old.
In software development, how often has it happened that the quick bug fix or rushed feature ultimately required more effort than if we had done it diligently and correctly from the start?
If this strategy worked for the most enduring, successful Roman emperor (and Germanic tribes) maybe we ought to think again when considering a quick-fix? Well done is quickly done.
Yesterday we examined Coupling. Today we’ll look at Coupling’s alter-ego: Cohesion.
You’ve probably heard that code with low Cohesion is likely to be problematic, while highly cohesive systems are easier to maintain.
It’s true; but why? What is Cohesion?
I like this definition:
“A class has high Cohesion if it contains methods and data that ‘naturally belong together’.
Conversely, a class has low Cohesion if the methods and data don’t fit well together.“
Unfortunately, this definition is a bit wishy-washy; what does ‘naturally belongs together‘ actually mean?
OK, time for a couple of examples.
Firstly, say, we have a Customer class in an eCommerce system. Customer has the following methods:
CalcDeliveryRoute()
PrintOrderReport()
Save()
Do these look like they belong together? No, they don’t. The responsibilities of the three methods vary wildly:
Programmers from the IT department are responsible for data persistence. They change the implementation of the Save() method.
PrintOrderReport() is an administrative function. The Accounting department uses it to track large customer orders. Accountants are requesting modifications to this report.
Finally, Operations and Logistics drive changes to CalcDeliveryRoute().
Let’s get more precise with our definition of Cohesion. Robert C. Martin (aka Uncle Bob) has restated the Single Responsibility Principle, which is all about Cohesion, as:
“A module (or class) should be responsible to one and only one actor.”
‘Actor‘ is a term from Unified Modelling Language (UML) meaning ‘a distinct group of system users’.
Is our Customer class cohesive? No, since three separate actors may request changes to it:
Logistics for CalcDeliveryRoute(),
the Accounting department for PrintOrderReport(), and
IT to the Save() method.
OK, what about an example of a cohesive class? Class ShoppingCart in the same eCommerce system has these methods and getter properties:
Add()
Remove()
Clear()
Total
Contents
All five behaviours manage merely the contents of ShoppingCart. A single ‘actor’ would request changes to the cart’s operations. ShoppingCart is highly cohesive.
Finally, it is worth noting that we developers can reduce Cohesion even if all existing methods and data structures reside inside the one class. How would this happen? Simple—by not putting a new behaviour onto the class that it naturally belongs to.
To illustrate this point, we’ll continue with the ShoppingCart example. Let’s say new legislation requires eCommerce websites to display the GST amount pre-checkout.
Programatically, one way to a high Cohesion implementation would be to put a GST or GstAmount getter property on the ShoppingCart class.
Unfortunately, the developer didn’t realise that the GST calculation depends on a fixed GST rate and ShoppingCart.Total and can therefore be encapsulated in ShoppingCart. No, they decided to implement GST calculations outside of ShoppingCart. In so doing, the developer has unwittingly dealt the eCommerce system a blow—Cohesion is now lower. This seemingly small mistake, left unchecked, will see us having code like this littering the application:
var gst = cart.Total * GST_RATE;
or even
var gstAmt = cart.Total * 0.15;
while the more cohesive outcome might have looked like this:
var subtotal = cart.Subtotal; // before GSTvar gst = cart.GstAmount; // GST calculated inside ShoppingCartvar total = cart.Total; // Subtotal + GstAmount
Carefully consider where you place behaviour—small mistakes today may blow up into maintainability headaches in the future.
Today and tomorrow we’ll look at Coupling and Cohesion. You might have heard that Coupling is bad and Cohesion is good. Yes, that is true. These two concepts are mirror opposites of one another:
Coupling – Code that does not belong together
Cohesion – Code that belongs together
If we achieve low Coupling and high Cohesion, our software should be easier to understand and simpler to change than vice versa; high Coupling and low Cohesion.
Say, in high-level business logic we access a SQL Server database in this way:
var database = new SqlServerDataAccess(connectionString); var orders = database.GetCustomerOrders(customerId);
In this example, the business logic has a dependency on data access. In the first line, SqlServerDataAccess is directly instantiated:
var database = new SqlServerDataAccess(connectionString);
That is a problem. Why?
Hard to change. If we wanted to change our data access to a MongoDB database, we could not easily do so. We are already committed to SqlServerDataAccess.
Hard to unit test. We will have a hard time unit testing the business logic code without actually making calls to the SQL Server database. Unit tests don’t make calls to databases.
We have an undesirable dependency from the business logic to SQL Server data access code. We say that the business logic is coupled to the data access.
How do we identify Coupling?
Look for code that changes for different reasons.
Business logic changes when business stakeholders change their minds regarding workflows. Data access changes when database admins and developers want to store or retrieve data differently. It doesn’t make sense to have the business logic depend on DBAs and developers’ whims.
Code should read like English. As much as possible anyway. For Christmas, Santa brought me a coffee mug, and it has printed on its side a short, hilarious code snippet that approaches this ideal.
Here is the code again:
while (working) { coffee.drink(); work.execute(); if (coffee == "empty") { if (coffeepot == "empty") coffeepot.brew(); coffee.refill(); } }
Yes, it’s pretty clear what’s going on.
But could it be even better?
Yesterday I asked you to send in your answers on how you would improve the coffee mug code. And send in your answers you did. I was delighted with the audience participation level: I got three well-thought-out responses.
The first response was from Andrew Baird. Andy suggested replacing the string comparisons in the two if statements with boolean properties (or methods) on the coffee and coffeepot object, respectively:
while (working) { coffee.drink(); work.execute(); if (coffee.isEmpty) { if (coffeepot.isEmpty) coffeepot.brew(); coffee.refill(); } }
What I like about Andy’s idea is the increase in the code’s abstractness; it is no longer concerned with measuring emptiness via direct string comparison. The exposed isEmpty properties on coffee and coffeepot hide the implementation detail. After all, this is high-level code—it should only be concerned in determining that a vessel is empty (or not), and not at all with how this determination occurs.
Andy also pointed out that the working variable’s boolean state could be absorbed into the work object—maybe as another property, haveWork. Unfortunately, if(work.haveWork), has lost us the joke of the original code.
Natasha’s response mirrored Andy’s regarding bringing the state of the working variable into the work object. Natasha named her property isInProgress, so the predicate becomes if(work.isInProgress), which I slightly prefer to if(work.haveWork)since it reads more like English.
Natasha spotted another improvement, one which had eluded me: The first two lines in the while loop, coffee.drink() and work.execute(), are more effective as the last two lines in the loop. Natasha is right when she says that there is no point refilling the coffeepotafter doing our work.
But there is another reason why coffee.drink() and work.execute() should go at the end: It’s safer. Thank you, Eugine, for coming up with this gem. After all, we can’t drink an empty cup of coffee! If coffee is empty to start with then coffee.drink() may throw an exception or otherwise destabilise the program. In any case, without coffee, we would not have the energy to power our work execution, would we?!?
However, if we first check and refill as necessary, then we get to drink our coffee and execute our work:
while (work.isInProgress) { if (coffee.isEmpty) { if (coffeepot.isEmpty) coffeepot.brew(); coffee.refill(); } coffee.drink();
work.execute();
}
I find it fascinating how we ended up in a situation where we ‘do’ our work on the last line and all prior lines inside the loop are concerned with getting the coffee sorted. Talk about code mimicking real life! ;-)
We are almost done. Now all the coffee preparation code could go into a separate local method:
private void prepareCoffee(Coffee coffee) { if (coffee.isEmpty) { if (coffeepot.isEmpty) coffeepot.brew(); coffee.refill(); } }
Finally leaving us with
while (work.isInProgress) { prepareCoffee(coffee); coffee.drink(); work.execute(); }
Not bad!
One more thing. Could we have encapsulated the coffee preparation code on the coffee object itself? Yes, I suppose we could have defined a coffee.prepare() method. Logically, I have my doubts as to whether the coffeepot object should entirely be subsumed, via Aggregation or Composition, into the coffee object. It seems that coffee and coffeepot are more like siblings to one another than coffee owning the behaviour of coffeepot. Therefore it makes more sense, IMHO, to have coffee prepared at the highest level—and so we end up with prepareCoffee(coffee).
Thank you to Andy, Natasha and Eugine for your improvement suggestions. You guys did all the heavy lifting!
For Christmas, I received a hilarious coffee mug from my father-in-law.
Here is a photo of it.
It’s an amusing little program. I’ve transferred the listing:
while (working) { coffee.drink(); work.execute(); if (coffee == "empty") { if (coffeepot == "empty") coffeepot.brew(); coffee.refill(); } }
I love coffee and programming—it’s the perfect present for me.
But there is something that I love even more about the mug:
The code is so simple a layperson can understand it.
My 80-year-old father-in-law, who is not a programmer, could see the hilarity of the coffee-consuming code. Other non-programmer family members also immediately got the joke and smiled at its appropriateness.
And it had to be so. If the mug manufacturer had made the code too complicated and lost the joke, then no mugs would have ended up in Christmas stockings.
Not that it would fit on the side of a coffee mug, but 200 lines of over-complicated computer code indented to 6 levels, is not funny. On the contrary—it’s sad. A software developer would have to invest much time and effort to learn what is going on.
The mug’s lesson is simply this:
We ought to write our code so it’s easy to understand and simple to change.
That’s it.
Let me propose that we start 2021 out the right way and commit to writing easy-to-read code. To the best of our abilities, of course. And it’s a skill we can always get better at. There is no end goal. Imagine how much we could improve our working lives if we could stick to such a commitment! Who knows—maybe easy-to-read code will catch on with our fellow developers?
Tomorrow we’ll look at how we could improve the coffee mug code.
Question To You: Can you see ways of improving the code on the coffee mug? If so, please send me your ideas to olaf@codecoach.co.nz. I will publish the best responses tomorrow.
Have you ever watched babies learning to walk? It’s fascinating. The way they gingerly move themselves into a standing position, holding onto a wall or other structure. They slowly put one foot forward, but they lose balance and fall to the floor. And then they repeat this process. Again. And again. Pretty much always with the same result. By the time they are confident walkers, they will have tried and failed, hundreds of times.
One day when my eldest son was learning to walk, he slipped and hit his head on the corner of our wooden coffee table. Luckily there was no blood, but he did get a decent bruise above his right eye. Within minutes, a golf-ball-sized purple lump had swelled up, and he could hardly open his eye. Did that stop him wanting to be a walker? Nope. Later on the same day, he was back at it, practising his walking!
Not walking is not an option for babies; they all become walkers. They ignore the falls. The failures are required to get the success—they are part of the process—no success without those failures.
“Success Is Going from Failure to Failure Without Losing Your Enthusiasm”
– Winston Churchill
If babies can show this level of perseverance, why can’t we? Why do we give up so readily on what we want?
Many of us are in careers and jobs we hate. Family and friends tell us to be realistic, or we have told ourselves as much. We need to be financially secure and comfortable. Now we hate what we do with our time, but we have the money to buy the latest iPhone.
Maybe we even tried a couple of times to get out of the rat race, to start our own business or new career. But it doesn’t work out—time to get real and call it quits. Usually, we tend to give it a few half-hearted attempts and then leave it at that. It must be too hard and impossible to achieve.
It’s like we’ve forgotten what we used to ‘know’ as babies—that the failures are necessary. They are the stepping stones to our success. It’s time to recall that if we keep relentlessley coming at an obstacle, it will at some point, crumble before us.
If you adopted the perseverance of babies, imagine what mountains you could conquer.
“Our inward power, when it obeys nature, reacts to events by accommodating itself to what it faces – to what is possible. It needs no specific material. It pursues its own aims as circumstances allow; it turns obstacles into fuel. As a fire overwhelms what would have quenched a lamp. What’s thrown on top of the conflagration is absorbed, consumed by it – and makes it burn still higher.”
For our example, we had a CalculateStreak() method from an eLearning platform. Again, here is the listing:
public int CalculateStreak(int streak, IEnumerable<StudentQuiz> quizzes) { var thisWeekFirstDay = _dtSvc.GetStartOfWeek(_dtSvc.UtcNow); var lastWeekQuizzeDates = quizzes.Where(q => q.startedAt >= thisWeekFirstDay.AddDays(-7) && q.startedAt < thisWeekFirstDay)
.GroupBy(q => q.startedAt.Date); var thisWeekQuizzeDates = quizzes.Where(q => q.startedAt >= thisWeekFirstDay)
.GroupBy(q => q.startedAt.Date);
var lastWeekContinuity = lastWeekQuizzeDates.Count(); var thisWeekContinuity = thisWeekQuizzeDates.Count(); if (lastWeekContinuity < STREAK_CONTINUITY) streak = 0; if (thisWeekContinuity >= STREAK_CONTINUITY) streak++; return streak; }
This method comprises regular legacy code, nothing special. We get the gist of what it does, i.e. calculate the length of a learning ‘streak’ based on quizzes, but it is not that clear, at a glance, how it does its work. Yesterday we wanted to characterise the behaviour of CalculateStreak() by introducing unit tests. However, the method was private, and we could not call it in a test. We have fixed this problem by declaring it public, at the cost of compromising encapsulation a little.
Now we’re hitting the next obstacle. We should not be surprised; the standard operating procedure when trying to write unit tests for legacy code is to move from one dependency that we must break to another. That’s fine; ultimately, we’ll get there.
So which line poses the next stumbling block?
It’s
var thisWeekFirstDay = _dtSvc.GetStartOfWeek(_dtSvc.UtcNow);
_dtSvc is a reference to a class member of type DateTimeService. DateTimeService implements interface IDateTimeService. Good news should we need to mock or stub the service.
It appears the method invokes _dtSvc.GetStartOfWeek() to calculate the ‘first day of this week’ – the variable name could read more naturally, maybe firstDayOfTheWeek?
_____________________
Aside: There is another problem with this line of code. It smacks of Feature Envy. The call to GetStartOfWeek() takes as argument a term that is also part of _dtSvc, specifically _dtSvc.UtcNow.
A better way to express this behaviour would have been to add a parameterless GetStartOfWeek() overload that internally makes a forwarding call to the parameterised overload:
public DateTimeOffset GetStartOfWeek() { return GetStartOfWeek(UtcNow); }
The call in CalculateStreak() then reduces to
var thisWeekFirstDay = _dtSvc.GetStartOfWeek();
We could go even further and condense this into a getter property.
Isn’t that much nicer?!
_____________________
Let’s return our attention back to the call to _dtSvc.GetStartOfWeek().
Stubbing the DateTimeService for a single value seems a bit of overkill. Is there an easier way?
Yes, there is.
We could make thisWeekFirstDay a parameter on CalculateStreak() and move the call to the DateTimeService outside the method. It would mean that for unit testing, we don’t have to stub DateTimeService; we could pass thisWeekFirstDay argument values, as appropriate.
public int CalculateStreak(int streak, IEnumerable<StudentQuiz> quizzes, DateTimeOffset thisWeekFirstDay) { var lastWeekQuizzeDates = quizzes.Where(q => q.startedAt >= thisWeekFirstDay.AddDays(-7) && q.startedAt < thisWeekFirstDay)
.GroupBy(q => q.startedAt.Date); var thisWeekQuizzeDates = quizzes.Where(q => q.startedAt >= thisWeekFirstDay)
.GroupBy(q => q.startedAt.Date); var lastWeekContinuity = lastWeekQuizzeDates.Count(); var thisWeekContinuity = thisWeekQuizzeDates.Count(); if (lastWeekContinuity < STREAK_CONTINUITY) streak = 0; if (thisWeekContinuity >= STREAK_CONTINUITY) streak++; return streak; }
We can turn the existing version of CalculateStreak() into a forwarding overload to ensure those existing callers of CalculateStreak() work as before:
public int CalculateStreak(int streak, IEnumerable<StudentQuiz> quizzes) { var thisWeekFirstDay = _dtSvc.GetStartOfWeek(_dtSvc.UtcNow); return CalculateStreak(streak, quizzes, thisWeekFirstDay); }
Promoting a difficult-to-stub local variable to a parameter has significantly simplified the process of arranging unit tests for our method. Additionally, the data retrieval logic of the DateTimeService didn’t gel well with the rest of the behaviour in CalculateStreak() which is business logic solely concerned with how we calculate the length of a student’s streak.
Recently I came across the below method. Take a quick look. Do you understand what it does?
private int CalculateStreak(int streak, IEnumerable<StudentQuiz> quizzes) { var thisWeekFirstDay = _dtSvc.GetStartOfWeek(_dtSvc.UtcNow); var lastWeekQuizzeDates = quizzes.Where(q => q.startedAt >= thisWeekFirstDay.AddDays(-7) && q.startedAt < thisWeekFirstDay)
.GroupBy(q => q.startedAt.Date); var thisWeekQuizzeDates = quizzes.Where(q => q.startedAt >= thisWeekFirstDay)
.GroupBy(q => q.startedAt.Date); var lastWeekContinuity = lastWeekQuizzeDates.Count(); var thisWeekContinuity = thisWeekQuizzeDates.Count(); if (lastWeekContinuity < STREAK_CONTINUITY) streak = 0; if (thisWeekContinuity >= STREAK_CONTINUITY) streak++; return streak; }
The method originates from a service class in an eLearning system. It determines the number of consecutive weeks, a ‘streak’, in which a student has completed at least one quiz. The system quizzes student to test how well they are progressing in their subject. Ideally, students should do quizzes every week but may choose not to. If they have missed a week, they have ‘broken’ their streak, and the streak length will be reset to zero. If they have added another week of completing quizzes, the length of their streak is incremented by 1.
The eLearning company has decided to change how streaks are calculated. Unfortunately, this method had no unit tests. Unit tests are great for ensuring we haven’t broken existing functionality. A useful suite of unit tests lets us know whenever we break existing application behaviour.
Before making our modifications to this method, we were going to characterise the existing behaviour with unit tests. However, we hit a snag right away: The method is declared as private. We won’t be able to access it in a unit test.
What are we to do?
Simple. We change the method to be public. Now we have access and can write our unit tests.
Why do we have encapsulation? Well-encapsulated code clarifies the behaviour of a system. For example, a method exposes its signature, i.e. method name, return value and parameters. The detail of how the method does its work is hidden, i.e. encapsulated, in the method body.
Breaking encapsulation to allow for unit testing does make it slightly harder to reason about the behaviour of the system. However, the unit tests make up for this loss. Explanatory unit tests characterise the action of the system and let us reason about our code more directly. Once we have unit tests in place, we can safely change the structure of the code to reintroduce and even improve encapsulation. For example, rather than retain the streak calculation code in a service class with many responsibilities, we could move it to a new StreakCalculator class. A temporary suspension of strict encapsulation to introduce unit tests will have enabled a superior program structure and encapsulation.
Yesterday we explored the famous The Singleton Pattern – Code Coach. Today we’ll look at the Monostate Pattern which we can often substitute for Singleton. Both Monostate and Singleton solve the same problem:
The data must always be in sync and in a single location.
That is the only reason we should apply either of these patterns; not because it makes the logic simpler to have only a single instance. Most of the time, you want to use regular instance objects, where each holds its own internal state different from the others.
OK. Let’s take a look at the Monostate. How do we create a Monostate class?
We declare our backing fields as static.
I like to think of static state as utterly separate from instance state. It’s memory that is not part of the instance at all. When we declare a field or property as static, it means we have only a single copy shared by all objects.
Here is a simple Monostate class definition:
public class Monostate { private static string data; public string Data { get { return data; } set { data = value; } } public Monostate() { } }
It looks deceptively like an instance class. But having the backing field declared as static makes all the difference: There is only one copy of the data.
How does our Monostate behave?
var monostate1 = new Monostate();var monostate2 = new Monostate();monostate1.Data = "blah";Console.WriteLine($"monostate1.Data: {monostate1.Data}");Console.WriteLine($"monostate2.Data: {monostate2.Data}");
And the output will be
monostate1.Data: blahmonostate2.Data: blah
Yet we only set monostate1.Data. monostate2.Data contains the same value since it is pointing to the same backing data.
It means we can create as many instances as we see fit, and they will all represent the same data.
One of the criticisms the Monostate pattern attracts is that from the outside it looks like a regular class, but on the inside it behaves differently. My view differs – I believe that this is a strength. It’s an example of object-orientation (OO) at its best – using Abstraction and Encapsulation.
We should ask the question: Why do the callers need to know the internal implementation? It’s none of their business. The static backing state is encapsulated and hidden from callers of the class. The class does its job – how it does, is not a concern of the calling code.
OK, here are some further points comparing Monostate and Singleton:
Singletons use a static factory method to return the single instance. Monostate objects can be instantiated the usual way – using the new operator.
Both Singletons and Monostate are classes and can implement interfaces. When working with the abstracting interfaces, both can be mocked in unit tests easily enough. On the other hand, when we must overcome instantiation of Singleton (static method) or Monostate (new operator) in a chunk of code we are trying to unit test, then this is equally awkward and difficult.
Suppose we want to move away from Monostate to a regular, instance class implementation. In that case, we can inject an instance class against the interface without having to modify the calling code.
With multiple concurrent threads accessing the Singleton instantiation logic, we could end up with more than a single instance. Monostate does not have this problem; simultaneous threads can safely create Monostate objects.
Both Monostate and Singletons require locking on access to static fields to be threadsafe.
Monostates objects look and feel like instance objects, but their implementation differs to suit their ‘single copy data’ requirements. Why should we need to use a different programming paradigm (i.e. Singleton) because we desire a different implementation? We don’t;
The Singleton Pattern is probably the most widely used (and abused) design pattern, which is a shame because it has some serious flaws.
Developers tend to apply the Singleton Pattern when they want to ensure the existence of only one object instance. One object means only a single copy of the state exists at any given point in time.
Some situations where we might want to have only a single instance are for a database connection, logger, or cache. In these use cases, we often desire only a single instance of the same state. Alternatively, some objects could be very resource-intensive to create. An optimisation might be to instantiate such an expensive object only once and then reuse it.
Here is a description of how to create a Singleton:
Declare the constructor as private, to avoid direct instantiation.
Declare a private static Instance property (or class member) to hold our single instance.
Define a public static method (or property) that returns the singleton instance. We can use lazy instantiation to create a new instance when it doesn’t exist yet.
A simple Singleton implementation would look like this:
public class Singleton { private static Singleton Instance = null;
private Singleton() { } public static Singleton GetInstance() { if (Instance == null) Instance = new Singleton(); return Instance; } // Instance methods/properties to call on our Singleton instance. public string Data { get; set } // ... }
How does this code behave?
var singleton = Singleton.GetInstance(); var anotherReference = Singleton.GetInstance(); singleton.Data = "abc"; Console.WriteLine($"Set singleton.Data to {singleton.Data}"); Console.WriteLine($"singleton.Data: {singleton.Data}"); Console.WriteLine($"anotherReference.Data: {anotherReference.Data}"); Console.WriteLine();
anotherReference.Data = "xyz"; Console.WriteLine($"Set anotherReference.Data to {anotherReference.Data}"); Console.WriteLine($"singleton.Data: {singleton.Data}"); Console.WriteLine($"anotherReference.Data: {anotherReference.Data}");
And the output is:
Set singleton.Data to abc singleton.Data: abc anotherReference.Data: abc Set anotherReference.Data to xyz singleton.Data: xyz anotherReference.Data: xyz
As we see, irrespective of which reference we are using, we are referring to to the same instance. A change to Data in one is reflected in the other.
The Singleton pattern has its problems:
If we change our minds about the class being a Singleton, we will need to modify all the calls to GetInstance(). Potentially such a change will touch many areas of our application.
The GetInstance() method in our simple example is not threadsafe. A careless implementation of GetInstance() could have multiple concurrent threads instantiate several copies of the data. When we have simultaneous threads, GetInstance() will require a locking mechanism.
Last but not least, Singleton code can be tricky in unit tests. The Singleton may represent an entity that we would prefer to mock rather than refer to the real object in a unit test, like a database connection. Naturally, we don’t want to call into a database in a unit test. However, the GetInstance() method is static, and statics are notoriously difficult to mock. We may have to use advanced unit testing techniques, like Extract & Override, to overcome this obstacle. We’ll look into Extract & Override another time.
There is a better alternative to the Singleton Pattern. We’ll check this out tomorrow.
Philosophy Friday: Well Done Is Quickly Done
/0 Comments/in Philosophy Friday /by Olaf ThielkePhilosophy Friday:
Well Done Is Quickly Done
Photo by iam_os on Unsplash
In the year 9 CE three Roman legions, a combat strength of over 20,000 men, were annihilated in a surprise attack in Roman-occupied Germania. A coalition of rebel Germanic tribes had planned for months to lead the Romans down a narrow forest path where they would be ambushed and picked off. The plan had worked out.
Rome’s loss was so complete they would never occupy Germania again.
This event was a rare setback for the old Roman emperor, Caesar Augustus, a thoughtful and deliberate man. The Teutonic moves had thrown his ideas for extended Germanic conquest into disarray.
By the time Augustus died, he had been in office for 41 years, the longest of all Roman emperors. During his reign, he had outmanoeuvred rivals, charmed the Roman populace with buildings and art, and expanded Roman territory into an immense empire.
It’s come down to us that one of Augustus’s saying was ‘Well done is quickly done’. It’s a one-liner that served him well.
A good job is quick because it does not require fixing up. On the other hand, shoddy work has the appearance of speed but will need to be reworked. Any savings on the hack are an illusion and evaporate later when someone has to repair it. Often additional costs are incurred leaving us wishing we’d done it properly from the beginning. Well done is quickly done.
This insight is nothing new—it’s at least 2000 years old.
In software development, how often has it happened that the quick bug fix or rushed feature ultimately required more effort than if we had done it diligently and correctly from the start?
If this strategy worked for the most enduring, successful Roman emperor (and Germanic tribes) maybe we ought to think again when considering a quick-fix? Well done is quickly done.
What Is Cohesion?
/0 Comments/in Today's Tip /by Olaf ThielkeWhat Is Cohesion?
Photo by Scott Sanker on Unsplash
Yesterday we examined Coupling. Today we’ll look at Coupling’s alter-ego: Cohesion.
You’ve probably heard that code with low Cohesion is likely to be problematic, while highly cohesive systems are easier to maintain.
It’s true; but why? What is Cohesion?
I like this definition:
Unfortunately, this definition is a bit wishy-washy; what does ‘naturally belongs together‘ actually mean?
OK, time for a couple of examples.
Firstly, say, we have a
Customerclass in an eCommerce system.Customerhas the following methods:CalcDeliveryRoute()PrintOrderReport()Save()Do these look like they belong together? No, they don’t. The responsibilities of the three methods vary wildly:
Save()method.PrintOrderReport()is an administrative function. The Accounting department uses it to track large customer orders. Accountants are requesting modifications to this report.CalcDeliveryRoute().Let’s get more precise with our definition of Cohesion. Robert C. Martin (aka Uncle Bob) has restated the Single Responsibility Principle, which is all about Cohesion, as:
“A module (or class) should be responsible to one and only one actor.”
‘Actor‘ is a term from Unified Modelling Language (UML) meaning ‘a distinct group of system users’.
Is our Customer class cohesive? No, since three separate actors may request changes to it:
CalcDeliveryRoute(),PrintOrderReport(), andSave()method.OK, what about an example of a cohesive class? Class
ShoppingCartin the same eCommerce system has these methods and getter properties:Add()Remove()Clear()TotalContentsAll five behaviours manage merely the contents of
ShoppingCart. A single ‘actor’ would request changes to the cart’s operations.ShoppingCartis highly cohesive.Finally, it is worth noting that we developers can reduce Cohesion even if all existing methods and data structures reside inside the one class. How would this happen? Simple—by not putting a new behaviour onto the class that it naturally belongs to.
To illustrate this point, we’ll continue with the
ShoppingCartexample. Let’s say new legislation requires eCommerce websites to display the GST amount pre-checkout.Programatically, one way to a high Cohesion implementation would be to put a
GSTorGstAmountgetter property on theShoppingCartclass.Unfortunately, the developer didn’t realise that the GST calculation depends on a fixed GST rate and
ShoppingCart.Totaland can therefore be encapsulated inShoppingCart. No, they decided to implement GST calculations outside ofShoppingCart. In so doing, the developer has unwittingly dealt the eCommerce system a blow—Cohesion is now lower. This seemingly small mistake, left unchecked, will see us having code like this littering the application:var gst = cart.Total * GST_RATE;or even
var gstAmt = cart.Total * 0.15;while the more cohesive outcome might have looked like this:
Carefully consider where you place behaviour—small mistakes today may blow up into maintainability headaches in the future.
What Is Coupling?
/0 Comments/in Today's Tip /by Olaf ThielkeWhat Is Coupling?
Photo by Georg Eiermann on Unsplash
Today and tomorrow we’ll look at Coupling and Cohesion. You might have heard that Coupling is bad and Cohesion is good. Yes, that is true. These two concepts are mirror opposites of one another:
If we achieve low Coupling and high Cohesion, our software should be easier to understand and simpler to change than vice versa; high Coupling and low Cohesion.
Say, in high-level business logic we access a SQL Server database in this way:
In this example, the business logic has a dependency on data access. In the first line, SqlServerDataAccess is directly instantiated:
var database = new SqlServerDataAccess(connectionString);That is a problem. Why?
We have an undesirable dependency from the business logic to SQL Server data access code. We say that the business logic is coupled to the data access.
How do we identify Coupling?
Business logic changes when business stakeholders change their minds regarding workflows. Data access changes when database admins and developers want to store or retrieve data differently. It doesn’t make sense to have the business logic depend on DBAs and developers’ whims.
Tomorrow we’ll explore Coupling’s polar opposite: Cohesion.
Improving The Coffee Mug Code
/0 Comments/in Today's Tip /by Olaf ThielkeImproving The Coffee Mug Code
Code should read like English. As much as possible anyway. For Christmas, Santa brought me a coffee mug, and it has printed on its side a short, hilarious code snippet that approaches this ideal.
Here is the code again:
Yes, it’s pretty clear what’s going on.
But could it be even better?
Yesterday I asked you to send in your answers on how you would improve the coffee mug code. And send in your answers you did. I was delighted with the audience participation level: I got three well-thought-out responses.
The first response was from Andrew Baird. Andy suggested replacing the string comparisons in the two
ifstatements with boolean properties (or methods) on thecoffeeandcoffeepotobject, respectively:What I like about Andy’s idea is the increase in the code’s abstractness; it is no longer concerned with measuring emptiness via direct string comparison. The exposed
isEmptyproperties oncoffeeandcoffeepothide the implementation detail. After all, this is high-level code—it should only be concerned in determining that a vessel is empty (or not), and not at all with how this determination occurs.Andy also pointed out that the
workingvariable’s boolean state could be absorbed into theworkobject—maybe as another property,haveWork. Unfortunately,if(work.haveWork), has lost us the joke of the original code.Natasha’s response mirrored Andy’s regarding bringing the state of the
workingvariable into theworkobject. Natasha named her propertyisInProgress, so the predicate becomesif(work.isInProgress), which I slightly prefer toif(work.haveWork)since it reads more like English.Natasha spotted another improvement, one which had eluded me: The first two lines in the
whileloop,coffee.drink()andwork.execute(), are more effective as the last two lines in the loop. Natasha is right when she says that there is no point refilling thecoffeepotafter doing our work.But there is another reason why
coffee.drink()andwork.execute()should go at the end: It’s safer. Thank you, Eugine, for coming up with this gem. After all, we can’t drink an empty cup of coffee! Ifcoffeeis empty to start with thencoffee.drink()may throw an exception or otherwise destabilise the program. In any case, without coffee, we would not have the energy to power our work execution, would we?!?However, if we first check and refill as necessary, then we get to drink our coffee and execute our work:
I find it fascinating how we ended up in a situation where we ‘do’ our work on the last line and all prior lines inside the loop are concerned with getting the coffee sorted. Talk about code mimicking real life! ;-)
We are almost done. Now all the coffee preparation code could go into a separate local method:
Finally leaving us with
Not bad!
One more thing. Could we have encapsulated the coffee preparation code on the
coffeeobject itself? Yes, I suppose we could have defined acoffee.prepare()method. Logically, I have my doubts as to whether thecoffeepotobject should entirely be subsumed, via Aggregation or Composition, into thecoffeeobject. It seems thatcoffeeandcoffeepotare more like siblings to one another thancoffeeowning the behaviour ofcoffeepot. Therefore it makes more sense, IMHO, to havecoffeeprepared at the highest level—and so we end up withprepareCoffee(coffee).Thank you to Andy, Natasha and Eugine for your improvement suggestions. You guys did all the heavy lifting!
Coffee Mug Code
/0 Comments/in Today's Tip /by Olaf ThielkeCoffee Mug Code
For Christmas, I received a hilarious coffee mug from my father-in-law.
Here is a photo of it.
It’s an amusing little program. I’ve transferred the listing:
I love coffee and programming—it’s the perfect present for me.
But there is something that I love even more about the mug:
My 80-year-old father-in-law, who is not a programmer, could see the hilarity of the coffee-consuming code. Other non-programmer family members also immediately got the joke and smiled at its appropriateness.
And it had to be so. If the mug manufacturer had made the code too complicated and lost the joke, then no mugs would have ended up in Christmas stockings.
Not that it would fit on the side of a coffee mug, but 200 lines of over-complicated computer code indented to 6 levels, is not funny. On the contrary—it’s sad. A software developer would have to invest much time and effort to learn what is going on.
The mug’s lesson is simply this:
We ought to write our code so it’s easy to understand and simple to change.
That’s it.
Let me propose that we start 2021 out the right way and commit to writing easy-to-read code. To the best of our abilities, of course. And it’s a skill we can always get better at. There is no end goal. Imagine how much we could improve our working lives if we could stick to such a commitment! Who knows—maybe easy-to-read code will catch on with our fellow developers?
Tomorrow we’ll look at how we could improve the coffee mug code.
Question To You: Can you see ways of improving the code on the coffee mug? If so, please send me your ideas to olaf@codecoach.co.nz. I will publish the best responses tomorrow.
Philosophy Friday: Failure And Perseverance
/0 Comments/in Philosophy Friday /by Olaf ThielkePhilosophy Friday: Failure And Perseverance
Photo by GR Stocks on Unsplash
Have you ever watched babies learning to walk? It’s fascinating. The way they gingerly move themselves into a standing position, holding onto a wall or other structure. They slowly put one foot forward, but they lose balance and fall to the floor. And then they repeat this process. Again. And again. Pretty much always with the same result. By the time they are confident walkers, they will have tried and failed, hundreds of times.
One day when my eldest son was learning to walk, he slipped and hit his head on the corner of our wooden coffee table. Luckily there was no blood, but he did get a decent bruise above his right eye. Within minutes, a golf-ball-sized purple lump had swelled up, and he could hardly open his eye. Did that stop him wanting to be a walker? Nope. Later on the same day, he was back at it, practising his walking!
Not walking is not an option for babies; they all become walkers. They ignore the falls. The failures are required to get the success—they are part of the process—no success without those failures.
If babies can show this level of perseverance, why can’t we? Why do we give up so readily on what we want?
Many of us are in careers and jobs we hate. Family and friends tell us to be realistic, or we have told ourselves as much. We need to be financially secure and comfortable. Now we hate what we do with our time, but we have the money to buy the latest iPhone.
Maybe we even tried a couple of times to get out of the rat race, to start our own business or new career. But it doesn’t work out—time to get real and call it quits. Usually, we tend to give it a few half-hearted attempts and then leave it at that. It must be too hard and impossible to achieve.
It’s like we’ve forgotten what we used to ‘know’ as babies—that the failures are necessary. They are the stepping stones to our success. It’s time to recall that if we keep relentlessley coming at an obstacle, it will at some point, crumble before us.
If you adopted the perseverance of babies, imagine what mountains you could conquer.
Promote Dependencies To Parameters
/0 Comments/in Today's Tip /by Olaf ThielkePromote Dependencies To Parameters
Photo by Emile Perron on Unsplash
Yesterday we discovered why we ought to favour unit tests over encapsulation.
For our example, we had a
CalculateStreak()method from an eLearning platform. Again, here is the listing:This method comprises regular legacy code, nothing special. We get the gist of what it does, i.e. calculate the length of a learning ‘streak’ based on quizzes, but it is not that clear, at a glance, how it does its work. Yesterday we wanted to characterise the behaviour of
CalculateStreak()by introducing unit tests. However, the method was private, and we could not call it in a test. We have fixed this problem by declaring itpublic, at the cost of compromising encapsulation a little.Now we’re hitting the next obstacle. We should not be surprised; the standard operating procedure when trying to write unit tests for legacy code is to move from one dependency that we must break to another. That’s fine; ultimately, we’ll get there.
So which line poses the next stumbling block?
It’s
var thisWeekFirstDay = _dtSvc.GetStartOfWeek(_dtSvc.UtcNow);_dtSvcis a reference to a class member of typeDateTimeService.DateTimeServiceimplements interfaceIDateTimeService. Good news should we need to mock or stub the service.It appears the method invokes
_dtSvc.GetStartOfWeek()to calculate the ‘first day of this week’ – the variable name could read more naturally, maybefirstDayOfTheWeek?_____________________
Aside: There is another problem with this line of code. It smacks of Feature Envy. The call to
GetStartOfWeek()takes as argument a term that is also part of_dtSvc, specifically_dtSvc.UtcNow.A better way to express this behaviour would have been to add a parameterless
GetStartOfWeek()overload that internally makes a forwarding call to the parameterised overload:The call in
CalculateStreak()then reduces toWe could go even further and condense this into a getter property.
Isn’t that much nicer?!
_____________________
Let’s return our attention back to the call to
_dtSvc.GetStartOfWeek().Stubbing the
DateTimeServicefor a single value seems a bit of overkill. Is there an easier way?Yes, there is.
We could make
thisWeekFirstDaya parameter onCalculateStreak()and move the call to theDateTimeServiceoutside the method. It would mean that for unit testing, we don’t have to stubDateTimeService; we could passthisWeekFirstDayargument values, as appropriate.We can turn the existing version of
CalculateStreak()into a forwarding overload to ensure those existing callers ofCalculateStreak()work as before:Promoting a difficult-to-stub local variable to a parameter has significantly simplified the process of arranging unit tests for our method. Additionally, the data retrieval logic of the
DateTimeServicedidn’t gel well with the rest of the behaviour inCalculateStreak()which is business logic solely concerned with how we calculate the length of a student’s streak.Favour Unit Tests Over Encapsulation
/0 Comments/in Today's Tip /by Olaf ThielkeFavour Unit Tests Over Encapsulation
Photo by Annie Spratt on Unsplash
Recently I came across the below method. Take a quick look. Do you understand what it does?
The method originates from a service class in an eLearning system. It determines the number of consecutive weeks, a ‘streak’, in which a student has completed at least one quiz. The system quizzes student to test how well they are progressing in their subject. Ideally, students should do quizzes every week but may choose not to. If they have missed a week, they have ‘broken’ their streak, and the streak length will be reset to zero. If they have added another week of completing quizzes, the length of their streak is incremented by 1.
The eLearning company has decided to change how streaks are calculated. Unfortunately, this method had no unit tests. Unit tests are great for ensuring we haven’t broken existing functionality. A useful suite of unit tests lets us know whenever we break existing application behaviour.
Before making our modifications to this method, we were going to characterise the existing behaviour with unit tests. However, we hit a snag right away: The method is declared as
private. We won’t be able to access it in a unit test.What are we to do?
Simple. We change the method to be
public. Now we have access and can write our unit tests.Hold On. Doesn’t that break Encapsulation?
Yes, it most certainly does.
Why do we have encapsulation? Well-encapsulated code clarifies the behaviour of a system. For example, a method exposes its signature, i.e. method name, return value and parameters. The detail of how the method does its work is hidden, i.e. encapsulated, in the method body.
Breaking encapsulation to allow for unit testing does make it slightly harder to reason about the behaviour of the system. However, the unit tests make up for this loss. Explanatory unit tests characterise the action of the system and let us reason about our code more directly. Once we have unit tests in place, we can safely change the structure of the code to reintroduce and even improve encapsulation. For example, rather than retain the streak calculation code in a service class with many responsibilities, we could move it to a new StreakCalculator class. A temporary suspension of strict encapsulation to introduce unit tests will have enabled a superior program structure and encapsulation.
Favour unit tests over encapsulation.
Prefer Monostate To Singleton
/0 Comments/in Today's Tip /by Olaf ThielkePrefer Monostate To Singleton
Photo by Raymond T. on Unsplash
Yesterday we explored the famous The Singleton Pattern – Code Coach. Today we’ll look at the Monostate Pattern which we can often substitute for Singleton. Both Monostate and Singleton solve the same problem:
The data must always be in sync and in a single location.
That is the only reason we should apply either of these patterns; not because it makes the logic simpler to have only a single instance. Most of the time, you want to use regular instance objects, where each holds its own internal state different from the others.
OK. Let’s take a look at the Monostate. How do we create a Monostate class?
static.I like to think of static state as utterly separate from instance state. It’s memory that is not part of the instance at all. When we declare a field or property as static, it means we have only a single copy shared by all objects.
Here is a simple Monostate class definition:
It looks deceptively like an instance class. But having the backing field declared as static makes all the difference: There is only one copy of the data.
How does our
Monostatebehave?And the output will be
Yet we only set
monostate1.Data.monostate2.Datacontains the same value since it is pointing to the same backing data.It means we can create as many instances as we see fit, and they will all represent the same data.
One of the criticisms the Monostate pattern attracts is that from the outside it looks like a regular class, but on the inside it behaves differently. My view differs – I believe that this is a strength. It’s an example of object-orientation (OO) at its best – using Abstraction and Encapsulation.
We should ask the question: Why do the callers need to know the internal implementation? It’s none of their business. The static backing state is encapsulated and hidden from callers of the class. The class does its job – how it does, is not a concern of the calling code.
OK, here are some further points comparing Monostate and Singleton:
Monostates objects look and feel like instance objects, but their implementation differs to suit their ‘single copy data’ requirements. Why should we need to use a different programming paradigm (i.e. Singleton) because we desire a different implementation? We don’t;
Prefer Monostate to Singleton.
The Singleton Pattern
/0 Comments/in Today's Tip /by Olaf ThielkeThe Singleton Pattern
Photo by Robert F. on Unsplash
The Singleton Pattern is probably the most widely used (and abused) design pattern, which is a shame because it has some serious flaws.
Developers tend to apply the Singleton Pattern when they want to ensure the existence of only one object instance. One object means only a single copy of the state exists at any given point in time.
Some situations where we might want to have only a single instance are for a database connection, logger, or cache. In these use cases, we often desire only a single instance of the same state. Alternatively, some objects could be very resource-intensive to create. An optimisation might be to instantiate such an expensive object only once and then reuse it.
Here is a description of how to create a Singleton:
private, to avoid direct instantiation.private static Instanceproperty (or class member) to hold our single instance.public staticmethod (or property) that returns the singleton instance. We can use lazy instantiation to create a new instance when it doesn’t exist yet.A simple Singleton implementation would look like this:
How does this code behave?
And the output is:
As we see, irrespective of which reference we are using, we are referring to to the same instance. A change to
Datain one is reflected in the other.The Singleton pattern has its problems:
GetInstance(). Potentially such a change will touch many areas of our application.GetInstance()method in our simple example is not threadsafe. A careless implementation ofGetInstance()could have multiple concurrent threads instantiate several copies of the data. When we have simultaneous threads,GetInstance()will require a locking mechanism.GetInstance()method isstatic, and statics are notoriously difficult to mock. We may have to use advanced unit testing techniques, like Extract & Override, to overcome this obstacle. We’ll look into Extract & Override another time.There is a better alternative to the Singleton Pattern. We’ll check this out tomorrow.