2001/11/16

What is Extreme Programming?

Check out this xp textbook classic from Ron Jeffies, our kongfu man got it in action...

Extreme Programming is a discipline of software development based on values of simplicity, communication, feedback, and courage. It works by bringing the whole team together in the presence of simple practices, with enough feedback to enable the team to see where they are and to tune the practices to their unique situation.

In Extreme Programming, every contributor to the project is an integral part of the "Whole Team". The team forms around a business representative called "the Customer", who sits with the team and works with them daily.

Core Practices: Whole Team

Extreme Programming teams use a simple form of planning and tracking to decide what should be done next and to predict when the project will be done. Focused on business value, the team produces the software in a series of small fully-integrated releases that pass all the tests the Customer has defined.

Core Practices: Planning Game, Small Releases, Customer Tests

Extreme Programmers work together in pairs and as a group, with simple design and obsessively tested code, improving the design continually to keep it always just right for the current needs.

Core Practices: Simple Design, Pair Programming, Test-Driven Development, Design Improvement

The Extreme Programming team keeps the system integrated and running all the time. The programmers write all production code in pairs, and all work together all the time. They code in a consistent style so that everyone can understand and improve all the code as needed.

Core Practices: Continuous Integration, Collective Code Ownership, Coding Standard

The Extreme Programming team shares a common and simple picture of what the system looks like. Everyone works at a pace that can be sustained indefinitely.

Core Practices: Metaphor, Sustainable Pace

Core Practices

Whole Team

All the contributors to an XP project sit together, members of one team. This team must include a business representative -- the "Customer" -- who provides the requirements, sets the priorities, and steers the project. It is the best if the Customer or one of her aides is a real end user who knows the domain and what is needed. The team will of course have programmers. The team may include testers, who help the Customer define the customer acceptance tests. Analysts may serve as helpers to the Customer, helping to define the requirements. There is commonly a coach, who helps the team keep on track, and facilitates the process. There may be a manager, providing resources, handling external communication, coordinating activities. None of these roles is necessarily the exclusive property of just one individual: Everyone on an XP team contributes in any way that they can. The best teams have no specialists, only general contributors with special skills.

Planning Game

XP planning addresses two key questions in software development: predicting what will be accomplished by the due date, and determining what to do next. The emphasis is on steering the project -- which is quite straightforward -- rather than on exact prediction of what will be needed and how long it will take -- which is quite difficult. There are two key planning steps in XP, addressing these two questions:

  1. Release Planning is a practice where the Customer presents the desired features to the programmers, and the programmers estimate their difficulty. With the costs estimates in hand, and with knowledge of the importance of the features, the Customer lays out a plan for the project. Initial release plans are necessarily imprecise: neither the priorities nor the estimates are truly solid, and until the team begins to work, we won't know just how fast they will go. Even the first release plan is accurate enough for decision making, however, and XP teams revise the release plan regularly.
  2. Iteration Planning is the practice whereby the team is given direction every couple of weeks. XP teams build software in two-week "iterations", delivering running useful software at the end of each iteration. During Iteration Planning, the Customer presents the features desired for the next two weeks. The programmers break them down into tasks, and estimate their cost (at a finer level of detail than in Release Planning). Based on the amount of work accomplished in the previous iteration, the team signs up for what will be undertaken in the current iteration.

These planning steps are very simple, yet they provide very good information and excellent steering control in the hands of the Customer. Every couple of weeks, the amount of progress is entirely visible. There is no "ninety percent done" in XP: a feature story was completed, or it was not. This focus on visibility results in a nice little paradox: on the one hand, with so much visibility, the Customer is in a position to cancel the project if progress is not sufficient. On the other hand, progress is so visible, and the ability to decide what will be done next is so complete, that XP projects tend to deliver more of what is needed, with less pressure and stress.

Customer Tests

As part of presenting each desired feature, the XP Customer defines one or more automated acceptance tests to show that the feature is working. The team builds these tests and uses them to prove to themselves, and to the customer, that the feature is implemented correctly. Automation is important because in the press of time, manual tests are skipped. That's like turning off your lights when the night gets darkest.

The best XP teams treat their customer tests the same way they do programmer tests: once the test runs, the team keeps it running correctly thereafter. This means that the system only improves, always notching forward, never backsliding.

Small Releases

XP teams practice small releases in two important ways:

  1. First, the team releases running, tested software, delivering business value chosen by the Customer, every iteration. The Customer can use this software for any purpose, whether evaluation or even release to end users (highly recommended). The most important aspect is that the software is visible, and given to the customer, at the end of every iteration. This keeps everything open and tangible.

  2. Second, XP teams release to their end users frequently as well. XP Web projects release as often as daily, in house projects monthly or more frequently. Even shrink-wrapped products are shipped as often as quarterly.
It may seem impossible to create good versions this often, but XP teams all over are doing it all the time. See Continuous Integration for more on this, and note that these frequent releases are kept reliable by XP's obsession with testing, as described here in Customer Tests and Test-Driven Development.


Simple Design


XP teams build software to a simple design. They start simple, and through programmer testing and design improvement, they keep it that way. An XP team keeps the design exactly suited for the current functionality of the system. There is no wasted motion, and the software is always ready for what's next.Design in XP is not a one-time thing, or an up-front thing, it is an all-the-time thing. There are design steps in release planning and iteration planning, plus teams engage in quick design sessions and design revisions through refactoring, through the course of the entire project. In an incremental, iterative process like Extreme Programming, good design is essential. That's why there is so much focus on design throughout the course of the entire development.

Pair Programming


All production software in XP is built by two programmers, sitting side by side, at the same machine. This practice ensures that all production code is reviewed by at least one other programmer, and results in better design, better testing, and better code.It may seem inefficient to have two programmers doing "one programmer's job", but the reverse is true. Research into pair programming shows that pairing produces better code in about the same time as programmers working singly. That's right: two heads really are better than one!

Some programmers object to pair programming without ever trying it. It does take some practice to do well, and you need to do it well for a few weeks to see the results. Ninety percent of programmers who learn pair programming prefer it, so we highly recommend it to all teams.

Pairing, in addition to providing better code and tests, also serves to communicate knowledge throughout the team. As pairs switch, everyone gets the benefits of everyone's specialized knowledge. Programmers learn, their skills improve, and they become more valuable to the team and to the company. Pairing, even on its own outside of XP, is a big win for everyone.


Test-Driven Development


Extreme Programming is obsessed with feedback, and in software development, good feedback requires good testing. Top XP teams practice "test-driven development", working in very short cycles of adding a test, then making it work. Almost effortlessly, teams produce code with nearly 100 percent test coverage, which is a great step forward in most shops. (If your programmers are already doing even more sophisticated testing, more power to you. Keep it up, it can only help!)It isn't enough to write tests: you have to run them. Here, too, Extreme Programming is extreme. These "programmer tests", or "unit tests" are all collected together, and every time any programmer releases any code to the repository (and pairs typically release twice a day or more), every single one of the programmer tests must run correctly. One hundred percent, all the time! This means that programmers get immediate feedback on how they're doing. Additionally, these tests provide invaluable support as the software design is improved.

Design Improvement


Extreme Programming focuses on delivering business value in every iteration. To accomplish this over the course of the whole project, the software must be well-designed. The alternative would be to slow down and ultimately get stuck. So XP uses a process of continuous design improvement called Refactoring, from the title of Martin Fowler's book, "Refactoring: Improving the Design of Existing Code".

The refactoring process focuses on removal of duplication (a sure sign of poor design), and on increasing the "cohesion" of the code, while lowering the "coupling". High cohesion and low coupling have been recognized as the hallmarks of well-designed code for at least thirty years. The result is that XP teams start with a good, simple design, and always have a good, simple design for the software. This lets them sustain their development speed, and in fact generally increase speed as the project goes forward.

Refactoring is, of course, strongly supported by comprehensive testing to be sure that as the design evolves, nothing is broken. Thus the customer tests and programmer tests are a critical enabling factor. The XP practices support each other: they are stronger together than separately.

Continuous Integration

Extreme Programming teams keep the system fully integrated at all times. We say that daily builds are for wimps: XP teams build multiple times per day. (One XP team of forty people builds at least eight or ten times per day!)

The benefit of this practice can be seen by thinking back on projects you may have heard about (or even been a part of) where the build process was weekly or less frequently, and usually led to "integration hell", where everything broke and no one knew why.

Infrequent integration leads to serious problems on a software project. First of all, although integration is critical to shipping good working code, the team is not practiced at it, and often it is delegated to people who are not familiar with the whole system. Second, infrequently integrated code is often -- I would say usually -- buggy code. Problems creep in at integration time that is not detected by any of the testing that takes place on an un-integrated system. Third, weak integration process leads to long code freezes. Code freezes mean that you have long time periods when the programmers could be working on important shippable features, but that those features must be held back. This weakens your position in the market, or with your end users.

Collective Code Ownership

On an Extreme Programming project, any pair of programmers can improve any code at any time. This means that all code gets the benefit of many people's attention, which increases code quality and reduces defects. There is another important benefit as well: when code is owned by individuals, required features are often put in the wrong place, as one programmer discovers that he needs a feature somewhere in code that he does not own. The owner is too busy to do it, so the programmer puts the feature in his own code, where it does not belong. This leads to ugly, hard-to-maintain code, full of duplication and with low (bad) cohesion.

Collective ownership could be a problem if people worked blindly on code they did not understand. XP avoids these problems through two key techniques: the programmer tests catch mistakes, and pair programming means that the best way to work on unfamiliar code is to pair with the expert. In addition to ensuring good modifications when needed, this practice spreads knowledge throughout the team.

Coding Standard


XP teams follow a common coding standard, so that all the code in the system looks as if it was written by a single -- very competent -- individual. The specifics of the standard are not important: what is important is that all the code looks familiar, in support of collective ownership.

Metaphor

Extreme Programming teams develop a common vision of how the program works, which we call the "metaphor". At its best, the metaphor is a simple evocative description of how the program works, such as "this program works like a hive of bees, going out for pollen and bringing it back to the hive" as a description for an agent-based information retrieval system.

Sometimes a sufficiently poetic metaphor does not arise. In any case, with or without vivid imagery, XP teams use a common system of names to be sure that everyone understands how the system works and where to look to find the functionality you're looking for, or to find the right place to put the functionality you're about to add.


Sustainable Pace


Extreme Programming teams are in it for the long term. They work hard, and at a pace that can be sustained indefinitely. This means that they work overtime when it is effective, and that they normally work in such a way as to maximize productivity week in and week out. It's pretty well understood these days that death march projects are neither productive nor produce quality software. XP teams are in it to win, not to die.

Conclusion

Extreme Programming is a discipline of software development based on values of simplicity, communication, feedback, and courage. It works by bringing the whole team together in the presence of simple practices, with enough feedback to enable the team to see where they are and to tune the practices to their unique situation.

2001/09/06

Dig around to find ActiveX control? Try this - ActiveX Manager

ActiveX Manager is a utility software for ActiveX control registered on your local computer. I found it helpful when I dig around to find Sharepoint's upload control.

Below is a sample report generated for my box, which runs Windows XP Pro SP2, all up-to-date MS updates, Office 2003, VS.NET 2003 and 2005, SQL2003 and 2005, et al.

--------------------------------------------------------------------------------
Computer Name: xxxx
Generated On: Monday, January 30, 2006
Control Count: 159
--------------------------------------------------------------------------------

Control Name: Ref Edit Control
Version: 1.0
Status: Registered
ProgID: RefEdit.Ctrl
CLSID: {00024512-0000-0000-C000-000000000046}
TypeLib: {00024517-0000-0000-C000-000000000046}
File Location: C:\Program Files\Microsoft Office\OFFICE11\REFEDIT.DLL
File Size: 77824 Bytes
Created: 05/08/03 21:54:00
Modified: 05/08/03
Accessed: 01/27/06

--------------------------------------------------------------------------------

Control Name: Microsoft Data Bound Grid Control 5.0 (SP3)
Version: 1.0
Status: Registered
ProgID: MSDBGrid.DBGrid
CLSID: {00028C00-0000-0000-0000-000000000046}
TypeLib: {00028C01-0000-0000-0000-000000000046}
File Location: C:\WINDOWS\SYSTEM32\DBGRID32.OCX
File Size: 525352 Bytes
Created: 06/24/98 00:00:00
Modified: 06/24/98
Accessed: 01/30/06

--------------------------------------------------------------------------------

Control Name: Microsoft Office XP Web Components
Version: 1.0
Status: Registered
ProgID: OWC10.Spreadsheet.10
CLSID: {0002E551-0000-0000-C000-000000000046}
TypeLib: {0002E550-0000-0000-C000-000000000046}
File Location: C:\PROGRA~1\COMMON~1\MICROS~1\WEBCOM~1\10\OWC10.DLL
File Size: 7330360 Bytes
Created: 08/04/03 13:19:34
Modified: 08/04/03
Accessed: 01/27/06


--------------------------------------------------------------------------------


Control Name: Microsoft Office Web Components 11.0
Version: 1.0
Status: Registered
ProgID: OWC11.Spreadsheet.11
CLSID: {0002E559-0000-0000-C000-000000000046}
TypeLib: {0002E558-0000-0000-C000-000000000046}
File Location: C:\PROGRA~1\COMMON~1\MICROS~1\WEBCOM~1\11\OWC11.DLL
File Size: 8086072 Bytes
Created: 08/01/03 15:09:04
Modified: 08/01/03
Accessed: 01/27/06

and on...

2001/08/01

Introduction of Aglie Development

Introduction
I want to provide thorough information for the everyday coder - without the "I want to sell you something so I have to look extra smart" obfuscation layer. These are my personal views, acquired by analyzing my own development "challenges", browsing the web, discussing it at CP and elsewhere, and trying it myself. It won't be a "brief introduction", so here's an overview in case you want to skip something:

  • Where do we come from - two scenarios you might find yourself in
  • Agile Programming - introduction to "new old" principles
  • Refactoring Techniques - simple techniques, and an advanced real-life example
  • Selling to your Boss - how to convince your company
  • Limits of the Agile process - Where Agile Techniques are not applicable
  • Appendix
Where do we come from

We all know this: Your project has a neat design you're really proud of. You did care for all eventualities that came up in the early design studies, the schedule is approved, there's even an extra week "padding for the unexpected" - and you are happy you can finally start coding. Two weeks into it, the first change requests arrive. Nothing special, just the usual "can we do this, too?" - "Yes, no big problem, we just need to plug an Carbunkulator into the Arglebargle".

Halfway through it, things look less shiny. A few more functionality tweaks, a few bugs, your best coder one week in the hospital - the schedule lags behind big time. Your boss returns from a talk with a client, after they played around with the first beta. It turns out they never really needed an arglebarge, it is just in the spec because their old system had a big one that was very expensive. What they really need is a big gonkulator, and it must be fast - much faster than now. Oh, and the one feature that gave you headaches while designing - you can scrap that: the only one guy who insisted on this feature (although no one understood why) moved on to greener pastures.

Whatever the reasons - the application ends up different from what it was envisioned. Chances are, it's a mess of crooks and shortcuts across a baroque, utterly inefficient infrastructure. You might even get afraid of touching it - 'cause a little change here breaks something there. Every time you try to fix some nasty behavior, you have to wad through tons of interdependent code, and every function, every class you see screams "rewrite me". Far from what you wanted.

Interestingly, you can arrive at the same place by leaving out the formal design process altogether: You have an idea, a rough plan how you can make it, and start coding. It starts well, but after some time, it gets tricky: an important library refrains doing what you expect, some things didn't work out as you thought, you're forced to hold much more distributed state information than you can juggle in your head.

The whole thing turns out a bit fragile, and although it mostly does what you want it to, it's a pain to use. As much as it's brittle to the user, the code feels brittle to you, probably no one will be able or willing to continue working on it, you're reluctant to change anything yourself, because, once you start to weed out the crooks, you wish you had the strength to start over again.

What went wrong? In the first scenario, the design (likely perfect for the initial requirements) did not live up to the changes that are inevitable in the course of a project. In the second, a reasonable design failed to evolve.

The solutions I discuss here are aimed at the course of the project, to help you avoid situations like this. Once you are stuck with a huge unmaintainable code base, it's much harder to stay on the success track (or get back on it again). At least, even when you feel you're stuck, many of the techniques here can help you not to give up on the way - neither economically nor stress-wise.

What is Agile Programming

AP is a collection of principles and techniques that try to overcome the inflexibility of the strictly-design-based development cycle. Three things make AP very powerful:

You are not required to model the entire development process after AP (of course you can). You can change project management slowly and incrementally, and you need to adopt only what really helps you.

The Agile process does not require extreme excellence at design or development - rather, it's aimed at the average team with some experience.

The techniques are simple, so simple that most old-timers consider them "common knowledge" - if only they were!

Here is what I understand as the core rules:

  • Simple Design: use the simplest design that solves your immediate needs
  • Design as you go: Always scrub and exercise the code you work on while the project develops, to make sure it remains well structured, designed and written. (Techniques for this are called Refactoring)
  • Incremental steps: When changing or adding code, take the smallest step you can, then compile and test again.
  • Independent steps: Don't mix up the things you do - when you fix a bug, fix the bug, when you add a feature, add the feature.
  • Know and use your tools with purpose: Especially for tasks beyond writing code - like design and documentation, know the available tools, use those that help you (not just a single one), and always understand why you do what you do.

The Meta Rule: Use only the principles and techniques that actually work for you.

Simple Design and Design as you go

I considers this the very heart of the AP approach - and the one with the biggest potential to change the development process.

Instead of planning ahead for all nooks and crannies, make sure "Version 0.1" works out well. Concentrate on your next task, and pick the most simple design that makes it possible. This does not mean forget about design! Design remains an important part of the entire process, and classic good/bad rules still apply. The additional rule is: make your next step happen, not the 10th. Don't go far out of your way for something you think you need later. When you really need it, new possibilities will have opened, and priorities sure will have changed.

To keep the design evolving with the project, you always need to pay attention to the code base. With only some primitive techniques and trust in your instincts, you can get along very well for most of the time - so you're less burdened when you have to face te real challenges. Exercising the part you're working on means: over time the "hot spots" of your application get most attention automatically.

Although individual things, like renaming variables, might appear silly as itself, the cumulative effect is impressive. It's wonderful when the feeling of understanding your code base kicks in - don't miss it!

The initial design will have a great impact on your project as well (although you typically end up more flexible than with a strict design based approach). But don't worry too much: Different designs can support the same product, a simple one will give you something to work with, and refactoring will make sure your design grows with the application.

If the analogy is allowed: Agile Modeling is replacing the intention of a "perfect creation" with an evolutionary process: Although 7 neck vertebras can't be the perfect design for both the mouse and the giraffe, it does it's job very well in both cases.

Advantages

  • You can react much more flexible to requirement changes and additions
  • The overall design remain simple almost "by itself" - baroque arabesques are usually rooted out very early, before they grow big
  • By scrubbing the code you're working on, the most important parts get most attention, and you don't invest extra time into changing what doesn't need to be changed.
  • When cleaning up your code is technically part of the development process, you have much better chances to end up with a well commented and documented orthogonal readable code base
  • You might be able to start coding earlier (although you won't necessarily be faster overall)
  • You won't end up in the dead ends
  • A good designer/developer can achieve the same with a "less agile" approach. But chances are, a wizard will get very close to the agile approach himself, if you let him do as he pleases. And for us non-wizards, we're all fallible to the stress and strains of development, and forget to follow idolized "good practice" in those dreaded one-nighters.

    Incremental, independent Changes

Incremental changes are the key to happiness, and the core idea of refactoring. However, I want to separate the principle from the techniques, that's why it gets it's own paragraph. To repeat the two rules:

Take the smallest step possible into the direction you want to go. Then compile and do a basic test that it's still working. And always do only one step - don't try sneak in a feature while you refactor - tempting as it may be.

For me, these rules still require some discipline, and a conscious effort. Sometimes it just seems easiest to scrap a class, and write it anew. Yet, when I get interrupted, it's much easier to say "five minutes" - and finish the search&replace at hand; or jot down a quick note what I was doing. When I return to my desk, I can continue without looking back and forth where I left of, without the fear I forget something.

Advantage: You always have working code you can deliver. Don't take this literally and skip QA - but in case of emergency (e.g. a bug at a customer site) you're much more ready to leave your current task in a working condition. In-house testing can get a new version anytime. You are quicker to react to new requirements: No more "I need to finish the Gonkulator rewrite before I can add this graphic feature that everybody suddenly seems to need urgently."

Also, your code passes much more often through the compiler, and a basic "does it work?" test - especially so if you do Automated Unit Testing. This gives a bit more confidence in complex code, and can be a real live saver.

There's one human reason behind this rule: Only a limited amount of state information is present in your mind (the often-mentioned "seven things"). Conscious splitting into steps with the least state information tries to saves you from a "short term memory overflow", which makes you forget things you wanted to do, and feel overwhelmed by the complexity of the code. And there is a Murphy reason: Every step you take will be a little bit more complex, have a few more dependencies and side effects than you expected. E.g. when rewriting two classes into one, a problem with header inclusion order can sidetrack you so far that you just forget to initialize an important variable again.

Know your Tools, and know your reasons

Besides writing code, many things belong to the development process: Design, Documentation, QA...

The first question should be: Why do I do that? The importance of these artifacts is as well known as a rich number of techniques and methods for them, that all to often claim or at least suggest to be exclusive. But, to take an example: why do you actually document your code? Do you still want to understand your code in 6 month? Should a 3rd party be able to write plugins based on your API? Is it to inform co-workers of changes in the interface or implementation specifics? Is it because you plan to retire to the Bahamas, so the code base needs to be passed on to a still-to-be-hired guy? These are quite different goals, and for each of them, different techniques are appropriate.

In the example, documentation comes in many flavors. UML charts, formal code comments that can be extracted by a parser, inline comments, a separate Word file describing your intentions, Source Control change logs, etc. You are much better off when you understand and use more than one tool. Look out for new tools, and don't forget about unused features of the tools you have.

Advantage: The time spent on non-coding tasks is used more effective, and doesn't feel wasted. Again: It's just to make you happy!

Refactoring Techniques

Refactoring is nothing magic, refactoring is a fancy word for cleaning up the code. A more formal definition would be:

Refactoring means continuously improving the design and appearance of your code base in small steps confined to surveyable areas.

All techniques are allowed that:

  • improve code quality, readability, design
  • are simple, or even "dumb" (such as automatic search-and-replace of a variable name)
  • are small, and independent steps

Refactoring has two major uses: first, to keep an application well designed, to enable the "design as you go" principle. Second, instead of rewriting a larger module or class, you can refactor it into something much better. This requires much more discipline (controlling one's enthusiasm to make it better) than a rewrite, but is often the less risky yet more rewarding route.

I split the discussion in two parts - a formal list of basic techniques, and a real life example that contains suggestions for less automatable ones.

Basic Refactoring Techniques

Rename a variable / type / class / function

Every developer or team has it's coding standards - usually both formally defined and informal. Apply them to your code! If you have a function ReadData, and a complementary function DataWrite - rename one, so they are consistent. if you have a member that misses the m_ - prefix everyone else uses, spend the one or two minutes to change that. When you plan to change multiple identifiers, change only one at each step then compile and run. Use unique names - so when you forget to rename one place, the compiler catches it. (Oh, if the function is in an interface declaration shared by all modules of your 10-developer-project, ask your co-workers before you do!)

Reformat a function to conform to your coding standards

We want readable code - make it so! All-nighters tend to produce interesting, almost-working code that's horrible to understand. We don't want to throw it away, so first apply some formal beatification to it, then look deeper.

turn a code sequence into a function

If the complexity of a method increases beyond what makes you feel well, or if you notice that similar functionality is used at different places, make it a function.

move functionality shared by multiple classes to a common base class (or helper class)

This can break down the complexity of a single class back to a reasonable level.

Separate independent functionality into different classes / functions

The inverse of the above.

Notice a theme in c-e: We introduce a base class only when it seems necessary. Early design decisions are often intentionally immutable: because the design guru said it so, because it was the result of heated discussions, etc. In this course, the technical reason for a decision often gets lost, and with it: simplicity.

All these steps will take around 5 - 10 minutes - usually including "compile and test". You can take them anytime: when you're bored, while you're waiting for another project to compile, when you don't want to leave shortly before your boss. Whatever. Even taking one step will make your code base a little bit better, and you will have working code. They are easily undone (assuming you know to use your tools: editor, and source control)

While the decision what to do requires that you understand the structure of the code you're working on, executing it does not: they are simple search-and-replace or copy-and-paste tasks, and under VS.NET there are nifty tools available that can automate them safely.

Also, AP does not tell you how to design, only when. You still need to know what makes a good design, and find it yourself.

Other Refactoring techniques - A real life example

When I plan to refactor a complex class or module, I start with the things mentioned above. This has two purposes: First, the code gets easier to read, more compact, and unnecessary arabesques are removed in these steps, so I have a much easier time later on. Second, I get fairly accustomed to the class again, refreshing my memory. I find out which members are hot spots, discover old comments telling me what I wanted to do, etc.

Only when I'm through with the basics, I begin the actual changes. Again, I try to take the smallest step that takes me closer to my goal and keeps the code working. Here you need to be more creative - the techniques are not that straightforward anymore, and you need to plan ahead. That's why I'll take a real example, to illustrate some possibilities.

Recently, I refactored a class implementation that simulated a map<int, struct> by two arrays: a data array holding the values, and a key array, holding the key for each value at the same index as the data array. To speed things up, I tried to store the values at their "native" position: e.g. the value for key 17 I would first try to insert into index 17. To look up a value, I checked the "native position", then I had to search the key array for the index where the key was stored, then retrieve the value from the same index in the data array. The whole thing looked like this:

if (keyArray.size() > key && keyArray[key] == key)

// look up "native" position

return dataArray[key];

else {

int index = FindKeyInKeyArray(key); // linear search! (ugh)

if (index >= 0)

return dataArray[index];

}

(This atrocity to common sense grew from a quick side hack into a generic datakeeper class. I'm really ashamed of this - well, no more)

The first step were to rename the arrays (originally named data and map) to the ones above, so I wouldn't get a name clash later on - neither in the code, nor in my mind.

Ultimately, I would have to remove the keyArray index lookups completely, and replace the dataArray lookups. So I did a "Find in Files" for "keyArray[" and "dataArray[", just to see how often they were used. I was shocked - over 20 times each. I needed to break this down a bit further, before I "injected" the map<>.

So I moved some rarely used extra functionality that affected most functions to a derived class - due to the prior usage this wouldn't break any client code. While this moved no "hot spots" out of the class, the complexity of the hot spots itself was greatly reduced. Compile and run - still working. (Later I found I introduced a bug in this step, that even escaped my quickly written unit test. But due to the new cleaner code structure, it was found quickly).

The remaining lookup complexity, especially when inserting/changing values, was dominated by the "native position" handling - it probably didn't help much, and made everything ugly. I decided to remove this altogether. While the code would still work, performance might take a hit - this was a small risk I had to take. The worst thing that could happen would be rolling back to before this step (so I made a check-in at this point).

After removing the extra lookup, most of the hot spot functions did something similar to this:

int index = MapID(key); // lookup the key

if (index >= 0) { // when found...

// do something to dataArray[index]

}

else { // when not found...

// do something else

}

I figured, to replace this with a map, it wouldn't be a simple m_map[key] - the dataArray[index] was often used multiple times but I wanted the map lookup to happen only once, and I didn't need the operator[]'s feature to insert a new element silently. So I wrote a helper function, that contained all the functionality that I intended to change:

ValueType * GetValPtr(int key) {

int index = MapID(key); // lookup the key

if (index >= 0) { // when found...

return dataArray[index];

else

return NULL;

}

And started replacing the lookups by

ValueType * pVal = GetValPtr(key);

if (pVal) { // when found...

// do something to *pVal

}

else { // when not found...

// do something else

}

Again, very simple replacements, especially since I had made sure before local variable and parameter names are consistent. I renamed dataArray and MapID() in the class declaration and the GetValPtr implementation, so the compiler caught all occurrences where I was still relying on them. I picked "pVal" as name for the new local variable, since this name was used nowhere in the class.

After this step, I had a sleek implementation of a horrible idea. Quite an improvement.

Everything worked fine, so I took the last step: introducing an std::map<int, ValueType> member into the class, commenting out the the dataArray and keyArray declaration, and replacing the GetValPtr implementation with a std::map.find call:

ValueType * GetValPtr(int key) {

std::map<int, ValueType>::iterator it = m_map.find(key);

if (it == m_map.end())

return NULL;

else

return &(it->second);

}

Of course, replacing the two arrays with a map had some other side effects, temporarily breaking the storage functions (that needed to iterate over all values), and turning the array allocation/cleanup functions into syntax errors. This was a single big step, I had no ideas how to break this down further (and maybe started to get a little bit impatient). But due to all the preparation, it took no more than 40 minutes to do the change, replace the keyArray iteration with an map iterator, and get the code compile and run again. The thing is working fine now, I felt very happy, and I sleep much better.

While scrubbing the code, I marked commented-out sequences with a special comment tag, so I could search for these places. Thus, removing all the dead code (that I left in initially for reference and rollback), was a matter of a minute or two.

Of course, a few things still could be done. There's still a naming inconsistency in the "insert new item" implementation, and the GetValPtr function could be removed altogether, replacing the ValueType * with anmap::iterator. But the task at hand was done, and a new task was waiting for the next day, so I left it at that.

Refactoring techniques used in the example

A short overview of the things I used:

  • Move "hot spot" functionality to be changed to a helper function, that has a the same calling syntax for the old and the desired new implementation - so you separate syntactic changes at many places (that are semi-automatic and can be caught by the compiler) from functional changes (that need to be tested if they still do the same)
  • Move functionality to be replaced "inline" to a temporary helper function that you can remove later
  • Use "Find in files" to find occurrences of a certain construct in your project - so you find hot spots, and know if you can replace it in one step.
  • Pick names that make the compiler catch mistakes, or places you forgot to change
  • Use simple refactoring techniques, like generalizing variable names, until you feel you can handle the complexity of the trickier steps

    Selling to your boss

OK, since you didn't fall asleep yet, you'll probably pondering one question: How do you convince your boss that renaming variables is worth your pay?

  1. The best selling point is success.
    Just try some of the techniques and ideas presented here on a small scale. In an ideal situation, they help you solve a tricky problem efficiently - maybe one that has been bugging your team for a time. Your boss might ask you "Nice! How did you do that?" Just mention that you "tried some new techniques you read about recently"...
  2. Refactoring is a fancy word for cleaning up code.
    There is a reason to use a fancy word: it sounds new, it sounds smart, and it makes you think about "usual things" from a different perspective. "Agile Programming" and Refactoring are buzzwords, chances are, your boss might already have heard something of this and wonder if he misses something.
  3. Unless you have a very strict development process, Agile techniques can sneak in step-by-step. A key point of all Agile techniques is: only do what works for you. You don't have to revolutionize the entire development process. Start with "Incremental changes" for tasks assigned to you. If your tasks is to rewrite something, consider refactoring it instead. Try new tools, and unused features of existing tools, first for minor design and documentation tasks.
  4. Remember the prime strength and original intent of Agile Programming: Additional flexibility towards requirement changes. Requirements do change over time. Clients can change their priorities at a large scale after trying the first beta. New features need to be added. 3rd party components (libraries, or OS components) change over time.

    Limits of the Agile Process

AP is not the holy grail either. There are some requirements that must be met to make it work:

  • You need an open, friendly team
    If you have to stand mind games among the coders, if communication is bad, or if your co-workers take changes to "their" code as personal insults, it won't work.
  • You need some experience in the team
    While you may not need a design ueberguru, you need a decent amount of real-live experience in your team. AP can stand a certain percentage of newbies, but if your 10-headed team consists of 9 freshmen and one experienced developer to guide them, you're probably better off with a more formal approach
  • AP alone is not sufficient
    You will need other techniques. Focusing solely on AP techniques, you can quickly loose the "big picture" of your application. bad thing - you still need to know what you do, how things interact etc. AP is one tool, to make some of these tasks easier.
  • Refactoring won't change the construction plans
    The basic structure of your code base can rarely be changed through refactoring. Usually, you can work towards something that might even look completely different, but uses the same basic mechanisms as the old code. If the implementation is good but the structure is wrong, a rewrite might be faster. Relying on AP alone might stall the large-scale changes that are necessary from time to time.
  • AP doesn't tell you how to design
    Although certain techniques became popular together with AP (designing around user stories, design patterns, etc.), there is no formal mechanism. As I said, old design principles still hold true, but some designs work better with AP than others.


  1. Appendix

Links

  1. Here on CP, Marc Cliftons Organic Programming Environment and Automation Application Layer are well worth reading if you're looking for design concepts. According to Marc, they go along very well with agile techniques. (Sorry to the CPians with valuable related articles - I'm just not aware of them. If you know a related article, why not leave a comment?)
  2. The WIKI - An interesting "open database" mainly concerned with modern design and development techniques - a good starting point is WhatIsRefactoring
  3. Agile Modeling - A very good web site, with much more information than I can (or want to) present here, well written and not too heady.

    Why is Refactoring called Refactoring?

Although there are different explanations, the one that feels most natural to me is this one: Refactoring stems from the mathematicians "desire" to reorganize a term like

F = xyz + 2xy -7xz + 3yz - 14x + 6y - 21z - 42

into it's factors:

F = (x+3)*(y-7)*(z+2)

While both are absolutely identical, the second one exposes it's inner structure and important information on one look. Also, there are parallels between the processes.

2001/04/24

CSS Design: Taming Lists

As early as July of 1999 I was pontificating on email lists about the virtues of style sheets. Some things never change.

What has changed is how I think about CSS, and the underlying structure of (X)HTML to which it is applied. For example, I find that most pages on the web contain a menu of links in a navigation area. These are often marked up as a string of links, often in separate DIVs or paragraphs. Structurally, however, they are a list of links, and should be marked up as such.

Of course the reason that we don’t mark them up in that way is that we don’t want a bullet in front of every link in our navigation area. In this article, I'll demonstrate how to use CSS to bring unwieldy lists under control. It’s time for you to tell lists how to behave, instead of letting them run wild on your web page.


Setting the stage

For purposes of this article, I am using unordered lists. The same CSS can be applied, with similar results, to ordered lists as well. Unless otherwise defined, all of the examples in this article use the following code for the lists.

<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5 we'll make a bit longer so
that it will wrap</li>
</ul>

Each list is simply placed inside a different DIV, and the CSS is written so that the list’s behavior is determined by the DIV it is in. Each DIV has a base rule:

#base {
border: 1px solid #000;
margin: 2em;
width: 10em;
padding: 5px;
}

Without any additional styles applied, the list is rendered in this way in the base DIV:


  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5 we'll make a bit longer so that it will wrap

Positioning


Sometimes the default indent of a list is too much for the design you are working on. But simply changing the margin or the padding of the UL doesn’t work for all browsers. To make the list flush left, e.g., you need to change both the margin and the padding. This is because Internet Explorer and Opera opted to create the indent with the left margin, while Mozilla/Netscape use padding. For more on this see the DevEdge article Consistent List Indentation.


In the following example both the margin-left and padding-left of the UL in the DIV are set to zero:




  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5 we'll make a bit longer so that it will wrap

Note that the markers lie outside of the DIV. If the containing box were the BODY of the HTML document, the markers might be rendered outside of the browser window, in effect vanishing. If you want the markers to line up inside the DIV, but along its left side, set either the left padding or margin to one em:


  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5 we'll make a bit longer so that it will wrap

Markers


Maybe you've had a project that required a custom bullet. If so you might have marked it up in a table with one column containing the GIF image bullets aligned top and right, and the other column containing the content of what should have been LIs. With CSS it is possible to use an image as a bullet. If the browser doesn’t support this part of CSS (or doesn’t do images), the default bullet will be used (or you can specify a different HTML bullet if you wish).

The rule looks something like this:

ul {
list-style-image: url(bullet.gif);
}

And the browser renders it:

  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5 we'll make a bit longer so that it will wrap

To specify an HTML bullet to use if the browser doesn’t support this part of CSS, add:

 list-style-type: disc;

to your rule. Depending on the image that you choose you may find that it doesn’t align itself with the list items the way that you intend. In that case you may choose to have the image be placed within the list item block (rather than outside the block). Adding the following:

 list-style-position: inside;

to your rule will make that change. These three declarations can be combined into a single, shorthand declaration as illustrated in the following rule:

ul {
list-style: disc url(bullet.gif) inside;
}

which is the equivalent of:

ul {
list-style-type: disc;
list-style-image: url(bullet.gif);
list-style-position: inside;
}

This is what it looks like in the web page:

  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5 we'll make a bit longer so that it will wrap

There may be times when you have a list, but you don’t want any bullets, or you want to use some other character in place of the bullet. Again, CSS provides a straightforward solution. Simply add list-style: none; to your rule and force the LIs to display with hanging indents. The rule will look something like this:

ul {
list-style: none;
margin-left: 0;
padding-left: 1em;
text-indent: -1em;
}

Either the padding or the margin needs to be set to zero, with the other one set to 1em. Depending on the “bullet” that you choose, you may need to modify this value. The negative text-indent causes the first line to be moved to the left by that amount, creating a hanging indent.

The HTML will contain our standard UL, but with whatever character or HTML entity that you want to use in place of the bullet preceding the content of the list item. In our case we'll be using &#187;, the right double angle quote: ».

  • » Item 1
  • » Item 2
  • » Item 3
  • » Item 4
  • » Item 5 we'll make a bit longer so that it will wrap

I should point out that Netscape6/7/Mozilla (and other Gecko-based browsers) and Opera can create generated content via the CSS2 :before pseudo-element. We can take advantage of this to automatically generate the » character (or any other character) for the bullets. This allows us to leave the content of the UL alone. If you are using Opera or a Gecko-based browser, the following CSS will create the same list as above, but using the standard UL with no extra content:

#custom-gen ul li:before {
content: "\00BB \0020";
}

The content property may contain strings, URIs and more, including special characters. When using these characters, like », it is necessary to encode them as their escaped HEX equivalents. For the right double angle quote, we use \00BB (the other character, \0020, is a space). The final result (remember, the character will only be visible in Opera or Mozilla/Netscape):


  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5 we'll make a bit longer so that it will wrap

Truly inline lists


Who says a list needs to be vertically aligned with bullets hanging off the left side of each item? Perhaps you want the structure of an ordered list of links, but visually you want it to look like a vertical navigation bar on the web page. Or maybe you want your list of links to align themselves horizontally across the top of your page.

This applies to more than just lists of links. There are times when you might need to list several items in the midst of a paragraph, maybe a list of books that you want to read. Structurally it makes sense to mark this up as a list, but presentationally you might not want break the flow of the paragraph. CSS to the rescue again!

Since this list will not be separate and unto itself, I won’t put it into the base DIV that the previous lists have inhabited. This time the markup will be a paragraph, followed by the same list, followed by another paragraph.

I hear you crying,“FOUL! I thought you were going to put a list inside of a paragraph, not between two paragraphs.”

To which I reply,“Well, yes. But (X)HTML does not allow a list to appear inside of a paragraph. However, with the help of our style sheet, that is how it will look in the web page.”

Here’s what the styles look like:

#inline-list {
border: 1px solid #000;
margin: 2em;
width: 80%;
padding: 5px;
font-family: Verdana, sans-serif;
}

#inline-list p {
display: inline;
}

#inline-list ul, #inline-list li {
display: inline;
margin: 0;
padding: 0;
color: #339;
font-weight: bold;
}

The markup consists of a <div id="inline-list">. This DIV contains a paragraph followed by our standard UL, and a followup paragraph. The UL list has been modified so that each list item has a comma after it, with the last item followed by a period.


The results are below (list appears bold and blue):

A bit of text before the list appears. Perhaps the context is something about a husband getting a call from his wife to pick up a few things on the way home from work. It doesn’t really matter, for our purposes we just need some preceding text before the list:


  • Item 1,
  • Item 2,
  • Item 3,
  • Item 4,
  • Item 5 we'll make a bit longer so that it will wrap.

And then there is the text that follows the list in the paragraph. One or two sentences is sufficient for the example.

As in the custom bullet example above, we could use CSS to automatically generate the commas and period that follow each list item. If all you had to worry about were Opera and Gecko powered browsers, that is. This time the styles would look like:

#inline-list-gen ul li:after {
content: ", ";
}

#inline-list-gen ul li.last:after {
content: ". ";
}

Here we use the :after pseudo-element to add a comma after each list item, and a period after a list item with class="last", resulting in the following (remember, it will only be visible in Opera or Mozilla/Netscape):

A bit of text before the list appears. Perhaps the context is something about a husband getting a call from his wife to pick up a few things on the way home from work. It doesn’t really matter, for our purposes we just need some preceding text before the list:


  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5 we'll make a bit longer so that it will wrap

And then there is the text that follows the list in the paragraph. One or two sentences is sufficient for the example.

Navigation

As I mentioned previously, the menus of links that appear on nearly every site should really be marked up as lists, since that is what they are. Since we usually don’t want the default list style to apply to these links, we can use CSS to change the way they appear on the page. As we saw above, lists can be forced to display horizontally (inline) rather than stacked vertically (the default behavior). When you do this the bullet goes away and you have many choices about how to separate the list items.

These examples of horizontal lists will all use the same base DIV with the following styles:

#h-contain {
padding: 5px;
border: 1px solid #000;
margin-bottom: 25px;
}

The next two examples use the same UL as in the previous examples, but without the final list item with its extra text. They also include an additional class that sets apart one of the LIs in the list.

Borders

A pipe character, , is often used to differentiate between choices. It is an obvious separating character, and can be emulated by adding borders to list items:

#pipe ul {
margin-left: 0;
padding-left: 0;
display: inline;
}

#pipe ul li {
margin-left: 0;
padding: 3px 15px;
border-left: 1px solid #000;
list-style: none;
display: inline;
}

#pipe ul li.first {
margin-left: 0;
border-left: none;
list-style: none;
display: inline;
}
Here we add class="first" to the first LI so that it does not end up with a border on its left side.



  • Item 1
  • Item 2
  • Item 3
  • Item 4

You can modify these styles to create a tabbed navigation effect:

#tabs ul {
margin-left: 0;
padding-left: 0;
display: inline;
}

#tabs ul li {
margin-left: 0;
margin-bottom: 0;
padding: 2px 15px 5px;
border: 1px solid #000;
list-style: none;
display: inline;
}


#tabs ul li.here {
border-bottom: 1px solid #ffc;
list-style: none;
display: inline;
}



  • Item 1
  • Item 2
  • Item 3
  • Item 4

In this example adding class="here" to an LI creates a bottom border that matches the background color to indicate that the tab refers to the current page.


Note: This technique was first proffered by Randal Rust, and then riffed on by many on the css-discuss email list


Breadcrumb trails


Another list of links that typically has a horizontal orientation on a web page is what has become known as breadcrumbing. Breadcrumbs show you where you are in the hierarchy of a site, starting with the home page and drilling down to the current section or page. If you really want to make the markup meaningful, you would want to create a series of nested lists, since each new section is part of the section before it:

<div id="bread">
<ul>
<li class="first">Home
<ul>
<li>&#187; Products
<ul>
<li>&#187; Computers
<ul>
<li>&#187; Software</li>
</ul></li>
</ul></li>
</ul></li>
</ul>
</div>

creates the following:




  • Home

    • » Products

      • » Computers

        • » Software

Adding the following rules to the style sheet for the page:

#bread {
color: #ccc;
background-color: #006;
padding: 3px;
margin-bottom: 25px;
}

#bread ul {
margin-left: 0;
padding-left: 0;
display: inline;
border: none;
}

#bread ul li {
margin-left: 0;
padding-left: 2px;
border: none;
list-style: none;
display: inline;
}

creates this:




  • Home

    • » Products

      • » Computers

        • » Software

Again, we can generate the » character (or any other character you might want to use as a separator) with the :before pseudo-element, combined with a class="first" so that the first LI doesn’t generate a separator:

#bread-gen ul li:before {
content: "\0020 \0020 \0020 \00BB \0020";
color: #ff9;
}

#bread-gen ul li.first:before {
content: " ";
}

And the end result:




  • Home

    • Products

      • Computers

        • Software


In the Real World


I'd like to end with a real world application of some of the techniques that have been discussed here. We'll use a standard UL containing links to create a dynamic menu with hover effects. In order to obtain the hover effects we'll let the UL provide the structure, and the anchor styles will provide most of the visual effects.



This menu of links is actually a solution to a question posed by Michael Efford on the css-discuss list. Michael had created this exact effect using a table, images, and JavaScript. He asked the list if it could be done with CSS. I took the challenge, and with the help of several other members who tracked down some browser specific issues, we came up with a style sheet that works on this markup:

<div id="button">
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">Hidden Cameras</a></li>
<li><a href="#">CCTV Cameras</a></li>
<li><a href="#">Employee Theft</a></li>
<li><a href="#">Helpful Hints</a></li>
<li><a href="#">F.A.Q</a></li>
<li><a href="#">About Us</a></li>
<li><a href="#">Contact Us</a></li>
</ul>
</div>

Let’s look at the style sheet rule by rule, and I'll explain why each rule is constructed the way that it is.

#button {
width: 12em;
border-right: 1px solid #000;
padding: 0 0 1em 0;
margin-bottom: 1em;
font-family: 'Trebuchet MS', 'Lucida Grande',
Verdana, Lucida, Geneva, Helvetica,
Arial, sans-serif;
background-color: #90bade;
color: #333;
}

The first rule is for the #button DIV. It defines the space that the menu will occupy, and provides a context for the menu so that we can define the way the list and links will behave inside the DIV. I chose to make the menu fluid, based on the browser’s font size preferences, so (almost) all units are in ems. This includes the width of the menu. The solid black border on the right was based on the original design from Michael. The bottom padding is there to extend the DIV down beyond the menu of links so that you can see the background of the DIV. Again, this follows the original design. The bottom margin is to separate the DIV from what follows it. The colors came from the original design.

 #button ul {
list-style: none;
margin: 0;
padding: 0;
border: none;
}

#button li {
border-bottom: 1px solid #90bade;
margin: 0;
}

Next I defined what the list will look like. Since all the list items were to be links, and the rollover functionality would be built into the CSS for the links, I essentially removed all styling from the lists. I did add a single pixel border on the bottom of each link that matched the background of the #button DIV, to work as the separator. In the original design, this was an image.

 #button li a {
display: block;
padding: 5px 5px 5px 0.5em;
border-left: 10px solid #1958b7;
border-right: 10px solid #508fc4;
background-color: #2175bc;
color: #fff;
text-decoration: none;
width: 100%;
}

html>body #button li a {
width: auto;
}

#button li a:hover {
border-left: 10px solid #1c64d1;
border-right: 10px solid #5ba3e0;
background-color: #2586d7;
color: #fff;
}

Finally, I defined the links. The original design has 10 pixel borders on the right and left. These borders, along with the background, change color on the rollover. This is a relatively simple thing to control with the :hover pseudo-class in CSS, so I put this style into the anchor styles.


There is one workaround in this part of the style sheet. To make the links active for the full width of the DIV, I made them display: block;. This works for everything but IE/Windows. If you give the block an explicit width of 100%, then IE/Windows plays along. But doing this creates problems with IE5/Mac and Netscape/Mozilla. So I used the child selector“>” to redefine the width to auto. Since IE/Windows doesn’t understand child selectors, it ignores the rule. IE5/Mac, Opera and Netscape/Mozilla follow the rule, and everyone is happy.


The rule for the :hover pseudo-class creates the color changes on the backgrounds and borders when the links are moused over.


The style and list markup (about 1K worth) replaced about 5K of JavaScript and TABLE markup, not to mention another 8K or so of images for the rollover effects. It also made the markup more readable, and easier to update, since you no longer need to create new images if a link name changes. Now you simply modify some text.


Tip of the Iceberg


Believe it or not, we have just scratched the surface of what can be done to modify lists with style sheets. I won’t claim that all of the techniques presented here are the most practical CSS that you'll come across, but I do hope they make you think about how using CSS can release you to use more structured markup.

2001/02/03

Mastering the Requirements Process

by Suzanne Robertson, James Robertson (Hardcover)
Addison-Wesley Professional; 1st edition (August 12, 1999)

Editorial Reviews

Amazon.com
Written in an engaging style and relevant for any software analyst or designer, Mastering the Requirements Process provides a powerful and useful guide to defining more complete software requirements that lead to better software overall. It's also filled with innovative advice.

The heart of this book is the authors' Volere Requirements Process Model, a step-by-step guide to gathering your requisites. Throughout this book, the authors use this process to explicate a single case study--a system for a municipality that will optimize the de-icing of roadways during snowy weather. Along the way, the book provides a solid guide to identifying and refining requirements, both functional and nonfunctional (such as performance and ease of use).

There are many excellent ideas in the book, including the notion of fitness for your requirements, which can be later used to track whether the software is successful. The book also wisely separates technology from requirements so that analysts can concentrate on understanding and modeling business problems instead of moving right away to the nuts and bolts of implementation. Even if you don't adopt the Volere model in toto, you can benefit from the concepts of "trawling" (a metaphor for the requirements-gathering process), quality gateways (in which tentative requirements are evaluated for inclusion in a project), and the wise use of patterns to help simplify the process.

Anchored by numerous examples (including many samples of successful requirements), the book provides an appealing mix of new ideas along with a remarkably clear presentation. In short, Mastering the Requirements Process provides useful advice that can make the project specification building phase of the software process easier and more robust. It provides the first steps for improving overall software quality for your organization. --Richard Dragan

Topics covered: Volere Requirements Process Model; project blastoff; determining requirements; user and stakeholders; project constraints; requirements constraints; use cases; business events; adjacent systems; innovation; trawling for requirements: apprenticing, interviews, and videotape; functional and nonfunctional requirements; fit criteria; quality gateways; traceability; prototyping and scenarios; low and high fidelity prototypes; patterns and requirements reuse; improving the requirements gathering process.

Product Description:
Written by two internationally acclaimed experts on requirements, Mastering the Requirements Process provides software engineers with the practical insights, techniques and templates to discover exactly what their customers desire for their systems. It also explains how to implement an easily learned, ongoing forma requirements process which allows the requirements to evolve over the life time of the project. Using this book you will learn how to ask the right questions, how to determine whether or not the final solution will satisfy the requirements, how to fit the solution to the requirements to provide high quality products and even how to reuse requirements. The result is, systems that the user loves to use!

2001/01/15

Code Complete, Second Edition

(Paperback - June 2004)
by "Developing computer software can be a complicated process, and in the last 25 years, researchers have identified numerous distinct activities that go into software development..." (more)

Editorial Reviews

From Book News, Inc.
For this second edition of a practical guide to programming, McConnell, a software engineer, describes new practices and offers hundreds of new code samples illustrating software construction. Capturing the body of knowledge available from research, academia, and everyday commercial practice, he synthesizes techniques and principles for programmers of every experience level, development environment, or project size. Material is in sections on laying the foundation, creating high-quality code, variables, statements, code improvements, system considerations, and software craftsmanship. Numerous tips, key points, and checklists are included.Copyright © 2004 Book News, Inc., Portland, OR

Product Description:
For more than a decade, Steve McConnell, one of the premier authors and voices in the software community, has helped change the way developers write code--and produce better software. Now his classic book, CODE COMPLETE, has been fully updated and revised with best practices in the art and science of constructing software. Whether you're a new developer seeking a sound introduction to the practice of software development or a veteran exploring strategic new approaches to problem solving, you'll find a wealth of practical suggestions and methods for strengthening your skills. Topics include design, applying good techniques to construction, eliminating errors, planning, managing construction activities, and relating personal character to superior software. This new edition features fully updated information on programming techniques, including the emergence of Web-style programming, and integrated coverage of object-oriented design. You'll also find new code examples--both good and bad--in C++, Microsoft(r) Visual Basic(r), C#, and Java, though the focus is squarely on techniques and practices.

Mercury簡易改裝

有同好有一樣的困擾 - 如何使用自己的data logging軟體,因此寫了這篇來分享我的簡易改裝。 Background 雲豆子 MERCURY roaster 烘豆機的設計是使用自行開發的軟體,來:1. 操控風門/火力; 2. data logging/自動烘焙。 ...