Slashdot Mirror


Making Software Suck Less

That much software sucks -- perhaps most of it -- is hard to dispute. Except for the simplest programs, it seems like the price of complexity is a tendency to failure. Commands don't work, user interfaces are neglected to the point of ruin, and components of even the same piece of software often clash with each other. And once you start combining them and try to use more than one application at once, sometimes the best you can hope for is an operating system that neatly segregates the problems so that your word processor doesn't take down your web browser, your IDE or your e-mail client. At least those are desktop applications for individual users, though -- the trouble compounds briskly when the common faults of software manifest in multiuser environments, where one machine going down means a wasted time and frustration for a lot of people at once. In an effort to outline the ways that software could suck less is coding, reading and writing dervish chromatic.

Making Software Suck Less - Processes Once upon a time, a prominent writer and programmer rose to declare "I want software that doesn't suck!" He then explained that certain successful free software projects have similar development features that contribute to software quality. Most of us aren't gifted with the organizational clarity of a Linus, or the brilliant non-orthogonal design of a Larry.

There's hope, though. Improving the ways in which we produce software can dramatically improve the software itself. Extreme Programming suggests that simple habits, acting in concert, produce extremely powerful results. By adapting these techniques to the unique world of free software, we can improve the quality of our programs. We start by restating some common truths about free software development.

Distributed Development Open development, of course, means that anyone with the time and the inclination can look at the code. Developers and dabblers have the opportunity to modify it to their needs. This by no means guarantees that anyone will do so. Making source code available is no silver bullet. Many qualified eyes actively looking for bugs make bugs shallow.

To harness the power of additional developers, you must attract them to the project. A simple design and clear documentation reduce the amount of work needed to come to grips with the system. XP suggests an overall metaphor to describe the system as a whole and to provide good names for the components and subsystems.

Test First The most powerful weapon in your toolbox is comprehensive unit testing. (Unit tests are automated, independent procedures that exercise the smallest possible pieces of functionality individually.) Extreme Programming recommends a test-first approach. Before adding a new feature, the programmer writes a test for the feature and runs all the unit tests. The new test fails, so he writes code to pass the test. When all tests pass, the feature can be checked in. Tests cover everything that could possibly break.

When a bug appears, the programmer writes tests to demonstrate it. After fixing the bug in the code, he runs all tests again. This not only proves that the fix corrects the defect, but it proves that the correction did not break any other features. Besides that, it can prompt the programmer to write additional tests he had not previously considered.

Test-first programming ensures that all features have unit tests. Coders receive immediate feedback -- it's almost like a game. It produces a different mindset, freeing the programmer to concentrate solely on the task at hand. Code becomes easier to write, in the same way that finding the correct piece for a jigsaw puzzle is easier with its neighbors in place. Finally, it gives programmers the confidence to refactor, modifying existing code, by identifying the effects of a change.

Consider providing your test suite with the project. Add a 'test' or 'check' target to the Makefile. Projects designed to run on multiple platforms and distributions can generate better bug reports by including test results. Make it easy for users to report failures.

Simple Solutions First After writing a test, write the simplest possible code that could pass it. Resist the tendency to make things more flexible than you need at the moment. Concentrate only on the task at hand, programming only what you need to pass the test. Don't sacrifice current elegance and simplicity for a feature months down the road.
"It's true that 'simple and tested code means less bugs'.... Good and clear interfaces reduce bugs. Avoiding complexity reduces bugs. Using your brain before you code something up reduces bugs."
-- Linus Torvalds
Good tests free you to change things in the future by identifying the effects of a change. Simple code localizes changes, reducing interconnections. Besides that, your design will change. Adding a feature will take the same amount of time whether you do it now or in the future. Don't spend time and energy overgeneralizing for something six months away when no one will use it in the meantime. Reduce the need for costly and time-consuming rewrites by avoiding extraneous complexity. Have a Plan, Code For Your Users Write a plan for the software. Describe each feature in a paragraph or less, with sufficient detail that people will know when it is complete. Arrange the stories by importance, then tackle them in that order. This allows you to identify the work that will provide the most value to the customer. (In a free software project, the lead developers may be the customers.)

Dividing the project into stories allows delegation, especially in free software projects. Some tasks require an experienced hacker, while others serve as a gentle introduction to the program. Writing stories also provides sane goals and a project roadmap. Choose a few stories for each release. This gives end users a clear view of project progress.

Continuous Design, Refactor With tests in place, you have the freedom to refine your initial design. By using the simplest solution first, you avoid investing time in hard to follow and difficult to maintain code. Your initial design will change. Your plan will change. Expect this and allow it to happen.
"Premature optimization-including premature low-level design--is the root of all evil."
-- Michael Abrash
When you see an opportunity to refactor, do it! Eliminate duplicate code. Relocate common features into a new object or a function. Reduce complexity and interconnections. Don't maintain the same functionality in multiple places. Use simple, well-defined, and consistent interfaces. This, along with your test suite, will allow you to overhaul individual pieces without having to track down holes in far-flung files. Release Often, Release Working Features Commit to regular release dates. This shortens the feedback loop. Users who can count on regular, stable releases with valuable new features will be more likely to use the software. It also provides more frequent entry points for new developers.

Follow your plan to add a few important features to each release. Focus programmer time and effort towards a simple, reachable goal. Allow time for design, testing, documenting, and packaging. The more often you have to do this, the more likely you are to streamline these processes. Resist the urge to add features you cannot complete in time. Instead, break them up into smaller stories and implement the most important parts. As usual, the unit tests help to stabilize the codebase and keep it in a state of stability. After completing a release, take time to modify your stories, shuffling priorities as necessary. Then commit to the next release.

Conclusion If we truly want excellent software, with well-developed features and no messy surprises, we need more discipline in our approach to creating software. In my experiences with these techniques (and in talking to other developers), I have found that even simply migrating to a test-first approach, though painful, has increased my productivity and my confidence. It's scary at times, but immensely satisfying. Taken together, who knows what levels of excellence we can reach?

6 of 315 comments (clear)

  1. Re:Software Engineering will make software suck le by locust · · Score: 5
    I know many programmers that, despite having no 'formal' training, can run rings around the Software Engineers I know.

    The ability to hack, and knowledge of computer system internals, cannot be compared to software engineering. Software engineering requires knowledge of the design process, understanding of system design, and understanding of scheduling. It requires the ability to manage design, complexity, schedule, and people. These are the points where most programmers of all grades fall down... It is the core of why software sucks. Most of the people writing code don't want to manage. They want to design. They don't want to schedule. To them management and scheduling are a burden that takes them from the pure thought stuff that they love to work with it. The price that is then paid, is that people who have no concept of the tasks at hand are asked to do the management component. Unreasonable deadlines are set, features are changed without the proper estimate of the effor to make the changes...

    There is another thing to add to this. It is that people have been building things for millenia. Yet very little of this experience has been transfered to software design. Consider the planning and construction of a ship. Surely the techniques that are applicable in the engineering of that ship (remeber what I said about the management component of engineering -its what makes you and engineer not a scientist) should be to some extent applicable with in software engineering. Yet from my reading of software engineering texts this transfer has not happend. I think it has specifically to do with the sort of backgrounds from which people come to software. The theoretical underpinnings of software have always come from mathematics, where practical things like getting resources can be assumed away. A large number of the remainder have come without any education at all (self taught). They are not in a position to draw these links. They don't know where to look for the information.

    --locust

  2. Software Engineering will make software suck less by TWR · · Score: 5
    The real problem isn't a particular methodology like XP (which does have good ideas in it), it's the complete lack of professionalism in the software industry.

    How many times have people heard of programmers with no degree working on or designing large-scale projects? It's insane. No one would hire an architect or mechanical engineer who didn't have at least a piece of paper from a college. But it happens all the time in software. The costs of the defective systems being turned out by untrained programmers is starting to matter.

    Even a CS degree really isn't a sufficient solution to the problem. Software Engineering is NOT computer science, just as Chemical Engineering is not Chemistry. You need knowledge of the latter to do the former, but there is a different skill set which must be learned. Unfortunately, I'm not aware of any school which is teaching it to potential software engineers. When they do, real software development can finally begin.

    -jon

    --

    Remember Amalek.

  3. Re:Software Engineering will make software suck le by TWR · · Score: 5
    I believe he's referencing a paper whose subject was "Incompetent people fail to understand that they are incompetent, thus overestimate their skills." Hardly ground-breaking research.

    No it isn't ground-breaking to know that ignorant people don't know they are ignorant; the authors of the paper quote Charles Darwin: "as Charles Darwin (1871) sagely noted over a century ago, 'ignorance more frequently begets confidence than does knowledge'."

    What was ground-breaking was showing that people who weren't ignorant downplayed their skills; they "knew what they didn't know."

    He makes the flawed assumption that college graduates make a better effort to continuously hone their skills than non-graduates - a claim with little to no evidence, at least none that he has shown.

    The evidence is the college degree. It's a hoop to jump through; a painful, stupid hoop sometimes, but a hoop nonetheless. Get a science or engineering degree from a top-tier school and it says that, at the very least, you know how to work and to think. Skip that process and pretend that it doesn't have any value and it says volumes about you.

    I trust in top-tier universities to separate wheat from the chaff because I don't know of any other process which is a better way to judge someone just starting out. Can you name one, or do your skills only lend themselves to criticism?

    I still have a standing offer: will anyone have an architect without a degree design a house they would then live in?

    -jon

    --

    Remember Amalek.

  4. Process and Testing by Saige · · Score: 5

    As the article said, those two are by far the biggest steps you can take toward making good, quality software.

    I recently helped to add that CALEA surveillance garbage to a certain cellular system that was kinda news recently due to working with Sega on games for the subscriber unit, etc, etc. I didn't want to do it, most people I worked with didn't want to do it, but we still took the time to do it right.

    We followed software processes, tailored to eliminate unnecessary steps, and adding ones useful to us. We did quality unit testing on everything we touched, including functions that had been around for years. We re-wrote any DOL and function comments that were hard to read or out of date. And that was most of the old ones we touched.

    We took the time to break old functions that had grown complex (20+ cyclomatic complexity) into smaller pieces.

    Guess what? Not only were we just about on schedule (even with the extra time fixing problems left by other people), we found defects that had been sitting around that nobody knew about, and within maybe a month from the time we hit the system test lab, the area of the box we worked on was more or less defect free.

    We put more effort into process and testing than people had before, and had one of the best quality releases the department has seen. In fact, we've been spending months trying to find things to do because time that was set aside for us to fix defects found in testing and the field has been idle, because they haven't been coming in.

    We're not talking about minor changes either. 13 people, months of work each. The other feature that was in the release at the same time as us was smaller, and had fewer people, yet more defects, and took longer.

    A process for the sake of process, well, isn't a good idea. One that is based on doing things that work, and changes with feedback, becomes a great thing to have.
    ---

    --
    "You know your god is man-made when he hates all the same people you do."
  5. Frank Lloyd Wright by pos · · Score: 5

    As somone who has quoted Wright in my sig for some time now (See the article dept.) I feel I should point something out.

    Wright saw things as a whole object. He spent months thinking about the construction of Fallingwater and visiting the site. He drew the first concept draft in about 3 hours. (he actually called the client to come over and see what he had drawn before sitting down to draw it) It changed Very little from that initial drawing. Most experts at the time said the horizontal balconies would not stay floating out into space the way they do and would collapse. The workers were constantly changing the plans because they did not have faith in Wright's design. (Modern analysis now shows that these workers acually ended up weakening the structure)

    As someone who has actually walked through fallingwater, I think one could easily say that the design is the most elegant, natural design you could possibly want.

    To apply Wright's ideas to the concept of software engineering: I would say you either have to be very gifted in how your brain processes/sees information, data and functionality, or create a system that is whole and complete through lots of careful adjustments and evolution. The latter seems to be the common OSS approach however the former is the more respected/impressive way. :) I suppose one could argue that even Wright evolved his prarie style and his catilevered/fallingwater style over several hundered homes. I guess I can see some similarities between Wright, Torvalds, and Wall among others. (inspired design, excellent execution, and refinement over time)

    I think the important lesson here would be that all of these people create something that stands as a whole unified concept that doesn't sprawl out where it doesn't belong and is fundamental enough to change the way other people see the world or problem space. They all thought about their designs A LOT! They are all artists and craftsmen.

    Wright's work inspires me and fills me with awe, as does perl and the linux kernel. Does your software?

    -pos

    The truth is more important than the facts.

    --
    The truth is more important than the facts.
    -Frank Lloyd Wright
  6. history and suggestions by q000921 · · Score: 5
    About 20 years ago, there used to be programming environments that supported XP, runtime safety, incremental development and testing, and rapid development. They were things like the Lisp machine and the Smalltalk-80 environment.

    Don't get me wrong: those systems had their own share of problems, not the least of which was that they required expensive hardware to run well. They also lacked some of the niceties and safety check of modern programming languages (by which I mean languages like ML, not C++).

    So, what can you do? Don't blindly use C/C++ for everything. Those languages have their place, but they require you to spend a lot of time on stuff that isn't related to getting the job done. Learn something new, and learn about the history of all this. Here are some suggestions:

    • Learn about functional programming with Haskell and OCAML, and SML/NJ
    • Learn about logic programming with one of the Prolog implementations.
    • Read up on CommonLisp, Flavors, CLOS, and the Lisp Machine Window System. You can get CommonLisp implemenations at cons.org
    • Read up on Scheme and get a Scheme programming environment. PLT Scheme looks pretty good.
    • Read up on Smalltalk-80 and its programming environment (you can get a so-so Smalltalk-80 implementation at Squeak).

    While those systems may or may not help you in your day-to-day work, they teach a lot about what programming can be.

    For your day-to-day work, consider using languages and environments like Python, Perl, and Java. They aren't quite as convenient as the more academic systems I mention above, but they still let you focus much more on the problem rather than the mechanics of programming.