My previous posts have looked at the problems caused by trying to do too much at once. This can affect all our stakeholders – be they users, investors or developers.
As users, we want our apps to work intuitively, with minimal administration and a short learning curve. As investors, we want the development path to be smooth and predictable, so we can see that all important return on our investment. As developers, we want it to be easy to add new features without introducing (yet) more bugs. We all want life to be simple.
In this post, I’m going to look at the concept of simplicity – hopefully without making it too complicated. And so, to the third myth of Agile …
Where do things go wrong when we try to be Agile …?
The simplest solution is the easiest to implement.
We’ve often heard about the KISS principle – “keep it simple, stupid”. In isolation, this phrase is not particularly helpful. It’s no more helpful than “it’ll be ready when it’s ready” or “write the code properly”. Simplicity is relative and extremely subjective.
Under the hood, there is nothing simple about software. In fact, it is inherently complicated. Software exists to solve complicated problems that don’t have practicable solutions in hardware. It is our responsibility to break those problems down into manageable parts, and this effort can often be harder than taking the easy short cuts.
Simplicity is relative and subjective …
From the perspective of the user, simplicity can be perceived relatively, like when we compare the features supported by two apps. Likewise, simplicity can be perceived subjectively, like when we think about how well an app fits its purpose.
One app may have more features than another. The app with more features may be relatively harder to use than the app with fewer features. For example, Microsoft Word has many more features than Notepad. Notepad is simpler than Word.
The same may be true the other way round. An app with many features can still be easier to use than an app with fewer features. It is more intuitive to change the presentation or style of text using the features provided by Word than those provided by Notepad. Word is simpler than Notepad.
Maintaining the analogy of text editors, the vi editor has a similar feature set to Notepad, but for many it is difficult to use. Learning an extensive set of commands and keystrokes is more complicated – a bit like learning to play the piano when all you want to do is listen to music. vi is more complicated than Notepad.
And yet, when editing files on a terminal, vi provides a convenient short cut. The vi editor may be hard to learn – but in the context of the ubiquitous command line, it makes many tasks easier once it is learnt. vi is simpler than Notepad.
Therefore, we need to make sure that a software solution is simple for users, in terms of its feature set and how those features are used.
Incremental plans help us simplify the development process …
Much like death and taxes, budgets and timescales will (and should) always be tight – this is the nature of competitive business.
Planning the development of large multi-disciplinary systems is difficult. In addition to the complexity of each part, all the development must be scheduled so that it can be delivered on time and without the cost spiralling out of control.
Traditional waterfall plans must decompose complex system behaviour into a plan, often with little knowledge about the detail of the work. They must identify dependencies and lead times. They must resolve conflicts between time, cost and fractional resources. An entire project management profession and science is dedicated to creating such large scale plans. Waterfall plans are complicated.
Agile advocates making a plan that defines only small achievable goals over a small time period. Such a plan has fewer dependencies, and is executed by a small team. The small, simple plan can change direction easily (it is “agile”). An Agile plan is simpler than a waterfall plan.
However, it takes many small plans to meet the goals of a large scale multi-disciplinary product. Using many small simple plans means that we have to create and manage more plans, and we have to do this more often. Furthermore, it is challenging to define the scope of the tasks that we are certain we can complete within a short time period. Defining tasks that can continue without dependencies is hard. Defining the order of tasks in the backlog that avoids dependencies is also hard. Creating the Agile plan is harder than creating the waterfall plan. It is especially hard for a professional project manager who is not a software developer. An Agile plan is more complicated that a waterfall plan.
The Scrum framework delegates and distributes the unknown factors of planning to the team – those with the right expertise should be able to make the most accurate estimates about detailed work. With only a short time period to answer a well-formed question, we are more likely to be accurate in our estimate.
To be effective as an Agile development team, it is critical that we create a plan that delivers a series of small goals, building our product up to meet the users’ expectations over time.
Patching the code a lot doesn’t make it any simpler …
When the blood seeps through the dressing, stitches are more effective than a sticking plaster. Poorly developed software frequently becomes obscured by its own patches, and the code becomes the sum of its iterations rather than a coherent solution.
If one patch is considered “simple” just because it can be completed within a sprint, or changes only a few lines of code, then it is more than likely that the next “simple” patch will obscure more meaning from the code and make it more complicated. This can continue ad infinitum. Each small patch makes the software harder and harder to develop, and risks more and more bugs. The solution becomes sensitive to change (i.e the solution is unstable). The wounds fester.
Rashly applied changes may achieve the sprint goal on time, but this approach doesn’t make the code any simpler. In fact, it makes it more complicated and less reliable.
A small change is not equivalent to a simple solution.Agile Helpie
Making it Simple
As I pointed out in my first Agile myth, solutions are not made simple by simply not thinking about them.
Simplicity–the art of maximizing the amount of work not done–is essential.Agile Manifesto
So how do we harness this elusive simplicity for all our stakeholders? How do we know how much work we didn’t have to do? There are many ways to achieve this, but I’m going to suggest a couple of ideas that should help.
Minimise the Dependencies
One of many factors that complicate development is the dependence on external components or schedules. A product which has many parts that all depend on each other is hard to develop, hard to build and hard to manage. For example, if a circuit board is not ready then we can’t integrate the firmware functionality.
A good project manager simplifies their plans by making sure that they can accommodate any external influencing factors. In short, they minimise the project dependencies.
The same is true for a software solution. A good design is impervious to changes in its dependencies. If a header file in our source code includes may other header files, then it is complicated and it will require a lot of maintenance. Similarly, if our software target depends on many external third-party libraries, then we will need to put a lot of effort into managing new releases of each library.
Therefore, for any piece of code, and for any sprint period, we need to minimise the number of external entities that will affect our progress. This applies as much to the design itself as it does to the availability or status of the artefacts upon which our features depend. Those items with indeterminate dependencies can be deferred until we know we can commit to them.
Simplify the Problem
In order to keep the solution simple, the best place to start is to simplify the problem. This is not as trivial as it sounds. We need to accept that it takes a significant amount of analysis to simplify a problem before we establish the simplest solution.
Often, I see developers commit rashly to completing a user story, without really analysing the problem. Inevitably, this lack of foresight (or “design”) results in our failure to meet commitments within a sprint, or worse, we have to implement the solution many times. We create technical debt.
A problem can often be expressed in terms of the needs of the user. For example “I need to download the data quickly so I can show it to the customer” or “I need to see how quickly the pressure is changing in the tube so I can control the flow of fluids”.
The statements above provide a pretty clear idea of what the user wants. However, they are too vague to define a solution. As a developer, I can’t tell what data needs to be downloaded, how quick is acceptable or how the data needs to be presented to a customer. The problem must be sculpted into something that can be tested and accepted by the user. The solution must be broken down into individual objectives that can be integrated to provide the features requested.
A couple of useful techniques help us distil the needs of the user and at the same time reveal the technical details we need.
A user story is a written description of the user’s needs. Whilst the story can be summarised in a single sentence, it is often unlikely that the software can be completed within a single task. In fact, it is probably unwise to attempt that.
We might think that the first step to simplifying the problem and its solution is to form the right user story. But what is the right story? It is more effective to iterate over the story until the real requirements, and indeed the solution become clear. This actually takes very little time (a matter of hours or even minutes), and potentially saves days of effort in the code.
- Analyse the use case into the verbs and nouns of a sentence, to decompose the functionality.
- Identify the necessary refinement to interfaces, and therefore the impact on the existing code.
- Consider the opportunity to refactor the existing solution and therefore recover technical debt.
- Translate the high level use case into multiple stories.
- Assess the effort in terms of the development process, for example in terms Scrum’s definition of ready and definition of done.
- Add the stories to the backlog and add story points to each.
The art of simplifying a problem deserves an article in its own right; but once they have mastered it, the Agile developer will be in control of the solution and its delivery.
Sequence the Solution
Let us assume that we have simplified our problem into beautifully formed user stories, and these stories are nestling somewhere in our product backlog, waiting to be worked on.
As development team, we can work on multiple stories concurrently. We have minimised the dependencies of items in the backlog, so we should be able to take one story each and just crack on, right?
Not necessarily. When we decompose a problem into simple solutions, it is inevitable that we will introduce some dependency in the order of development, even if we minimised our dependency on external influencing factors.
Therefore, we need to have a look at the backlog and arrange the stories in order, so that each story provides a platform for the next to build upon. For example, it’s worth implementing and proving my UART driver before I try to integrate something that uses it, like a command line terminal. However, this doesn’t mean that I can’t write the code to provide the command line given, knowledge about the interface and performance constraints of the UART driver.
The stories in the backlog should be ordered to provide a path that allows features to be integrated from the bottom-up. In the case of our UART, the first commitment should be to prove a robust driver with a clearly defined interface. Once this is stable, it provides a firm foundation to which we can add the command line functionality.
Making these decisions is not particularly difficult, when we take a step back from the code and look at the backlog. A well drilled Agile team can actually make a lot of decisions very efficiently in backlog refinement meetings, provided the backlog is well populated and the team members have a broad view of the development.
So What’s Your Point …?
Software development is not “simple”. Whether we make apps with fewer features, or plan for shorter time periods, or do more up-front design, we can only trade off the inherent complexity of a solution between one dimension and another. The success of using Agile methods depends on the right team members making the right judgment calls to achieve the balance, or “just enough” complexity.
Scrum provides us with tools and advice about how to manage the various tasks effectively to reach our goals. We need to practice these techniques to make development simple.