Tag Archives: legacy-code

7 Rules on Code Readability

Posted on by

What makes good code? Many things but whatever the qualities are, readability is a cornerstone.  If you can’t read the code, you can’t fix it. So how do you write readable code? I’ll give you my view but it’s like books, what I find enjoyable may be different from you.

read more »

Bragging: 100% coverage, specification by example and pair programming

Posted on by

Yesterday we ended our second two-week sprint and on the demo, besides showing the system, we could do some bragging about test coverage using our Sonar dashboard.  We also could show Fitnesse tests at system level that implements the specification by example technique, or like some say, executable requirements.

read more »

The Solution to Technical Debt

Posted on by

(related article: Good and Bad Technical Debt – and how TDD helps)
(Translations: Russian)

Are you in a software development team, trying to be agile? Next time the team gets together, ask:

How do we feel about the quality of our code?

Everyone rates it on a scale of 1-5, where 5 means “It’s great, I’m proud of it!” and 1 means “Total crap”. Compare. If you see mostly 4s and 5s, and nothing under 3, then never mind the rest of this article.

If you see great variation, like some 5s and some 1s, then you need to explore this. Are the different ratings for different parts of the code? If so, why is the quality so different? Are the different ratings for the same code? If so, what do the different individuals actually mean by quality?

Most likely, however, you will see a bunch of 2s or worse, and very few 4s and 5s. The term for this is Technical Debt, although for the purpose of this article I’ll simply call it Crappy Code.

Congratulations, you have just revealed a serious problem! You have even quantified it. And it took you only a minute. Anyone can do this, you don’t have to be Agile Coach or Scrum Master. Go ahead, make it crystal clear – graph the results on a whiteboard, put it up on the wall. Visualizing a problem is a big step towards solving it!

Don’t worry, you aren’t alone, this is a very common problem. <rant>However, it’s also a very stupid, unnecessary problem so I’m baffled by why it is so common.</rant>

Now you need to ask yourselves some tough questions.

read more »

Code archeology 101: Custom Exception Hierarchies

Posted on by

After having worked with various legacy codebases one discovers certain recurring traits and patterns. The topic of today is the Custom Exception Hierarchy encountered in Java legacy code. This phenomenon is rather Java-specific because of that language’s checked exceptions.

So what is a Custom Exception Hierarchy? It’s an exception hierarchy, with some strangely named exception at its root, present throughout the entire codebase and used everywhere. The author(s) of such hierarchy obviously felt that exceptions like IllegalStateException or IllegalArgumentException, or the like weren’t sufficient for the sophisticated needs of their application, so they came up with a better suited hierarchy of checked exceptions.

read more »

Write Legacy Code and Secure Your Job

Posted on by

In this day and age with unstable economics, constant change in how to work with software, new languages and databases popping up from nowhere, it is important to cement yourself into your position at work.

Follow this guide and be sure of never being fired, no matter what. read more »

TDD Illustrated

Posted on by

I am planning an introductory course on TDD. In that process I have been thinking about how to convey the productivity gain with TDD.

Being a visual person, I had an idea that would illustrate this in a few pictures. Here they are for your scrutiny and enjoyment!

The main idea is to illustrate how effort over time is affected when using TDD in contrast to not writing tests at all.

We will start off with a new component, respond to feature request and then finally attack some legacy code.

Phase 1: A New Component

Let’s first look at the creating the component without writing any tests at all. The illustration below shows how you create your first version. The yellow rectangle with an “I” is your perceived progress.

The first time you say “done” and deliver to test, the component comes back with a bug report, illustrated as a red flash. So you go “oops”. As easy as apple pie, you fix that and deliver again only to find that the fixing of the first bug introduced a new, second bug. Oops, again.

Finally, on the third attempt, you succeed and the component is put in production.

Phase 1 non TDD

Now let’s look at the TDD way and how that comes out. As you write tests, it will take slightly longer time to reach “done”. Not as much as it feels, though, since in the other case the perceived time becomes shorter as you sit there scratching your head. When you do TDD, you tend to spend more time typing and the perceived time will be somewhat longer.

The tests are illustrated as rectangles with a “T” in them. As you see, they grow with the implementation.

Well, in this scenario, you eventually reach “done” but the component returns from test anyway since you made the same mistake. TDD is not fool-proof. However, the interesting thing about this, is that you don’t introduce a new bug. The test suite that you have written, saves you.

Phase 1 TDD

In summary, the time to the first “done” was longer with the TDD way, but the time to pass the test was shorter.

Phase 2: Next Version

We now follow the life of our imaginary component as a request for a new feature comes in. We still compare the two ways of doing development.

If we don’t have any tests, the scenario probably will be as illustrated here. The new feature puts us in somewhat more trouble than when wrote the first version. The reason is that the code is larger so the risk of introducing bugs gets higher. As you see, we have more attempts at delivering this time.

The code has become more difficult to maintain. We could say it has started rotting, if you see the analogy.

Phase 2 non TDD

Looking at the TDD way, we find that we have our tests as a safety net for making modifications.

All we do is add some more tests to the suite as we go along and create the new feature for our software.

With the test suite backing us up, the new feature is introduced as easily as when we were coding the component from scratch!

Phase 2 TDD

Phase 3: The Legacy Update

TDD would not be particularly useful if it only applied when you started from scratch. Almost 100 percent of our time as developers is spent with legacy code in some way.

Let us assume that you have been given the task to update a software component that has no tests, what do you do?

As above, there are two alternatives and we will look at them both.

With no tests in place all we see is a big pile of … code that we need to change somehow. We read the code, make assumptions about how it works and make the change.

It is a small change so it only takes one trip back from test before going into production. Phew!

Phase 3 non TDD

Now, doing it the TDD way, you start with writing tests that express your assumptions about how the component works. These tests will fail initially, which is enlightening and they will not cover all of the code, which is not necessary. However, from there on, we add tests and implement the change in a more confident manner.

Since this is a small change it goes through testing to production on the first try. The testers call you and ask you what you have done, they can’t find any bugs! Lean back in your chair and smile, it is a good day in legacy land.

Phase 3 TDD

The legacy code is not as horrible anymore as you now have more test coverage when doing the next change. Also, your learning tests in the beginning gave you insights that you wouldn’t have had if you did it the old way.

There are of course other values of TDD and there are some obstacles that you have to learn to overcome. Hopefully this post gave you some motivation to try!

Understanding a System

Posted on by

Understanding a system comes in pieces but each piece can take longer or shorter time depending on the circumstances.

What does it mean, then, to understand a system?

Well, if you don’t understand it and introduce a change, you risk going wrong. The code you wrote may seem to work, but …

 – You put the change in the wrong place so everyone else is confused.
 – Your unit tests ran fine but some other part of the code wasn’t under test and stopped working promptly.
 – Your change introduced a dependency to another component and we now have a circular dependency.
– The system can’t be deployed because there was a distributed interface which you thought were local.
– You didn’t follow the policies of error handling, logging or security. So now there is a security breach which is not caught by error handling and the log is nowhere.

So that’s the "why" of understanding. The "how" has some answers you probably know already.

  1. RTFC: Read The Fine Code. Yeah, that’s what we do. All the time. Don’t tell me to do something I do all the time. Thank You.
  2. Ask a Guru. There are gurus? No, guru means teacher which means the opposite of withholding information. That’s what some do, to be in need. Baaad. But you have to deal with it more often that you wish.
  3. Write unit tests until you get it. No harm in that if you do it as you go.

All these have the drawback of looking at the details without seeing the big picture. It reminds me of when I was 13 and learned the city by areas around the subway stations. After a while the areas got big enough to connect to each other and I could get the overall picture without looking at the map.

What is the big picture then? Well, it is the architecture of the system. There is no mystery about it, no magic patterns put down by a long gone super genius, no outdated ideas, just plain descriptions of how the system is designed.

Like a house is understood from blueprints of the outside, the disposition of rooms, the plumbing, etc, a system is understood from different views. There is a standard that will tell you that there are views but leave it to the author to decide which views.

The one I have seen most of is Kruchten’s 4+1, published in IEEE Software. You should be familiar with it but I guess you are not. I have a course on system architecture and I am still surprised how few of the students that have ever seen a document describing a system’s architecture, despite several years in the business.

The crash course is to study the Wikipedia article linked above. Start with the logical view and the physical (deployment) view, those are easiest to grasp.

But there is more to it. Remember that I said something about going wrong with logging, error handling and security? Those are principles of the design and impacts the system almost everywhere.

So to understand a system, I think you need the details and the views and principles of the big picture.

Oh, was the Wikipedia article too long? Here is a cheat sheet:

  • logical view: how components of the system relates to each other logically.
  • physical view: the servers and firewalls and stuff like that.
  • process view: how processes and threads are related.
  • development view: where the compiled code is package, e.g. a war.
  • scenario view: important functions of the system.