Sunday, May 23, 2010

Kenyon's Hierarchy of Software needs

Kenyon's Hierarchy of Software Needs

John Kenyon, 2010


As a developer and a pessimist, I often find myself dealing with my own past mistakes, as well as the mistakes of other people around me. Ostensibly, this means trivial syntax or logic errors. What I am most interested in are the deeper issues of software engineering. Not simply which type of loop, or which type of design pattern, rather the broader, unnamed decisions about what to work on, things like what part of the project should be done first, what should be deferred, what should be optimized and what should be brute forced.


That last one gets me a lot, optimization. Optimization is a dangerous animal. It is what made Google king and what makes modern games fight for frame rates. But premature optimization is widely accepted as, to quote Donald Knuth, the root of all evil. In this document I would like to explore why this is, by putting it into context. And I shall do so by founding, the Hierarchy of SOFTWARE needs.


This is an obvious parallel to Maslow's hierarchy of needs, but discussing the delivery of a software project to a client, in terms of how and how badly you will fail if you do not fulfill the needs of each level. The “needs” are presented in order of most important to least important. The fulfillment of any need must be achieved without compromising any more important need.


So here it is:


In order to be successful, a system must...


Section 1 – Physiological needs

A failure in any of these fields is fatal, and may lose you your client immediately. Failure here is basically a forfeit, you might as well have never even started the project.

1.1: ...Be Delivered

If your client goes bankrupt while waiting for your software, you fail outright. Simple as that.

If your client loses the first move advantage while waiting for your software, you fail indirectly.

There is no discussion on this. A solution that is never delivered in any form is of zero value. Sadly, it is very easy for a project to enter a cycle of distractions, failures, redesigns, conflicts and other circumstances that turn the project into an undeliverable. As a developer or manager, this word should be your biggest fear, as it means the project will not finish in its present state, all time previously spent is at risk of being totally wasted and discarded, and any future resources allocated to that project will likely also be time and effort wasted.

  • If a project appears to be undeliverable, then this must be corrected immediately and completely. This may require brutal sacrifices, firing programmers, throwing away code, and may even mean writing off tens-of-thousands of man hours as a loss. The sacrifices that must be made may be painful, but once it becomes clear that a project will not complete, will not halt, then desperate actions must be taken.

1.2: ... Be Correct

A friendly calculator that makes mistakes is useless, and may even be harmful.

A fast database that loses data is useless, and may even be harmful.

If your software seems to work, but is subtly and critically wrong, then your client's work based on your software will be wrong as well. This will likely compound over time, meaning when you do discover the problem, there will likely be a lot of damage done. This is the most subtle, as there are no warning signs of wrong software like there are of broken software. A program that provides a wrong answer one out of a million times may go for a while unnoticed and without doing any harm. But that one millionth time could cost millions of dollars, or even human lives. If your client is sued or bankrupt because of a fault in your code, you can expect the partnership to end shortly after that.

  • Faulty logic must be kept out of a program at all costs. This means your development system should take into account that even the smartest and most heroic of programmers can and will make mistakes. There are many processes that exist to address this, including all manner of testing approaches and tools, code reviews, and live iterations. When there is concern that a mistake has gotten into the program, it should be addressed immediately before it silently starts to cause damage.

1.3: ... Do What the Client Needs

NOT what they want. NOT what they ask you for. But rather, what they NEED.

The client doesn't always understand the language of software and engineering, and the client doesn't always understand the true nature of their problem. They may clearly and intentionally ask you for something that does not actually solve their problem. It is therefore important not just to translate their requests into code, but rather to understand the problem and then develop a solution to the real problem. Spending valuable time and capital on developing a solution to the wrong problem may get you payments in the short term, but will not help your client stay afloat, nor build the trust and record of success needed for larger, broader success.

  • Out of politeness, ego, impatience, or even laziness, a developer may not pry the full problem description and context from their user. This is extremely dangerous, and will likely lead to: programmer inefficiency and wasted time as they try to rebuild a (poor) model of the clients actual needs based on inadequate information; awkward demonstrations where desired features are not available as expected; arguments and blame passing; termination of contract; and worst of all, constantly changing design requirements, a condition that can often mutate into the dreaded undeliverable. To counter this, the software architects and the clients must be forced to reconcile their personalities, their languages and their methods. If there are personality conflicts, change the team, or leave the client. If there is some risk of communications failure, then extend the meeting, or even plant one or more developers in the clients operation so they see first hand the context and problems of the client. Strict Use Case diagrams (the only UML diagram I actually respect) should be created, and the client should sign off on these before the actual contract begins.

"Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." - Albert Einstein

Section 2 – Safety needs

A failure in any of these fields is critical, and will certainly lose your contract if the failure is allowed to stand for too long or is repeated too often. Failure here is a sound defeat, you are nothing more than an also-ran.

2.1: ...Be Stable

A system that crashes randomly is not going to be well received by a client.

Unstable software raises questions about the correctness of the software, which is of higher importance.

Unstable software is also a sign of poor design, which is itself a compounding problem as will be seen later. One may argue this goes higher on the list, but unstable software will not take you out of the game immediately. It is major, but taken in small doses is not always fatal. It is worth noting that this is the first purely technical issue on the list.

  • Test early, test often

  • Test in captivity, test in the wild

  • Test by hand, test with tools

  • Test the units, Test the integration

  • Test for smoke, test for regressions

  • Engage in code reviews. Buy lint. Compile with all warnings. Buy a copy of lint.

  • Consider using a language with automatic memory management and static types

Trust but verify” - Ronald Reagan

2.2: ...Be Scalable and Expandable

The world changes, and quickly. A clients needs change with the world. Your code must change too.

As code gets added to a project, the project becomes more complicated. As a project becomes more complicated, development slows down. It may even be, that while your software algorithms are fast, your development algorithms are slow (I have planned a whole blog post about this, O(N2) development time!). As this cycle of decreasing developer efficiency compounds, the project may become the dreaded undeliverable. Note that this is the second purely technical issue on the list.

  • All the software engineering in the world cannot give you perfect foresight. Talking to the customer helps, but still unforeseen circumstances can arise. It is entirely possible that even following the advice above, a project will become bloated and impossible to develop. This can be alleviated somewhat by preferring long term career programmers to temps, by using tests to prove the correctness of a system and thus demonstrate tangible progress or at least the absence of regression, and it may mean halting development of new features to engage in refactoring. Re-factoring is often overlooked as a time sink since it does show tangible results, but the intangible easing and improved efficiency of future development will mean more long term results. Managers must appreciate both the importance and the nature of refactoring. The importance of refactoring is that, if done properly and successfully, it can reduce the likelyhood of a project becoming an undeliverable. The nature of refactoring is that it will give the appearance that the project has already become undeliverable, because new developments will seem to be stalled. It is possible for refactoring to do damage to a project, but this usually means that the refactoring was put off way too long, was done for the wrong reasons, or was done with an over-complicated design.

It is not the strongest of the species that survives, nor the most intelligent that survives. It is the one that is the most adaptable to change.” - Charles Darwin


2.3: ...Be Usable

The system must be easy to use. It must be easy to install, easy to debug as needed, and easy to use for day to day use cases. Otherwise, people just won't use it. I've seen a dozen small programs disappear into the dusty corner of a repository simply for lack of an attractive interface.

This need goes beyond documentation, but rather demands that the software just be easy to use. It must be easy to build the source, it must be easy to install from a package, it must be easy to navigate the interface. If the problem it solves it inherently too difficult, then documentation may provide a backup.

That's why SMTP and HTTP won out over more complex (but better!) protocols. This is why Windows and OSX won the PC over Unix. If a problem is inherently too complex, then the documentation must be good, but (against common dogma) I think that documentation should be a fall back, not a front line item.

  • This is largely reliant on knowing how the user will use the software, and ties in closely with “Do What the Client Needs.” Some systems need elegant graphical user interfaces, some need web interfaces, some are totally invisible, and should have no interface at all. All of this is dependent upon the context. Hiring a QA team can help with this, but may not always be feasible depending on the size of the project. Involving the client, or presenting to them early and often can help with this as well.

Section 3 – Esteem needs

3.1: ...Be Delivered On Time

I previously listed “Be Delivered,” as the most important item on the list. This is not a repeat, but it is a sort of variant. Being delivered late infinitely better than never being delivered at all. But it is still bad.

  • First, read The Mythical Man Month by Fred Brooks. Next, be realistic about deadlines. Appreciate that all predictions made by optimists are optimistic, and will not happen because this world is not optimal. When someone says “this easy problem will take two weeks” its because he is being realistic. Refactoring now means less crunch later. Don't ask a programmer to stay late unless you stay late right along side them. Be realistic when setting time-lines, always schedule a “dress rehearsal” demo ahead of client demos. If you must have a crunch time, hold it well in advance of the real deadline. Focus on the features that matter.

  • Let your workers work. Time spent in meetings is time spent not working. Meetings should be measured and relevant.

  • Distractions hurt productivity, much more so than would be obvious. Temps, interns and novices cause distractions with reckless abandon, keep them under control.

  • While designing and planning are community activities, programming is not a community activity (pair programming not withstanding).

  • An interesting option: Keep scheduled “focus” hours, where no meetings may be held, no distractions or questions may be directed at those who are actively working.

  • When a developer comes to a manager with a request or a requirement, they should be listened to and given full consideration. A manager should aid and accommodate, as well as direct and dictate.


3.2: ...Be Fast

Humans will have to use your system, and humans are impatient. Gamers hate slow frame rates and lag. Workers hate having to slow down their work to accommodate their computer, or being interrupted by stalled software. Managers don't like idle workers.

  • First: Profile.

  • Second: Include performance tests in your test suite.

  • Third: Optimize by improving relevant algorithms and removing redundant calls.

  • Fourth: Optimize by addressing code issues.

  • Fifth: Optimize by taking advantage of embarrassingly parallel problems (if parallel hardware is available).


Optimization and performance falls into the eighth slot on the list of most important things for a system to fulfill. Yes, it is important, but it must be appreciated that there are much bigger threats in the software's life cycle than performance, and much more important tools than optimization. And even when you get to the speed requirements, optimization isn't even the first step.


Whenever anyone tells you that performance is the most important, I encourage you to start rattling off these other, more important requirements. Expect to hear “well, obviously yeah but...” once or twice before they get the point.


Is it important for program to be fast? Yes of course it is. Just as it is important for a person to live a rich life full of adventures and experiences. But more important to a person than a rich life full of wonder and joy, is oxygen, and then water, then food... shelter... security... and so forth. Attempts to gain food at the cost of lost oxygen (fishing the hard way?), will result in death. Attempts to gain security through hiding in a cave, a the cost of forgoing access to food and water, risk resulting in death. And so forth.


And, of course there are cases where performance is even a requirement of the system, such as a fail safe system designed to protect humans from heavy machinery. Yes, if the system is not fast enough, then it may fail and a human may even die because of this failure. But the exact same grim end result occurs if the fail safe system was never completed, if it fails to recognize the system correctly, if it does not interface correctly with the client's machinery, if it crashes instead of engaging the fail safe systems, if it isn't updated to handle the client's new machinery, if it is not installed incorrectly.


So to recap. Yes, performance matters. It matters a lot. But it must be understood that it is not the only thing that matters, and it is seldom the thing that scuttles a project. It should be sought only when it is sure that it will not risk any more dangerous failure in the project development process.