David Tanzer

Legacy Code: The Mikado Method

2018-05-21

At the We Are Developers World Congress 2018, I gave a talk about how to deal with legacy code using the Mikado Method. So, here is the concrete example I gave in my talk.

The Mikado Method

The Mikado Method gives us a way to change legacy code in small, safe steps. Read the linked post for a detailed description. To summarize:

  1. Write down your current goal
  2. Try to reach that goal directly
  3. If you fail
    1. Write down everything that prevents you from reaching your current goal as a sub-goal
    2. Revert your changes
    3. For each sub-goal, repeat 1
  4. If you succeed
    1. Commit your changes
    2. Repeat with the next goal

This gives you a tree where all the leaves are immediately solvable, and when you solved them, you can try and solve the goals higher up in the tree. You might discover more problems that prevent you from reaching your goal - Then you just add another branch to the tree.

In the end, you will - hopefully - have solved your original goal. And you will have done so in small, safe-to-fail steps.

The Legacy Code

I used the Baby Steps Timer as the starting point for this exercise. It’s a pretty nasty piece of code where every part of the code is coupled to something else in the code. So, whenever you try to change something, something else breaks.

Before I started with the mikado method, I wrote some characterization tests (maybe I’ll write about it in a future blog post). They are still a little bit flaky - they sometimes fail without a reason - because of all the threading involved.

But it is absolutely crucial to have them: With the mikado method, we must have a way to quickly check whether our change broke something. And the compiler is not enough for that.

Move Timer Thread to Own File

This commit on the branch characterization-tests is where I started with the actual refactoring. I have at least some tests in place now. So, I created a new branch called mikado-method and I also wrote down my main goal:

Note with main mikado goal

…and tried to move the TimerThread out of the main class, using the refactoring tools. This resulted in code that does not compile:

Source code with errors: TimerThread

Now, let me repeat that this - the code not compiling - is totally expected: With the mikado method, you just try to reach the goal in the most straight-forward way. You expect things to break. But you do this to identify your sub-goals. And then, you revert all your changes, back to the last working version.

Now I was supposed to write down everything that prevents me from achieving my goal. But in such a situation, I do not write down every compiler error. I write down some high-level design changes that will help me reach my goal. In this case, the compiler errrors belong to two categories: Stuff the timer needs for their own logic to work and stuff the timer needs for rendering the result.

Note with main mikado goal and two sub-goals

Don’t forget to write those sub-goals down. It is not enough to just identify them and hope you will remember. I prefer paper for writing things like that down, but a simple text file or a mind mapping tool will do too.

Timer Logic

This was a quick one… I moved the three variables that are related to the business logic to the timer thread inner class:

private static final class TimerThread extends Thread {
    private static boolean timerRunning;
    private static long currentCycleStartTime;
    private static String lastRemainingTime;

And in the rest of the code, I access them through the TimerThread class:

} else if("command://stop".equals(e.getDescription())) {
    TimerThread.timerRunning = false;
    timerFrame.setAlwaysOnTop(false);

Rendering Logic

I moved all the code related to rendering to a TimerRenderer class.

public static class TimerRenderer {
    static JTextPane timerPane;
    private static String bodyBackgroundColor = BACKGROUND_COLOR_NEUTRAL;
    private static JFrame timerFrame;

    //...

    public static String getRemainingTimeCaption(final long elapsedTime) {
        //...
    }

    private static String createTimerHtml(final String timerText, final String bodyColor, final boolean running) {
        //...
    }
}

I also had to create an interface that the timer thread can use:

public static class TimerRenderer {
    //...
    public static String getBodyBackgroundColor() {
        return bodyBackgroundColor;
    }
    public static void update(String remainingTime, String bodyBackgroundColor, boolean timerRunning) {
        TimerRenderer.bodyBackgroundColor = bodyBackgroundColor;
        timerPane.setText(createTimerHtml(remainingTime, bodyBackgroundColor, true));
        timerFrame.repaint();
    }
    //...
}

The timer thread now uses only this interface when updating the timer:

while(timerRunning) {
    long elapsedTime = wallclock.currentTimeMillis() - currentCycleStartTime;

    //...
    String bodyBackgroundColor = timerRenderer.getBodyBackgroundColor();
    //...
    
    String remainingTime = timerRenderer.getRemainingTimeCaption(elapsedTime);
    if(!remainingTime.equals(lastRemainingTime)) {
        //...
    }
    timerRenderer.update(remainingTime, bodyBackgroundColor, true);
    //...
}

Note: This change introduces a subtle defect. Apparently, I forgot one characterization test that would have cought it. It is very hard to know which characterization tests to write, and whether you have enough. But you still should write them!

Can you spot the defect?

More Problems

Now my two original sub-goals were complete. So, I tried to move the TimerThread to its own class again. But I noticed two more problems:

Note with main mikado goal and now with four sub-goals

I must pass the timer renderer to the timer thread as a constructor parameter - otherwise, the renderer cannot access it anymore, once it lives in a different file.

public TimerThread(BabystepsTimer.TimerRenderer timerRenderer) {
    this.timerRenderer = timerRenderer;
}

And I also created an interface to stop and to reset the timer, so that the main class does not have to access private variables of the timer thread anymore:

public static void stopTimer() {
    timerRunning = false;
}

public static void resetTimer(long newTime) {
    currentCycleStartTime = newTime;
}

I also had to change the access of one constant from private to public.

Done!

And now it was finally possible: I was able to move the TimerThread out of the main class, into its own file.

Note with main mikado goal, all sub-goals done

You can see the end result in the mikado-method branch of the babysteps-timer repository.

Maybe I could also have done this by doing a “refactor by compiler error”: Just do something, and then fix all the errors, do more, fix more compiler errors.

But this would definitely have been harder. The nice thing about the mikado method is that it is very safe. The code always compiles. You can always run the tests.

And when you do something that does not work right out of the box, you undo and solve the problems first. This allows you to work in small, safe steps, and to identify the steps as you go.

If you have a lot of legacy code, you might also experience some “Agile Anti-Patterns”. So, go get my book “Quick Glance At: Agile Anti-Patterns” ;) And if you liked this post, you might be interested in my services: I help teams to get better at developing high-quality software. Just contact me!

Related posts in the category “Legacy Code”:

Overcoming my Shyness - Intro

2018-05-10

I enter the room. I’m about to give a talk at a conference.
They gave me the biggest room of the venue.
Oh my god, I did not realize how big it is.
I hope it won’t be full.
Oh my god, I hope it won’t look empty!
I go to the audio engineer. Getting my microphone, testing my laptop.
I wait somewhere near the back. My heart starts racing.
Slowly, the room is filling. So many people.
Why did I submit my talk to this conference again?
5 minutes to go. I know that, because I am checking my watch every 20 seconds.
I ask the audio engineer the time. 4:40, then it starts.
I check if my hands are sweating. They are dry. Why are they dry?
I really don’t like to be in the same room with so many people.
40 seconds to go. I can’t remember what I wanted to talk about.
20 seconds. Do my slides even make sense? I should have re-arranged them.
0 seconds. OH MY GOD, I have to give my talk NOW.

I put on a smile. I walk up the stage.
“Good afternoon, everyone! So many came here - awesome! I hope your lunch was good. Today I will talk about…”

Two weeks ago, I gave a talk at a conference. This is roughly how I felt.

Had you asked me ~20 years ago, when I started university, if I could give a talk in front of 300 or more people, I would have said: “No. Never. Ever. I just cannot do that. I am too shy, I would die on the stage.”

Some of the things I am doing, like talking and networking at conferences, are still not easy to me. Even though I do them all the time. Even after many, many years. So, what has changed? Why am I doing them?

When WeAreDevelopers interviewed me, one of their questions (and my answer) was:

WeAreDevs: What is one of those things you wish you knew when you started out developing?

David: That becoming a good software developer is all about being good at communicating with other developers – and especially with “non-technical” people.

I think that communicating and networking are key to having a great career in software development. We must learn to talk to strangers. Talk to people from completely different backgrounds - Understand their background, adjust the communication. Be able to present ideas in front of groups. Quickly teach people a single thing about a topic.

Those are important, even if you never go to a conference. You also need those skills when joining a new team or when you want to become a technical lead, software architect or some other role that involves a lot of communication.

And so I am trying to get better at them. I am now at a point where, most of the time, many of those things are not scary anymore. But they are still exhausting. And I am not there yet - There is still much more to learn.

I am writing this down to clear my thoughts about it. And to get your feedback. And maybe what I wrote can help some others by showing them that this stuff is not easy for me, and that I (and others), too, are constantly working on that.

I want to write more about that, later. So, here are all the blog posts from this series:

If you have any questions, if you need help or advice or just somebody to talk to, feel free to ping me. I am sometimes quite busy, but I will help you if I can. DM me on Twitter or send me an email to business@davidtanzer.net.

Also, I want to teach a short (2-hour) workshop about “speaking at conferences” at SoCraTes Austria. Participants will practice

  • Finding conferences to speak at
  • Finding and refining a topic
  • Writing and refining abstracts
  • Preparing to create slides
  • Communicating with the conference
  • Courage and Self-Confidence

If this sounds interesting to you, come to SoCraTes Austria. And if you cannot make it, maybe I could teach it at a meetup or user group near you? Email me - business@davidtanzer.net - so we can talk about the details.

Immutable.js and Redux / React

2018-05-02

In the last installment of this series, I wrote about the basics of immutable.js. Today, I want to write about how to use it together with Redux.

I wrote a very small application with React, Redux and immutable.js: It just displays two red squares and some lines to the corners of each square. And you can drag and drop the corners with your mouse.

Simple React / Redux App

This functionality may sound simplistic. But it has some react components that operate on common data that can change (both Link and Square need the location of a Square), and so it can potentially benefit from Redux.

You can find the full source code here. For now I am showing you the code from the tag simple-redux-immutable.

Reducers and Immutable

There are two things you have to do to make your reducer work with an immutable data structure:

Make the initial state an immutable object

import { fromJS } from 'immutable';

const initialState = fromJS({
    squares: [
        { x: 316, y: 281, },
        //...
    ],
    edges: [
        { x: 0,    y: 0,   squareX: 0,  squareY: 0,  },
        //...
    ],
});

export function reducer(state = initialState, action) {
    //...
    return state;
}

src/Reducer.js

This application draws squares and lines between them. The data required to do so is stored in an immutable map with the keys squares and edges. Each of those keys contains an immutable list of Maps, that in turn contain the data.

Instead of creating a new JavaScript object, perform an immutable update

export function reducer(state = initialState, action) {
    switch(action.type) {
        case 'SQUARE_MOVED':
            return state
                .updateIn(['squares', action.id, 'x'], x => x+action.dx)
                .updateIn(['squares', action.id, 'y'], y => y+action.dy);
        }
    return state;
}

src/Reducer.js

When the user drags a square with their mouse (action SQUARE_MOVED), the reducer updates the x and y coordinate of that square.

mapStateToProps

In mapStateToProps, I get the data required for rendering the components from the redux store. Either as simple JavaScript numbers:

function mapStateToProps(state, ownProps) {
    return {
        x: state.getIn(['squares', ownProps.id, 'x']),
        y: state.getIn(['squares', ownProps.id, 'y']),
    };
}

src/Square.js

Where ID is provided by the parent component (src/DrawingArea.js):

<SquareContainer id={0} />

Or as an immutable data structure, that the component itself will pick further apart:

function mapStateToProps(state, ownProps) {
    return {
        square: state.getIn(['squares', ownProps.toSquare]),
        edge: state.getIn(['edges', ownProps.fromEdge]),
    }
}

src/Link.js

Where toSquare and fromEdge are again provided by the parent component (src/DrawingArea.js):

<LinkContainer fromEdge={0} toSquare={0} />

PureComponent

With redux, all the components that actually render stuff - Your Presentational Components - can be pure components (at least when you stick to the rules of Redux):

export class Square extends React.PureComponent {
    //...
}

src/Square.js

This may or may not be faster than having “normal” react components. What is more important to me is: It serves as a reminder to keep this component side-effect-free.

And to not implement shouldComponentUpdate: A presentational component that gets its data from redux should:

  • Not have any internal state
  • Only get the data it absolutely requires in its props, and thus:
  • Always re-render when the props change

Rendering

When the component only gets plain values in its props (like the numbers x and y for Square), then render looks as if there would be no immutable.js at all. But when the component gets immutable data structures through its props, like Link, it can use them in its render function (and elsewhere):

render() {
    const fromX = this.props.edge.get('x');
    const fromY = this.props.edge.get('y');

    const toX = this.props.square.get('x') + this.props.edge.get('squareX');
    const toY = this.props.square.get('y') + this.props.edge.get('squareY');

    return (
        <path d={'M '+fromX+' '+fromY+' L '+toX+' '+toY+' z'} className="link" />
    );
}

src/Link.js

Updates / Actions

On a DOM event, the component creates an action. There is no difference to not using immutable.js here. In this case, to handle mouse events correctly, the code first gets a ref to the DOM node and then installs the listener in componentDidMount:

<rect x={this.props.x} y={this.props.y} 
      width={50} height={50} className="square" 
      ref={e => this.rect=e} />

src/Square.js

componentDidMount() {
    this.rect.addEventListener('mousedown', this._mousedown_bound);
}

src/Square.js

Most of the code in the mouse listeners is for handling dragging with the mouse in a way that it does not jitter. But on mouse move, the component also calls an action creator:

_mousemove(e) {
    //...
    this.props.squareMoved(this.props.id, e.movementX, e.movementY);
}

src/Square.js

Which only packs its three arguments into an action object of type SQUARE_MOVED. When the reducer handles this action, it must use immutable updates. Note how it calls the second updateIn on the result of the first and how it returns the result of that:

case 'SQUARE_MOVED':
    return state
        .updateIn(['squares', action.id, 'x'], x => x+action.dx)
        .updateIn(['squares', action.id, 'y'], y => y+action.dy);
}

src/Reducer.js

CombineReducers

Redux only knows one reducer. But being forced to write a single, huge reducer would lead to unmanagable code. Hence you should split your reducer code and combine the smaller reducers with combineReducer.

And so, now I want to show you how you can structure your reducers when using immutable.js. Switch to the tag immutable-combine-reducers to see the source code of this version.

The only difference here is that you have to use combineReducers from redux-immutable instead of the default one:

import { combineReducers } from 'redux-immutable';

export const reducer = combineReducers({
    squares: squaresReducer,
    edges: edgesReducer,
});

const edgesInitialState = fromJS([
    { x: 0,    y: 0,   squareX: 0,  squareY: 0,  },
    //...
]);

function edgesReducer(state = edgesInitialState, action) {
    return state
}

const squaresInitialState = fromJS([
    { x: 316, y: 281, },
    //...
]);

function squaresReducer(state = squaresInitialState, action) {
    switch(action.type) {
        case 'SQUARE_MOVED':
            return state
                .updateIn([action.id, 'x'], x => x+action.dx)
                .updateIn([action.id, 'y'], y => y+action.dy);
        }
    return state;
}

src/Reducer.js

To Recap…

And that’s it: To use immutable.js within your React / Redux app, you have to:

  • Update your reducer’s initial state to immutable data structures
  • Use the immutable data structures in your mapStateToProps and possibly within your presentational components
  • Combine your reducers with a different function

You should also make all your presentational components PureComponents.

And then you will automatically get the advantages of immutable.js: It ensures by default that you have immutable state in your redux store and it does updates in a very efficient way.

Immutable.js - Basics

2018-04-20

This post is part of a series about React, Redux, Immutable.js and Flow

Two of the three Redux principles are “State is read-only” and “Changes are made with pure functions”. When changing the read-only state, you are not allowed to mutate the existing object: You are supposed to create a new object.

But this new object can share the parts that have not changed with the previous state.

Writing that code to update the read-only state is definitely possible with just plain JavaScript objects and arrays. But it is easier when you have immutable data structures. In this aritcle, I want to write about the basics of immutable data structures. So that, in the next post, I can show you how to use them with Redux.

Immutable.js

immutable.js gives you several immutable data structures: Map, List, Set, Record and more. Those data structures cannot be changed once created.

Convert from / to JavaScript

You can create those data structures with their constructors, which also accept JavaScript objects and arrays to initialize the data structure from.

import { Map, List } from 'immutable'

const emptyMap =  new Map();
const emptyList = new List();
const initializedMap =  Map({ x: 1, y: 2});
const initializedList = List([1, 2, 3]);

If you want to deeply convert some JavaScript data structure to nested immutable data structures, you can use fromJS. You can convert back to plain JavaScript data using toJS.

import { fromJS } from 'immutable'
const originalJS = {
    x: 'a',
    y: 'b',
    z: [1, 2, 3]
};
const immutable = fromJS(originalJS);
const convertedBack = immutable.toJS();

But, when working with immutable.js, you will rarely ever convert from or to JavaScript. Most of the time, you should work with the immutable data structures themselves (getting values and performing immutable updates). Only when you pass data from or to the outside of your own system, you would convert from JavaScript and back.

Query Functions

You can use get to get some value from the immutable data structure, and getIn to get a deeply nested value. Using the immutable object from above, this is how it works:

const a = immutable.get('x');        //returns 'a'
const b = immutable.getIn(['z', 1]); //returns 2

You can also run other functions that you would expect to work on collections, like forEach, filter, map, reduce and others.

Immutable Updates

OK, and now comes the interesting part. You can update those immutable data structures, but that will not modify them. Whenever you “update” one of these data structures, you get back a new object, and you can think of it as a complete copy of the old one, with the updated value modified (this is not how it works internally, see below).

const im = fromJS({ a: 1 });
console.log(im.get('a')); //prints 1

im.set('a', 2);
console.log(im.get('a')); //prints 1! Original data structure unchanged!

const im2 = im.set('a', 2);
console.log(im2.get('a')); //prints 2

When you need the previous value to calculate the new value of a field, you can use update, which takes a function as an argument that calculated the new value based on the old value.

const im = fromJS({ a: 1 });
const im2 = im.update('a', oldA => oldA+2);
console.log(im2.get('a')); //prints 3

And if you want to set or update deeply nested values, you can use setIn and updateIn.

const im = fromJS({ nested: { x: 1 }});
const im2 = im.updateIn(['nested', 'x'], oldX => oldX+2);
console.log(im2.getIn(['nested', 'x'])); //prints 3

And this Performs Well?

Yes. The immutable data structures try to copy as little as possible when doing mutable updates. They are implemented as trees that can share all the stuff that has not changed.

But, immutable data structures are slightly slower than using mutable JavaScript data structures. Just a few weeks ago, I was debugging a performance problem for a client. Updating their React/Redux app was too slow in some use cases. They were accessing immutable data structures a lot in their mapStateToProps.

As an experiment, I changed all those immutable data structures to JavaScript objects and arrays. Updates were slightly faster (~20%), but still not fast enough. Immutable.js was not our main performance bottleneck (and I think not even the second smallest bottleneck), so I put it back in. (I will write more about performance in later posts).

In exchange for that slight slowdown, you get a lot of safety. When you have immutable data, you can be sure it is unchanged, even when time has passed. And there are also some potential speed-ups: You never have to deeply compare data structures. If it is still the same object (pointer), the data is un-changed.

To Recap…

Immutable data structures can help you add safety to your programs. And when you use Redux, writing your reducers correctly will be easier and less error-prone when you use them.

But they are slightly slower than normal JavaScript data structures in some cases.

Also, this blog post was only a very quick overview of immutable.js and what you can do with it. If you want to learn more, check out the official site.

From Here Onward - 2018 Edition

2018-04-15

The first few months of this year were an awesome ride. I accomplished some things that were hard to do for me, but also hat to take some hard decisions. Here, I want to write about a few things that happened so far, and how I plan to move on…

This is a mostly personal post. I hope you still find it interesting. Ping me on Twitter to give me feedback (link at the bottom)…

Accomplishment: A Book

I finished and self-published my second book this year. The first one happened by accient. Ok, not really by accident, but I did not really plan to write it.

The second book, Quick Glance At: Agile Anti-Patterns was a planned project.

I kind-of knew that I did not want to do it with a publisher, after a very stressful experience in the past. But after I recognized that self-publishing is not that hard, I decided to write a book about agile software development.

I started and wrote some chapters. And I did not really like what was emerging. Then I had the idea with the anti-patterns. So, I threw everything away and started over.

I poured a lot of effort and money into it (e.g. I hired a very talented illustrator). And in early 2018, I finished it. Have a look at it here (ebook and paperback available): Quick Glance At: Agile Anti-Patterns

Decision: Employee or Not?

One of the most interesting companies I know asked me to come to an interview. After that interview, I faced the toughest decision of this year (at least so far).

I never really considered full-time employment. I have been a freelance consultant and coach for over ten years now. And, had you asked me last year if I wanted to become and employee, I would probably have answered: “Not really, except maybe at [names of three or four interesting companies]”.

Don’t get me wrong: I think that many more companies do great work and work on interesting problems. But… I think, in many cases I can provide more value (and have a better chance of doing what I am good at) as an external consultant.

Anyways, when one of the very few companies invited me for an interview, I had to go. A short time later, I told them: For now, I want to stay independent.

This was a hard decision: They work on really interesting problems, have a great engineering culture and there would have been many people I could learn from.

But in the last few years I have tried to learn and improve a few things my clients usually need help with, and for now, I want to build on them.

I have tried to get good at coaching teams, teaching them technical practices like Test-Drive Development or refactoring, practicing pair-programming or mob-programming, dealing with legacy code and facilitating meetings and discussions. And, at least for now, I want to learn even more in those areas and help my clients to get better with that.

(Does agile coaching or technical coaching sound like something your team or organization might need? Let’s talk…)

Conferences, Meetups, …

I am speaking at a lot of conferences and meetups this year - At least compared to past years. While I really enjoy it, it’s also exhausting. And hard to coordinate with my family.

My topics this year are about software quality and it’s relationship to speed, cost and agility, agile anti-patterns, and also technical topics like React and Redux.

Do you want me to speak at your event? I would love to do that. Let’s talk… - Bonus points if you make sure that you have an enforcable Code of Conduct in place, don’t make me #paytospeak and if you at least try to create a diverse event.

SoCraTes Austria

I am, for the third time, co-organizing the Software Crafting and Testing (SoCraTes) Austria, together with Elisabeth Rosemann and Rene Pirringer. Ever after visiting the “original” SoCraTes Conference in Germany, I wanted to organize such an Event in Austria.

And I am very glad that Elisabeth and Rene (and some others who advise us) joined me, because without them, I could not do it.

And I am also glad that they share my passion about creating a diverse and safe event. We put some considerable energy into making this conference interesting and accessible for everyone. We serve vegan food, have an enforcable code of conduct, an accessible venue, and we offer student discounts (ask me) and a diversity tickets campaign. And we are working on getting better every year.

This year, things are looking good so far: We have already sold as many tickets as in the first year (2 years ago), and we hope the conference will be sold out for the first time (100 attendees). And we already have enough sponsors so we can make the conference happen, but there are still a few sponsor packages left.

Are you interested in coming? Buy your ticket now ;).

And Now?

This year, I want to do more blogging again.

I have migrated my two blogs (this one and devteams.at) to a new technology technology, and I have completely re-designed them. And now I want to come back to at least a weekly blogging schedule.

I will also revive my newsletter. So, if you want to stay in touch, subscribe here or follow me on Twitter.

And, almost most importantly: A really big contract will end this summer (because of a customer policy). So, I had to think about how to proceed professionally. But first, I probably will take a lot of time off in August in September, to spend with my family, go to conferences and to play with new technology.

Then, in mid-September or so, I want to start doing client work again. But this time, I would prefer more, smaller assignments instead of a single big one.

I think I can provide a lot of value for teams as an agile coach or a technical coach, even if I am there only for a few days per week - or even per month. We can pair-program or mob-program. By doing that, we will practice pair programming, mob programming, object oriented design, continuous refactoring, test driven development and more.

Or, I can help teams communicate better, find and solve problems and anti-patterns, facilitate meetings, …

Is this something that might be interesting? Autumn will be there sooner than you think, so let’s start to talk now.

React / Redux / Immutable.js / Flow

2018-04-13

I have decided to collect some tips, tricks and things I have learned about working with React, Redux, immutable.js and Flow.

Those are very interesting technologies, and they work together really well. But there are some caveats, some things that we learned the hard way.

Here is what I have learned in the last 2+ years of working with those technologies:

Book: Software Testing Standard Requirements

2018-02-05

I just found this interesting book I wanted to share with you…

The Art of Service’s Software Testing Standard Requirements Excel Dashboard and accompanying eBook is for managers, advisors, consultants, specialists, professionals and anyone interested in Software Testing assessment.

Software quality is a topic that is very important for me right now, and it should be important for every team. This book contains a self-assessment that can be useful for your organization to find out where you currently are. If you struggle to ask the right questions about your testing efforts, this book will give many of them, and a way to score your answers.

The Single Responsibility Principle

2017-07-26

Do you know the Single Responsibility Principle (SRP)?

The single responsibility principle is a computer programming principle that states that every module or class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class.

It seems to generate a lot of confusion. Just a few days ago, Jon Reid had to clarify a misconception about that very principle:

There, he refers to the definition of Robert C. Martin, who expresses the principle as, “A class should have only one reason to change.” In this post, I want to write down my own thoughts about the “Single Repsonsibilty Principle”. I hope I can clarify a few things, and do not add too much new confusion ;)

A Definition that "Works for Me"

So, some of the confusion comes from “single responsibility” vs. “single reason to change”. The definition that talks about “responsibilities” is hard to follow in practice: What exactly is a responsibility? What if I can divide the responsibility in multiple sub-responsibilities? How can I make sure that all the code is part of the same responsibility?

On the other hand, “one reason to change” sounds more like a heuristic to me than a real definition. Yes, when a class has many different responsibilities, it also has many reasons to change. But if that was the definition, we should rename the principle to “SRTCP” (Single Reason To Change Principle).

So, I was searching for a definition that works for me and that gives me some guidance in my day-to-day work. After discussing with several very good developers, I nowadays really like the following definition:

You can describe everything a design element (method, class, module, ...) does - at a reasonable level of abstraction - as a single, coherent thing.

In other words, if you use “CRC cards” to desing your classes, the “Responsibilities” column should contain a single bullet point.

SRP_Hangman_1

If the level of abstraction is too high, you can describe everything as a single thing (“Is a part of the XYZ system”). If the level of abstraction is too low, everything has many responsibilities (“Execute assembler instruction x. Execute assembler instruction y. …”). So what is a “reasonable” level of abstraction?

We’ll come to that soon, after an example…

Hangman

When I teach TDD workshops, I ask the attendees to implement Hangman (the word guessing game) - even multiple times. I now want to discuss with you a few possible designs for implementing this game (none of them is the best possible design, of course).

Let’s start simple. The whole problem is so easy, you can implement everything in a single class:

SRP_Hangman_2

This design has a few disadvantages. Most glaringly, in a TDD class: It is really hard to test. Especially if you do not make any compromises like making methods public that should actually be private.

We can try to simply split the class along the four responsibilities that we have already identified:

SRP_Hangman_3

Now you can easily test three of the four classes, and with some work, you can probably even test the UI. And you can test every class in complete isolation from the other classes, which is great for achieving stable tests…

Is 4 classes for such a simple problem over-engineering? Quit possibly. But I am trying to make a point here…

(Single) Level of Abstraction

So, how do you decide which level of abstraction is right?

There are already several levels in your application, e.g.:

program / library
  > package / module
      > public classes
          > public methods
              > private methods
      > package protected classes
          > public methods
              > private methods

To add clarity to your design, make sure that all design elements in a level are roughly on the same level of abstraction (yes, there is gut-feeling involved in deciding that).

So, all the public methods in a class should be roughly on the same level of abstraction, and the class itself would be on a higher level. They delegate to private methods of that class to do the real work, which are on a lower level.

Sometimes you can find interesting responsibilities by looking at the tests of a class or method. And when you split it, you might need new design elements (a new package or a new class) to keep everything at roughly the same level of abstraction.

Tests and Responsibilities

So, I wrote some tests for the “Rules” class - This time using a different design, where I do not split out the game state to its own class. Here is the output of Jest, a JavaScript Test Runner:

  Hangman - Implements the flow of a single Hangman game, given a secret word.
     returns a hint that contains only underscores at the start of the game
     shows a hint with the correct length for the secret word "test" at the start of the game
     shows a hint with the correct length for the secret word "a" at the start of the game
     shows a hint with the correct length for the secret word "few" at the start of the game
     shows a hint with the correct length for the secret word "cases" at the start of the game
     updates hint to "c____" after guessing "c" when word is "cases"
     updates hint to "c_s_s" after guessing "c,s" when word is "cases"
     updates hint to "c_ses" after guessing "c,s,e" when word is "cases"
     does not update the hint when making a wrong guess
     decrements the number of remaining tries after a wrong guess
     does not decrement the number of wrong guesses after a right guess
     indicates game is over ("Lost") when there was only one guess remaining and the user guessed wrong
     indicates game is over ("Won") when the user guessed all letters of the secret word
     does not accept any input after the game is over

Here is the code that produced this output…

Oh, some of these tests seem to belong together. Let’s group them, and look at the test output again:

  Hangman - Implements the flow of a single Hangman game, given a secret word.
    Generates Hints from the secret word and the input
       returns a hint that contains only underscores at the start of the game
       shows a hint with the correct length for the secret word "test" at the start of the game
       shows a hint with the correct length for the secret word "a" at the start of the game
       shows a hint with the correct length for the secret word "few" at the start of the game
       shows a hint with the correct length for the secret word "cases" at the start of the game
       updates hint to "c____" after guessing "c" when word is "cases"
       updates hint to "c_s_s" after guessing "c,s" when word is "cases"
       updates hint to "c_ses" after guessing "c,s,e" when word is "cases"
       does not update the hint when making a wrong guess
    Keeps track of remaining guesses, so UI can draw the gallows pole
       decrements the number of remaining tries after a wrong guess
       does not decrement the number of wrong guesses after a right guess
    Keeps track of whether the game is running or over (Won / Lost)
       indicates game is over ("Lost") when there was only one guess remaining and the user guessed wrong
       indicates game is over ("Won") when the user guessed all letters of the secret word
       does not accept any input after the game is over
 

Here is the code that produced this output…

It seems like this class has three different responsibilities (at least at some level of abstraction). So, if I wanted, I could split this “Rules” class even further, into one class for each of the groups, and one to coordinate them. Then I would probably need a package to group these two “Rules” classes, and the responsibility of that package could now be “Implements the state changes of a single game, based on the rules”.

Does it always make sense to split a class like that? That depends on a lot of things, but from the perspective of the Single Responsibility Principle, we could do it…

Conclusion

The Single Responsibility Principle gives you an indicator when to change your design. Split your methods / classes / modules when they have more than one responsibility. Restructure code when your classes / methods / modules do not fully encapsulate that responsibility.

When your design elements have many different responsibilities, they have many reasons to change. And they are also hard to test. When your design elements do not reasonably encapsulate their responsibility, changes will cascade through your code. And again, it will be harder to test.

But do not start to split all your classes alon their reponsibilities right away! The SRP should not be the only driving force of your designs - There are other forces, and sometimes they give you conflicting advice. Take, for example, the SOLID principles - 5 design principles, where the SRP is only one of them.

By the way: Jon Reid has now also written an article about the SRP: Single Responsibility Principle: Is It a Fundamental Mistake? Go read it, it’s excellent!

I am Not the Best Developer on the Team

2017-03-31

Being a freelance consultant / coach, I have worked with many different teams in the last 10+ years. As far as I am concerned, I never was the best developer on the team.

No, I do not have any proof for that, of course not. It is more of a mind set than something that can be objectively proven to be true or false. Let me explain…

Learning Every Day

Learn from everyone, follow noone.

If you hire me, I come to your company to learn something. Yes, I also come to provide more value for you than you pay for me - To teach you something, to coach your team, to help you solve a problem, to write some code. That’s why you hired me.

But for me, it is also a learning experience. I am trying to get better at what I do every day. I read many books, blogs, and I try to learn from everyone. And I really think that you can learn something from everyone: Even the most senior developer might learn a thing or two from the most junior, if she is open to learning something.

Now, if I would be in a team and have an attitude like “I am the best X here”, learning from everyone else just becomes a lot harder, at least in the field of X. Also, I think others on the team might notice that attitude, and this would also hinder mutual learning / teaching.

But What if I am the Best?

Let’s assume, hypothetically, that I come to a team, where after some time, all my evidence suggests that I am really the best developer (I do not think this has ever happened to me). I would still try hard to think that I am not the best.

A little humility can help in many aspects. Mutual learning / teaching, like above, is one of them. A better team culture is another. When you ask for help, you encourage people to talk to you on the same level.

Too Many Dimensions

Also, there are too many dimensions where you can be good in software development. And a team working on any non-trivial task needs many of those dimensions.

So who is the best developer - The person who is good at keeping the overall architecture in mind, the person who knows all the details of your programming language, the person who is getting the details right, or anyone else on the team? You need all of them!

I think that I, personally, are quite competent in several programming languages, in software architecture / design, in techniques for better software quality, in facilitating better team practices. I think that, over time, I have become quite good at dealing with legacy code. I am also quite competent as a trainer and as a technical coach.

But I am probably not the best developer or tester or architect or coach or trainer you have ever seen.

Good in Multiple Disciplines

I think Scott Adams (I cannot find the quote anymore) once wrote that it is really hard to become world class in a single field, but when you become merely quite good in multiple fields, you might already be world class for this combination of fields. And this can be very valuable.

I always liked this idea, and I try to work like that. This is why I think I am competent in so many different fields, but surely not the best in any of them. And so far, this has worked quite well for me.

But even this is not what I am trying to say.

Keep Learning

My goal is to keep learning, to keep becoming better. And a little humility can help a lot here.

When my state of mind is “I am not the best X in here”, the questions become “What can I learn from you?” or “How can you help me today?” and, of course, “How can we help each other today?”.

But, of course, this is also something I have to constantly work on. I always have to remind myself to ask these questions. So this post is also a little reminder to myself ;)

React / Redux Training Course

2017-03-16

Last week, I hosted an online training course for people from all over Europe. There they learned how to build web applications with React and Redux. We recorded Videos during the talk, and I prepared some more Videos and Training Materials for you. Get them here:

React / Redux Training Course