“Things users don’t care about” is something every software developer needs to know about.
Kudos go to Thomas E. Deutsch for finding and telling me about it.
Many of us have noticed that designing software is surprisingly hard but many don’t know why that is. The simple answer: Design is the art to balance contradicting goals.
Let’s design a public garbage bin together.
What do we want?
It’s easy to see that “cheap” contradicts almost anything else. “Nice to look at” means an (expensive) artist has to build the form. Big garbage bins ain’t cheap. Easy to clean and robust mean high quality materials for hinges and locks. Easy to clean and long lifetime involve expensive surface materials and finishing.
It should be easy to lift for the cleaning crew but not for rioters. When a car hits it, the bin should give way. So these contradict each other as well.
Still not convinced? Look at my elevator example.
Documentation is the unloved step-mother of software development: Nobody likes it.
On the writing side, documentation is either considered a waste of time:
On the reading side, it’s a waste of time:
The core of the issue is that documentation and code are two different things. Documentation is, by nature, abstract. It’s at least one step removed from the solution.
But the question should be: Does it have to be that way?
So instead of writing hundreds of lines of code to open a window, give it a size, make sure it remembers its size and position, etc., we could write:
Users can search for Customer objects by any of the name fields.
Note that the links are part of the documentation and the code; the underlying code generator should follow them and examine the code/documentation on the other side.
(Second part of three; first part is here)
As you can see, the cost of fixing bugs rises as time passes. Why is that?
There are many reasons:
This also explains why unit testing is so much more efficient to QA testing for many kinds of bugs: It simply catches them before they spread their bad influence.
So fix your bugs early, OK?
I’ve prepared a small presentation to give an overview of software development costs.
This diagram describes the costs/gain per feature.
The most simple curve, complexity, is easy to understand: Costs go way up as you add features. Adding another feature to an already complex product is way more expensive than adding the first feature to a non-existing product.
The number of bugs in the final product is harder to understand. As you add features, you also add bugs. The number of bugs per kLOC is an individual constant. We always make the same mistakes and we the number of bugs we create per kLOC is pretty stable, too. The number is different for each person but every developer has their own number and that number doesn’t change much unless external circumstances change dramatically. In fact if you create statistics about bugs found per team member, you can tell how many new bugs there will be after he added N lines of code (see “They Write the Right Stuff“).
That means every product has bugs. If the project isn’t a complete disaster, then the team will have found a way to cope with these. Or to put it another way: If the number of bugs grows too fast, the project will either be canceled or drastic measures will be taken to reduce the flaws again.
This is what the curve means: In the beginning, there will be few bugs because there are only a few lines of code. Remember: number of bugs = lines of code * individual constants. Each line that you don’t write reduces the number of defects.
As time passes, the number of bugs will grow just because lines of code are written. Eventually, that number will either explode or the team will find a way to keep the number in check.
The last curve is for the marketing department. It describes the usefulness of the product for a customer as features are added. A product without features (a.k.a vaporware) is not very useful for a customer. The first feature will be the most useful … or it should be: Why are you wasting your and your customer’s time with features that aren’t the most useful?
But as you add features – and trust me, customers and marketing will try to get as many as they can get – the usefulness doesn’t grow as much anymore. Each feature comes with the cost of complexity: There will be more menu items, dialogs and buttons. The manual will get bigger. The customer will need to remember more to use every feature. That starts with remembering that a feature even exists and goes on with remembering how to use it efficiently.
At the same time, you started with adding the most useful features, right? So additional features, by definition, can’t be as useful as the first ones.
And eventually, the product will contain more features than any single customer cares about. New features will be added for new customers that existing customers don’t care about or that even get in their way (when menu items move around, for example).
This is one reason why everyone feels that Google or Apple products are so easy to use: They work really, really hard to reduce the number of features in their products.
Next week: Bug fixing costs.
When you develop a software, you will ask yourself these questions (quoted from here):
In his talk “Improving system development using traceability“, Ömer Gürsoy shows an approach to answer these. The idea is to trace changes end-to-end: From the idea over requirements to design, implementation, tests, bug reports and the product manual. For this to work, you’ll need to
At itemis, they developed tooling support. A plug-in for Eclipse can track changes in all kinds of sources (text documents, UML diagrams, requirement DSLs) and “keep them together”. It can answer questions like “who uses this piece of code?”
The answer will tell you where you need to look to estimate the impact of a change. That helps to avoid traps like underestimation or missing surveillance.
Today, the plug-in shows some promise but there are rough edges left. The main problem is integration with other tools. The plug-in supports extension points to add any kind of data source but that only helps if the data source is willing to share. The second problem is that it doesn’t support versioning right now. It’s on the feature list.
On the positive side, it can create dependencies from a piece of text (say a paragraph in a text file). If you edit other parts of the text file, the tool will make sure the dependency still points to the right part of the text. So you can make notes during a meeting. Afterwards, you can click on the paragraphs and link them to (new) requirements or parts of the code (like modules) that will be affected. Over time, a graph of dependencies will be created that helps you to keep track of everything that is related to some change and how it is related: Where did the request come from? Which code was changed?
Always keep in mind that tracking everything isn’t possible – it would simply too expensive today. But you can track your most important or most dangerous changes. That would give you the most bang for the buck. To do that, you must know what you must track and why.
A feature that I’d like to see is automatic discovery. Especially Java source code should be easy to analyze for dependencies.
In her talk “Agile Chartering: Energize Every Project Liftoff,” Diana Larsen presented approaches how you can set up your agile projects. Why is that important? When a rocket is launched into space, a lot of preparation happens to make sure the move from ground to space is smooth and successful.
Software projects often ignore this important step.
For example, it would make sense to check the commitment of team members. Commitment comes in two flavors:
Another important question that each team member will ponder is WIIFM – What’s in it for me? Answers to these questions will have a huge impact on the success of a project.
Regulations are important but don’t forget that the human brain has a limited capacity. If you want them to follow the rules, you must restrict them to five tops.
Another strategy is to create “member shields” where each member writes their name on top of a shield like shape. The shield is then separated into four quadrants:
Write a motto below the shield.
Put those in a place where every team member can see them.
Make sure that the team members know where the team fits into the organization. Post a 10’000 feet view of the company somewhere.
Agile development is all about risk management: Notice them, rate them, discuss them, act on them.
Good places to look for risks: Team boundaries and interactions: Who depends on the team’s work? On whom does the team depend? Does the team have everything it needs?
What does the team know about the future? What do we not know? What are opportunities and threats?
Remember the PAC triangle: Purpose – Alignment – Context. Every move of one corner influences the other two as well.
Marc Bächinger gave a presentation how to develop HTML5 browser applications.
You should use REST on the server side because that makes the server and the components of your application easier to reuse.
The main drawback is that you have (often much) more complexity on the client. This can be controlled by strict application of the MVC pattern.
Since the whole application now runs in the client, security is even more important since attackers can do anything that you don’t expect.
Ingmar Kellner presented some tips how to prevent your architecture rotting into a mess. When that happens, you will have these problems:
According to Tom DeMarco, your ability to manage this depends on control. And control depends on measurements – if you can’t measure something, you can’t control it.
How rotten is your software? Look for cycle groups (some package X depends on Y depends on Z depends on A depends on X):
What can you do?
Use a consistent “architecture blueprint” that makes it obvious which layer/slice can use what. In the blueprint, layers are horizontal (presentation, domain, persistence) and slices are vertical (everything related to contracts, customers, users, and finally common code).
You will need someone with the role “Architect” who “defines the architecture, thresholds for coding metrics, identifies ‘hot spots’” and developers who “implement use cases, respecting the architecture and coding metrics thresholds.” All this is verified by a CI server.
At the same time, avoid “rulitis” – the false belief that more and stricter rules makes things “better.”
Some rules you might want to use:
Following these rules can help to reduce costs during the maintenance phase:
according to a study conducted by Barry M. Horowitz for the Department of Defense.
What is assessment? The process of understanding a given situation to support decision-making. During software development, engineers spend as much as 50% of the overall effort on doing precisely that: they try to understand the current status of the system to know what to do next.
In other words: Assessment is a process and a set of tools to help developers to make decisions. They typical example is a bug shows up and you need to fix it. That raises the usual questions:
As we all know, each of these steps can be difficult. As an extreme example, someone mentioned selling software to the NSA. It crashed. The NSA calls the developer:
NSA: “There is a problem with your software.”
You: “Who am I talking with?”
NSA: “Sorry, I can’t tell you that.”
You: “Well … okay. So what problem?”
NSA: “I can’t tell you that either.”
You: “… Can you give me a stack trace?”
NSA: “I’m afraid not.”
Unlikely but we all know similar situations. Even seasoned software developers are guilty of giving completely useless failure reports: “It didn’t work.” … “What are you talking about? What’s ‘it’?”
Tudor gave some nice examples how he used simple assessment tools that allow him to query log files and sources of some application to locate bugs, locate similar bugs and help to find out why some part doesn’t behave well. Examples:
So assessments allow you to do strategic planning by showing you all the dependencies that some part of the code has (or the whole application).
In a spike assessment, you can analyze some small part to verify that a change would or could have the desired effect (think performance).
Did you know that developers spend about 50% of the time reading code? If tools can help them understand some piece of code faster, that makes them more productive. Unfortunately, today’s tools are pretty limited when it comes to this. Eclipse can show me who calls Locale.getDefault() but it can’t show me indirect calls.
Worse: If the developer makes the wrong decision because she couldn’t see all the important facts, then these often have a huge impact.
Another important aspect is how you use metrics. Metrics are generally useful but the same is not true for every metric. Just like you wouldn’t copy unit tests from one project to the next, you need to reevaluate the metrics that you extract from each project. Some will just be a waste of time for certain projects.
We really, really need better tooling to chop data. IDEs should allow me to run queries against my source code, collect and aggregate data and check the results in unit tests to validate design constraints.
It was also interesting to see how Tudor works. He often uses simple words which can be misleading. But when you look at the slides, then there was this graph about some data points. Most graphs show a linear Y axis with the ticks evenly spread. He uses a different approach: