Business People Don’t Think They Care About Clean Code
Do business people care about clean code? They behave like they don’t. Well, they do and I can prove it using proof by contradiction. For the best results, read this proof first.
Suppose that a business person does not care about clean code. The business person wants features and they want them fast. So they pressure engineers to just get the code working. This causes the code to deteriorate. The business person wants more features, but the code is a mess so features take longer to add and things that work start to break. If the business person wants features fast, they need clean code and if they need clean code they must care about it too, which contradicts the statement that business people don’t care about clean code. The contradiction proves the original supposition to be false, proving that business people care about code structure, even if they don’t realize it.
©2013 James Grenning's Blog. All Rights Reserved.
.Engineers and Programmers, Stop Writing So Much Firmware
(this article is not just for embedded developers)
A few months back I was reading Doug Schmidt’s blog, on The Growing Importance of Sustaining Software for the DoD, and he made the claim
“although software does not wear out, firmware and hardware become obsolete, thereby requiring software modifications”.
It was a bit of a clarifying moment for me. Doug clarified two terms that I suppose were obvious, or maybe not. Software is this thing that can have a long useful life, where firmware is going to be regularly be made obsolete as hardware evolves.
I’d like to add to Doug’s statement:
although software does not wear out, it can be destroyed from within by unmanaged dependencies on firmware and hardware.
Think of all the code denied the potential long life of software due to being infected with dependencies on hardware.
By firmware I don’t mean just the code lives in ROM, as the definitions I found suggest. It’s not firmware because of where it is stored, it is firmware because of what it depends upon and how hard it is to change as hardware evolves, and hardware does evolve (pause and look at your for phone for evidence).
I have nothing against firmware, or firmware engineers (I’ve been known to write some firmware myself). But what we really need is less firmware and more software. Actually, I am disappointed that firmware engineers write so much firmware!
By the way non-embedded engineers, you essentially write firmware too whenever you bury SQL in your code or when you spread platform dependencies throughout your code. Android and iPhone app developers do it when they don’t separate everything they should from dependency on those platforms.
I’ve been involved in a lot of efforts where the line between the product code (the software) and the code that interacts with the product’s hardware (the firmware) is pretty fuzzy at best, fuzzy to the point of non-existence. For example, in the late 90′s I had the fun of helping to redesign a communications system that was transitioning from time-division multiplexing (TDM) to voice over IP (VOIP). VOIP is how things are done now, TDM was state of the art in the 80′s and 90′s. Whenever we had a question for the systems engineer about how a call should react to a given situation, he would disappear and a little later emerge with a very detailed answer. Where did he get the answer? From the worn out legacy code. The existing implementation had no separation between TDM and the business logic of making calls. The whole product was hardware/technology dependent from top to bottom and could not be untangled.
Take another example, of a brand new message processor/dispatcher that resides in the same file as code that interacts with a UART. The message processor was polluted with UART details. It could have been software with a long useful life. Instead the brand new firmware would soon be obsolete. The message processor was denied the opportunity to become software! And that is just not right!
I’ve known and understood the need for separating software from hardware for a long time, but Doug’s words clarified how to use the terms software and firmware in relationship to each other.
So engineers and programmers, stop writing so much firmware and give your code a chance at a long useful life.
©2013 James Grenning's Blog. All Rights Reserved.
.Accessing static Data and Functions in Legacy C — Part 2
Maybe you read Part 1 of this article. If you did you’ll know it concerns adding tests to legacy code (legacy code is code without tests). You will also know that the code has file scope functions and data that we want to test directly.
My opinion on accessing private parts of well designed code, is that you do not need to. You can test well design code through its public interface. Take it as a sign that the design is deteriorating when you cannot find a way to fully test a module through its public interface.
Part 1 showed how to #include the code under test in the test file to gain access to the private parts, a pragmatic thing to do when wrestling untested code into a test harness. This article shows another technique that may have an advantage for you over the technique shown in Part 1. Including the code under test in a test case can only be done once in a test build. What if you need access to the hidden parts in two test cases? You can’t. That causes multiple definition errors at link time.
This article shows how to create a test access adapter to overcome that problem.
We’d like to get IsLeapYear() under test. IsLeapYear() is a static function from Date.c introduced in Part 1. I’d like to write this test, but IsLeapYear is hidden, so we get compilation and/or link errors.
TEST(Date, regular_non_leap_year)
{
CHECK_FALSE(IsLeapYear(1954));
CHECK_FALSE(IsLeapYear(2013));
}
You get compilation errors, because there is no function declaration in Date.h for the hidden functions and data. If you overcame those errors by adding declarations, in the test file or tolerating the related warnings, you would be rewarded with unresolved external reference errors by the linker.
The solution is pretty straight-forward; write the test using a test access adaptor function:
TEST(Date, regular_non_leap_year)
{
CHECK_FALSE(CallPrivate_IsLeapYear(1954));
CHECK_FALSE(CallPrivate_IsLeapYear(2013));
}
CallPrivate_IsLeapYear() is a global function declared in DateTestAccess.h like this:
#ifndef DATE_TEST_ADAPTOR_INCLUDED #define DATE_TEST_ADAPTOR_INCLUDED #include "Date.h" bool CallPrivate_IsLeapYear(int year); #endif
CallPrivate_IsLeapYear() is implemented in DateTestAccess.c like this:
#include "Date.c"
bool CallPrivate_IsLeapYear(int year)
{
return IsLeapYear(year);
}
You could add similar accessors for private data to DateTestAccess.h
#ifndef DATE_TEST_ADAPTOR_INCLUDED #define DATE_TEST_ADAPTOR_INCLUDED #include "Date.h" bool CallPrivate_IsLeapYear(int year); const int * GetPrivate_nonLeapYearDaysPerMonth(void); #endif
Implemented like this:
const int * GetPrivate_nonLeapYearDaysPerMonth(void)
{
return nonLeapYearDaysPerMonth;
}
There are some variations of this that could be helpful. If the code under test has problem #include dependencies, you could #define symbols that are needed in DateTestAdaptor.c and also #define the include guard symbol that prevents the real header from being included.
I don’t love doing any of this, except when I do. That is limited to when it solves the problem of getting hidden code under test without modifying the code under test. A plus is that the code under test does not know it is being tested, that’s a good thing. Neither of these approaches are long term solutions. They are pragmatic steps toward getting code under tests so that it can be safely refactored and have new functionality test-driven into it.
©2013 James Grenning's Blog. All Rights Reserved.
.Accessing static Data and Functions in Legacy C — Part 1
And a Happy Leap Year Bug
It’s a new year; last year was a leap year; so the quadrennial reports of leap year bugs are coming in. Apologies are in the press from Apple, TomTom, and Microsoft. Trains we stopped from running in China. Somehow calling them glitches seems to make it someone else’s fault, something out of their control. How long have leap years been around? Julius Caesar introduced Leap Years in the Roman empire over 2000 years ago. The Gregorian calendar has been around since 1682. This is not a new idea, or a new bug.
I’m going to try to take one excuse away from the programmers that create these bugs by answering a question that comes up all the time, “How do I test static functions in my C code?”
In code developed using TDD, static functions are tested indirectly through the public interface. As I mentioned in a this article TDD is a code rot radar. It helps you see design problems. Needing direct access to hidden functions and data in C is a sign of code rot. It is time to refactor.
But what about existing legacy code that has statics? It is probably way past the time for idealism and time for some pragmatism. In this article and the next, we’ll look at how to get your code untouched into the test harness and access those pesky static variables and functions.
If you don’t mind touching your code, you could change all mentions of static to STATIC. Then using the preprocessor, STATIC can he set to static during production and to nothing for test, making the names globally accessible. In gcc you would use these command line options
- For production builds use -dSTATIC=static
- For unit test builds use -dSTATIC
Let’s look at two options that, at least for access to statics, you will not have to touch your code to get it under test. First is #include-ing your .c in the test file. In the next article we’ll build a test adapter .c that give access to the hidden parts.
We are going to revisit code that is similar to the original code responsible for the Zune Bug. I rewrote the code to avoid attracting any lawyers but it is structured similarly to the original Zune driver, complete with static data and functions that must be correct for the function to work.
The header file provides a data structure and initialization function for figuring out the information about the date. Here is the header:
typedef struct Date
{
int daysSince1980;
int year;
int dayOfYear;
int month;
int dayOfMonth;
int dayOfWeek;
} Date;
void Date_Init(Date *, int daysSince1980);
enum {
SUN = 0, MON, TUE, WED, THU, FRI, SAT
};
enum {
JAN = 0, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC
};
Date_Init populates the Date instance passed in. Ignoring the fact that I can probably fully test this by rigging the daysSince1980, and inspecting the contents of the resulting Date structure, we are going to see how we can directly test the hidden functions and data.
Date_Init has three hidden helper functions.
void Date_Init(Date* date, int daysSince1980)
{
date->daysSince1980 = daysSince1980;
FirstSetYearAndDayOfYear(date);
ThenSetMonthAndDayOfMonth(date);
FinallySetDayOfWeek(date);
}
Date_Init is the tip of the iceberg. All the interesting stuff is happening in the hidden data and functions:
#include "Date.h"
#include <stdbool.h>
enum
{
STARTING_YEAR = 1980, STARTING_WEEKDAY = TUE
};
static const int nonLeapYearDaysPerMonth[12] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static const int leapYearDaysPerMonth[12] =
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static bool IsLeapYear(int year)
{
if (year % 400 == 0)
return true;
if (year % 100 == 0)
return false;
if (year % 4 == 0)
return true;
return false;
}
static int GetDaysInYear(int year)
{
if (IsLeapYear(year))
return 366;
else
return 365;
}
static void FirstSetYearAndDayOfYear(Date * date)
{
int days = date->daysSince1980;
int year = STARTING_YEAR;
int daysInYear = GetDaysInYear(year);
while (days > daysInYear)
{
year++;
days -= daysInYear;
daysInYear = GetDaysInYear(year);
}
date->dayOfYear = days;
date->year = year;
}
static void ThenSetMonthAndDayOfMonth(Date * date)
{
int month = 0;
int days = date->dayOfYear;
const int * daysPerMonth = nonLeapYearDaysPerMonth;
if (IsLeapYear(date->year))
daysPerMonth = leapYearDaysPerMonth;
while (days > daysPerMonth[month])
{
days -= daysPerMonth[month];
month++;
}
date->month = month + 1;
date->dayOfMonth = days;
}
static void FinallySetDayOfWeek(Date * date)
{
date->dayOfWeek = ((date->daysSince1980-1)+STARTING_WEEKDAY)%7;
}
void Date_Init(Date* date, int daysSince1980)
{
date->daysSince1980 = daysSince1980;
FirstSetYearAndDayOfYear(date);
ThenSetMonthAndDayOfMonth(date);
FinallySetDayOfWeek(date);
}
Let’s say you want to check the days per month vectors. You might want to write a test to check the months against the handy poem we use here in the US: Thirty days, has September, April, June and November; all the rest have thirty-one, except for February. It has 28 except in leap year it has 29.
If you started by writing this test…
TEST(Date, sept_has_30_days)
{
LONGS_EQUAL(30, nonLeapYearDaysPerMonth[SEP]);
}
… you get this error:
DateTest.cpp:41: error: 'nonLeapYearDaysPerMonth' was not declared in this scope
Let’s get access to the hidden statics in the test case by including Date.c instead of Date.h in DateTest.cpp. The full test case file looks like this now:
#include "CppUTest/TestHarness.h"
extern "C"
{
#include "Date.c"
}
TEST_GROUP(Date)
{
};
TEST(Date, sept_has_30_days)
{
LONGS_EQUAL(30, nonLeapYearDaysPerMonth[SEP]);
}
With a little refactoring days per month vectors can be checked like this:
#include "CppUTest/TestHarness.h"
extern "C"
{
#include "Date.c"
}
TEST_GROUP(Date)
{
const int * daysPerYearVector;
void setup()
{
daysPerYearVector = nonLeapYearDaysPerMonth;
}
void itsLeapYear()
{
daysPerYearVector = leapYearDaysPerMonth;
}
void CheckNumberOfDaysPerMonth(int month, int days)
{
LONGS_EQUAL(days, daysPerYearVector[month]);
}
void ThirtyDaysHasSeptEtc()
{
CheckNumberOfDaysPerMonth(SEP, 30);
CheckNumberOfDaysPerMonth(APR, 30);
CheckNumberOfDaysPerMonth(JUN, 30);
CheckNumberOfDaysPerMonth(NOV, 30);
CheckNumberOfDaysPerMonth(OCT, 31);
CheckNumberOfDaysPerMonth(DEC, 31);
CheckNumberOfDaysPerMonth(JAN, 31);
CheckNumberOfDaysPerMonth(MAR, 31);
CheckNumberOfDaysPerMonth(MAY, 31);
CheckNumberOfDaysPerMonth(JUL, 31);
CheckNumberOfDaysPerMonth(AUG, 31);
}
void ExceptFebruaryHas(int days)
{
CheckNumberOfDaysPerMonth(FEB, days);
}
};
TEST(Date, non_leap_year_day_per_month_table)
{
ThirtyDaysHasSeptEtc();
ExceptFebruaryHas(28);
}
TEST(Date, leap_year_day_per_month_table)
{
itsLeapYear();
ThirtyDaysHasSeptEtc();
ExceptFebruaryHas(28);
}
You have access to all the hidden stuff, so you can write the test for the static functions: IsLeapYear(), GetDaysInYear(), FirstSetYearAndDayOfYear(), ThenSetMonthAndDayOfMonth(), and FinallySetDayOfWeek().
If Date been an abstract data type, with its data structure hidden in the .c file, the tests would all have access to structure members hidden from the rest of the world.
There is a downside to this approach, which probably does not matter in this case, but could in others. You can only have one test file that can include a given .c file. In the next article we’ll solve that problem.
Have you heard of any interesting leap year bugs? Did you prevent your own?
©2013 James Grenning's Blog. All Rights Reserved.
.