About Andreas Leidig

I am a software developer and respectfully irreverent.

Legacy Software – Why I love working with it!

For years I worked as a consultant and coach. Both on agile methods and coding. I guess I was of some help on a few occasions. At least that is what some customers stated. But in the end I always left them alone. I often felt relief when I left them. But on the other hand it was also like surrender. The software was not finished. Most software is never finished; development goes on and on and on and …

This is probably nothing new to you. Maybe you have similar experiences. But probably you belong to the majority of people in software development: employed developers.

Buried Under Tons of Code

Old code. Untested. Unreadable. Unloved.

Is this what you dreamed of when you started your career? – Probably not. You may have dreamt of creating new shiny software from scratch using great technologies and fancy tools.

But you don’t quit your job. Perhaps you are a masochist? – I don’t think so. There are many reasons to face the challenge working in such an awkward place:

  • Responsibility: You feel responsible for the product. Although it is not the “Big Fun”, it is your job to keep the thing alive and even add more features to it.
  • Challenge: You think it is much harder to work in a situation like yours than to do small projects from scratch. You know that every software will become legacy after a certain age or size.
  • Fear: You are afraid of being the one to produce the nightmare from scratch that you are now working on. For you it is easier to say: “I just clean up other people’s mess!”
  • Hope: You are just staying because you have hope that you will be amongst the chosen few to start the next product from scratch.

In my case, it is a mixture of the first two aspects. In addition I have a strong belief that every legacy product can be changed to the better so that further development will be possible for a long period of time. This work is not funny but deeply satisfying. In our current product everyone in the team is trying his best while working on the huge codebase. And you know what: The software and the code become better each day.

We are all learning. We are all improving ourselves. Maybe some of us will become masters in the end. Who knows…

No IDE: A New Experience

Last week, we were attending a small conference that also included some one-day workshops. I chose to dig a little bit into Node.js. The workshop was held by Golo Roden.

I must admit I’ve had prejudices against JavaScript. And so I chose this topic to gain new insights. Now I know a lot more about JavaScript, have more questions and I really wonder:

Is it possible to conduct large complicated projects without an IDE?

I started developing software more than a decade ago with Smalltalk. For those of you who do not know Smalltalk: There is no separation of the IDE and the product. You don’t even work with files. Have a look yourself: http://www.pharo-project.org/home. – The non-existence of files in the Smalltalk IDE will give you an impression of how I feel with files. About ten years ago I had my first encounter with a different language based on files: Java. – Wow, that was strange at first.

To you this may seem weird. Programming without files? – To me it has been the other way around.

And last Thursday I’ve been attending my first workshop without even an IDE. Only an editor and a command line. – And it worked well for me. At least I was able to type in all the code (or should I say text?) Golo showed on the screen and made only few typos. I was really happy to have a quite sophisticated editor capable of JavaScript: syntax highlighting, able to show brace coherence.

But: I really wonder whether this will scale.

  • How will this work with more than ten files?
  • How will you do refactorings?
  • How can you see relations?

To me one aspect – if not the most important one – of programming is to be able to navigate my code. I definitely do want to see the implementation of a method or function I call. I want to be able to find the potential callers of a function. All this typing is so distracting from the product I’m about to build.

  • I have to know what is already defined to be able to use it.
  • It’s a pain (and slow) to look it up by reading potentially concerned files or documentation.
  • I have to remember the filenames where stuff is defined.
  • I have to track everything inside my head – in detail!

Is this really a professional working style? – What do you think?

 Instead I’d like to be able
  • to see an overview of my code
  • to see the big picture

This is even hard in today’s IDEs. But closer than just an editor.

P.S.: Some googling pointed me to obviously working IDEs for JavaScript with more than syntax highlighting.

How we ran our Legacy Code Retreat

Preparation:

The Content:

The Organization:

We had the great opportunity to use our employer’s facilities. Everything is available there, except for food. So the only thing left to do was to get some food. We have chosen our local bakery for breakfast, got fruit at the supermarket and hired a caterer for lunch.
What we learned: Don’t buy too much food. – We did. For the bakery we discovered that three pieces per participant are sufficient, and two pieces of fruit. We made an effort to offer food of excellent quality, and many participants rewarded this with small remarks about how much they enjoyed it.
We had coffee prepared for every break. During the setting up, we could count on the earlycomers’ aid in carrying stuff around. It is our general experience that participants of those kinds of events are always very helpful.

The iterations:

In gerenal the format worked well. The first iteration served as warm-up. We stretched the second iteration to another 45 minutes to give the participants the chance to play around more. The restriction-based iterations have been sort of confusing for some of the participants. Their feedback indicates that the codebase is not very suitable for applying the proposed patterns. We should have given a little bit more guidance there and clearly explain that the restrictions are not exercises to be completed but rather propositions to serve as a mental guide for the modifications to be done and to play around with.

A Great Surprise:

The biggest surprise we’ve experienced was that one of the participants (Hayati Ayguen) came up with doing the golden master and the automated comparison via a bash-script (see below)! Great!

Summary:

This won’t be the last legacy code retreat in Germany. Be prepared to see more of them in the future. Feel free to contact us for help when you want to run your own.

Bash Scripts and related Code:

createGoldenMaster.sh

#!/bin/bash

for s in `seq 1 $1`; do
  ./a.out $s >erg$s
done

compareWithGoldenMaster.sh

#!/bin/bash

totalerrs=0
for s in `seq 1 10`; do
  ./a.out $s >current
  errs=`diff erg$s current |wc -l`
  echo "vergleich $s hat " $errs "unterschiede"
  totalerrs=$[ $totalerrs + $errs ]
done

if [ $totalerrs -eq 0 ]; then
  echo all OK.
else 
  echo ERROR!
fi

GameRunner.cpp

#include <stdlib.h>
#include "Game.h"

static bool notAWinner;

int main( int argc, char * argv[] )
{
    if ( argc != 2 )
    {
        cerr << "usage: " << argv[0] << " <seed>" << endl
             << "  seed should integer " << endl;
        return 10;
    }
    int seed = atoi( argv[1] );
    cout << "seed is " << seed << endl;
    srand( seed );

	Game aGame;

	aGame.add("Chet");
	aGame.add("Pat");
	aGame.add("Sue");

	do
	{
		aGame.roll(rand() % 5 + 1);

		if (rand() % 9 == 7)
		{
			notAWinner = aGame.wrongAnswer();
		}
		else
		{
			notAWinner = aGame.wasCorrectlyAnswered();
		}
	} while (notAWinner);

}

The Quality Of Software Development Cannot Be Measured

I often read about the cool sides of agile and lean and other process frameworks or methodologies: you can measure where you are and how good you are doing what you want to do.

Concepts like Velocity or Lead Time help you predict what you will probably be able to achieve in the near future. But this is only the easy part: pure arithmetics.

Stop dealing with the easy, focus the difficult.

Did I say easy? – Yes, and I mean it. The above concepts (velocity, lead time) are easy as soon as you are able to measure them. You need a few requirements like: definition of done, being able to track tasks, estimations, discipline. Given you have all the requirements you defined, deducting the velocity (or lead time) is straightforward, if not to say trivial.

So please stop talking or writing of these concepts as some great discovery! – We all know that one of the hard parts is to fulfill those requirements.

If you are in a situation where the requirements can easily be fulfilled, chapeau! – You are one of the lucky few whose environment is in a great condition.

Now, what is the hard part? – It’s the quality.

Quality is hard.

How can you know if your quality is right?

Can you give me a sound definition of what quality means for you?

Can you even give me a definition of quality that you share with a few others?

Can you give me a definition that you can share with your team, with your organization?

There should be a consensus on these definitions that is supported by everyone who is concerned with the outcomes. And then you have the even greater dilemma: How can you prove that a certain result matches your definition of quality?

If you measure quality it becomes – by definition – a quantity!

Quality measures are only indicators.

Measures always face the problem that – once defined – people try to match the measure, not the intention behind it. Wouldn’t it be great to work together with a shared intention of quality instead of simply fulfilling metrics and measures?

If you have few/many bugs this can mean you have good/bad software. It need not be so.

If you are able to build new features quickly/slowly this can mean that the inner quality of your product is ok/not ok.

Metrics and measures are useful as indicators. I find them much more useful as indicators for bad quality than for good quality. Never be too satisfied when the indicators show everything is fine, but really be worried if they indicate a potential problem. – But this is just based on my experience. I’ve just never experienced a project with bad indicators not having serious problems sooner or later, but I’ve seen the opposite. This goes along the lines of watermelon reporting, which you may have experienced, too.

Quality is not objective.

I remember when Apple released their first iPod shuffle. A German consumer review organization (Stiftung Warentest) downgraded the device because it didn’t have a display. It simply didn’t fit their quality criteria. Nowadays they downgrade Apple devices because you need proprietary software to fill them with music. This can be a turn-off for some people but I guess it is not for many of those who own one.

As you can see by these examples – there are many more, just think about it – it is all about meeting expectations: The expectations of the people that define the measures. If these expectations are unmet, they regard the quality as being poor and vice versa.

And in software development? – Do we really have “hard” measures for software quality? – Do we even agree on very trivial topics? – Just ask a few developers how many LOCs per method are ok and you’ll probably end up in a joyful discussion. – We don’t even have a standard definition of LOCs!

Who can define measures for software quality? Insiders of the project rather than outsiders? There is always a trade-off, but I would always prefer the trustful outsider over the insider. Especially in legacy products it’s been the insiders that have produced the software as it now is. Especially if the system is a mess right now, would you trust them to give you a suitable advice? They see more resistance than outsiders do and they are part of the system, which means they are part of the resistance.

Back up quality by simple measures.

The struggle we are in should be the struggle for quality. Establish few but critical measures and teach your mates the intention behind them. In the domains I usually crawl around these may include:

  • Method length (combined with e.g. cyclomatic complexity)
  • Class size (number of methods)
  • Module dependencies (especially: no circular dependencies)

Why those? – They give an early indication of when you are in trouble to lose control of your code. But if you only strive for superficially fulfilling them through technical changes, it will result in a shattered system and the result on quality will be minimal. Finally, trust your experience or a friendly stranger with more experience than you have right now to judge if the code feels alright. If you can’t trust your feelings, start working on improving your intuition. And please don’t contaminate your intuition with knowledge. Intuition means you are able to judge the quality of a given piece of software before you can tell why. The explanation of your judgement is based on knowledge.

So please don’t mix quality and quantity. If you really want quality, stop treating it as numbers!

Does this sound obvious? – Then take your time and think about it.

The Schizophrenia of Object-Orientation

Why Object-Orientation is More than One Paradigm

Until recently, I believed that object-orientation is a paradigm that contrasts e.g. the functional or the procedural paradigm. I imagined that everybody who worked in an object-oriented fashion had more or less the same ideas, beliefs and views. On the other hand, I often discovered that I found myself misunderstood in the community of object-oriented developers, and that I did not relate to what they were talking about.

Then, I heard Richard P. Gabriel (at: 33:30) say (roughly): “When there is a shift in paradigms it is impossible for either side to understand the other. And there is a shift in paradigms: from Object Oriented Systems to Object Oriented Languages.” – This resonated deeply inside me. Both sides use the same words and idioms and yet they talk about completely different things. They talk and talk and …

…they don’t even realize that they don’t understand each other. Just sometimes they notice that something isn’t working.

To give you a picture of the situation, I guess it’s easiest to show you how Nicole and I approach the topic. We experience this difference very often, and I believe I am representing the “systems” side while she stands for the “language” side. We usually call this the “dynamic” and the “static” view on programming. In this article, we try to demonstrate each of the extreme positions.

Let’s start with a look at my perspective.

Software is Composed of Small Interacting Parts

Andreas: To me, software is a “living thing composed of small parts interacting with each other”.

If I code a class, I look at it as a small program, a self-containing entity. I want the class to show clearly how its instances (the objects) can interact with other objects and I want the objects to interact with others. I don’t focus on types or state. In fact, after more than 10 years of Java I am still annoyed by the static typing Java forces me to declare. When designing properties I am method centered, not field centered. To me a field is a necessity, not a value in itself.

But this all is only building the parts. A software that is not running is just dead code, not software. Push the “run” button, man, execute it! – As soon as the program starts to execute, its parts start interconnecting and interacting. And that is the real game! Messages sent from here to there, bytes flowing at incredible speed. This is what makes it fascinating to me. – All the coding is only a really primitive way to prepare the stage for the actors.

What does it look like on the other side?

The Beauty of Software Lies in its Construction

Nicole: 
My main fascination in software development comes from the theoretical underpinnings, especially type theoretical ones. They convey a sense of truth, truthfulness, reliability and provability, which is what I am striving for.

The programming language, especially its syntax together with its underlying concepts, is very important for me because it determines how I can express myself. It determines not only what I can state, but also in which way I can state it: Does it bring forward elegant and crisp formulations, or is it clumsy and talkative? What does it allow, what does it restrict? How many errors does it already uncover at compile time?

When actually coding, I am fascinated by finding a balance between shaping the code to be simple and understandable, shaping algorithms to be elegant and efficient, shaping objects to be encapsulated and self-contained, and integrating all this smoothly into the existing codebase.

But when it comes to trying out the code by running it, my first thought is “Why? I’ve already created this beautiful code, isn’t that enough?” Until now, it has not become second nature to me that I need to run my code.

In fact, actually running my program sometimes gives me the creeps because suddenly tons of strange things happen. That’s why I try to control many aspects of the code statically: Errors that can be caught at compile-time need not be caught by running the code… And no, I am not talking of Java’s lame attempts of static typing here! I have something more powerful in mind, something that is e.g. offered in functional languages like Haskell.

Diving Deeper Into Words

Let’s have a look at some well-known words and try to find out what their meaning is in the eyes of Nicole and Andreas:

Interaction

Andreas: Interaction is the sending of messages from one object (or group of objects / module) to another.

Nicole: What Andreas describes is merely the taking place of the interaction at runtime. In my opinion, this cannot happen unless the interaction has been defined statically by how the code is interconnected, e.g. which class possesses a reference to an instance of which other class, which method implements the invocation of some other method on some reference and so on.
Therefore, the static definition of interaction is a prerequisite for its taking place. Interestingly, different static definitions can lead to the same runtime behavior.

Structure

Andreas: Structure ist the topology of the object network, looked at from a static point of view. Structure is the basis for interaction. This concept is closely related to the static code, but relevant at runtime.

Furthermore, structure evolves from the layout of code units. It is very important where your code is located with respect to classes, packages or modules (in the sense of e.g. an OSGi-bundle or Eclipse project). If your code is healthy there will be identifiable modules. Structure defines which module accommodates which code. Structure also describes the dependencies of the modules.

Finally, structure defines the possible interactions at runtime.

Nicole: If I hear the word “structure” in general, I mainly think of the structure of the type system, namely how classes and interfaces are related to each other hierarchically. I do not regard as “structure” the connections between classes that are established via composition or aggregation. Therefore, structure and interaction are orthogonal concepts for me.

If some context is given, it may change my understanding of the word “structure”. If we e.g. talk about “package structure”, my understanding of “structure” gets much closer to Andreas’ description of code modules.

System

Andreas: A system consists of the interactions that take place on the basis of a structure. In a system, I can concentrate on static and/or dynamic aspects of a given (sub-)system, namely by focusing on a certain area of the structure or on certain interactions.

For example: A very small system is defined by a unit-test. The term “system under test” shows that very clearly. The smallest possible unit test describes also the smallest definable system in your code.

Nicole: The expression “system” is quite alien for me. When I think about its meaning, I get to something like “application”, where the application represents the “overall system”. An application can interact with other applications, this way forming a larger system. A part of an application, on the other hand, like a class in a unit-test, does not represent a system in itself.

So what?

It took us several weeks to write this article because we had so many long and intensive discussions around the topic. We’ve learned a lot about each other and ourselves. In our daily work it helps us to know that we – and probably our co-workers as well – have biased views of reality and especially what these views are.

This diversity of views greatly enhances our lives. It is our choice to see it this way.

Now find out about yourself. Ask yourself:

  • What do you think of this duality of object-orientation?
  • Which of the two views is closer to your own view of the world?

And then discuss with others!