jeudi 30 août 2007

FAVORITE PRACTICES AND TIPS - COMPILATION

This is a compilation of my favorite practices and tips, read in various books.

Bibliography
[PAD] Practices of an Agile Developer, Venkat Subramaniam and Andy Hunt
[XP] eXtreme Programming
[PP] The Pragmatic Programer, Andy Hunt and Dave Thomas
[ILSD] Implementing Lean Software Development, Mary and Tom Poppendieck.
[SI] Ship It!, Jared Richardson and William Gwaltney Jr.
[CCS] C++ Coding Standards, Herb Sutter and Andrei Alexandrescu.
[R] Refactoring, Martin Fowler.

_CONTINUOUS_INTEGRATION____________________________________

[XP] Continuous Integration.
The team keeps the system fully integrated at all times.

[PAD] Keep your project releasable at all times.
Ensure that the project is always compilable, runnable, tested and ready to deploy at moment's notice.

[PAD] Integrate early, integrate often.
Code integration is a major source of risk. To mitigate that risk, start integration early and continue to do it regularly.

[PP] Don't Use Manual Procedures
A shell script or batch file will execute the same instructions, in the same order, time after time.

[PP] Test Early. Test Often. Test Automatically.
Tests that run with every build are much more effective than test plans that sit on a shelf.

[ILSD] The Big Bang Is Obselete
Use continuous integration and nested synchronization;

[SI] Script builds on day one.

[SI] Any machine can be a build machine.

[SI] Build continuously.

[SI] Test continuously.

[SI] Continuously test changing code.

[SI] It has to work for everyone.

[SI] Integrate often, and build and test continuously.

[CCS] Use an automated build system.
Push the (singular) buton: Use a fully automatic ("one-action") build systems that builds the whole project without user intervention.
Have two build modes: Incremental and full.

_TEST_DRIVEN_DEVELOPMENT__________________________________


"Tests are to prevent bugs, not find them."

[XP] Test-Driven Developement.
The programmers work in very short cycles, adding a failing test, then making it work.

[PAD] Use automated unit tests.
Good unit tests warn you about problems immediately. Don't make any design or code changes without solid unit tests in place.

[PAD] Use it before you build it.
Use Test Diven Development as a design tool. It will lead you to a more pragmatic and simpler design.

[PP] Design to Test
Start thinking about testing before you write a line of code.

[PP] Test Your Software, or Your Users Will
Test ruthlessly. Don't make your user find bugs for you.

[PAD] Different makes a difference.
Run unit tests on each supported platform and environment combination, using continuous integration tools. Actively find problems before they find you.

[PP] Coding Ain't Done 'Til All The Tests Run
'Nuff said.

[PP] Use Saboteurs To Test Your Testing
Introduce bugs on purpose in a seperate copy of the source to verify that testing will catch them.

[PP] Test State Coverage, Not Code Coverage.
Identify and test significant program states. Just testing lines of code isn't enough.

[PP] Find Bugs Once.
Once a human tester finds a bug, it should be the last time a human tester finds that bug. Automatic tests should check for it then on.

[PP] Test Your Estimates
Mathematical analysis of algorithms doesn't tell you everything. Try timing your code in its target environment.

[PP] Don't assume it - Prove it
Prove your assumptions in the actual environment - with ream data and boundary conditions.

[ILSD] Mistake-Proof Code with Test-Driven Development

[SI] Exercise your product - automate your tests.

[SI] Use a common, flexible test harness.

[SI] Don't change legacy code until you can test it.

[R] Make sure all tests are fully automatic and that they check their own results.

[R] A suite of tests is a powerful bug detector that decapitates the time it takes to find bugs.

[R] Run your tests frequently. Localize tests whenever you compile -every test at least every day.

[R] When you get a bug report, start by writing a unit tests that exposes the bug.

[R] It is better to write and run incomplete tests than not to run complete tests.

[R] Think of boundary conditions under which things might go wrong and concentrate your tests there.

[R] Don't let the fear that testing can't catch all bugs stop you from writing the tests that will catch most bugs.

_CUSTOMER_TESTS____________________________________________

[XP] Customer tests

As part of selecting each desired features, the customers define automated acceptance tests to show that the feature is working.

[PAD] Automate acceptance testing.
Create tests for core business logic. Have your customers verify these tests in isolation, and exercise them automatically as part of your general test runs.

[ILSD] Write executable specifications instead of requirements.

[SI] Mock client tests do the most with the least.

_SIMPLICITY__________________________________

[PAD] Develop the simplest solution that works.
"Keep it simple"
Incorporate patterns, principles and technology only if you have a compelling reason to use them.

[XP] Simple Design
The team keeps the design exactly suited for the current functionality of the system. It passes all the tests, contains no duplication; expresses everything the authors want expressed, and contains as little code as possible.

[CCS] Correctness, simplicity and clarity comes first.
KISS (Keep It Simple Software°: Correct is better than fast. Simple is better than complex. clear is better than cute. Safe is better then insecure.

[CCS] Don't optimize prematurely.
Spur not a willing horse (Latin proverb): Premature optimization is as addictive as it is unproductive. The first rule of optimization is: Don't do it. The secod reule of optimization (for experts only) is: Don't do it yet. Measure twice, optimize once.
It is far easier to make a correct program fast than ot is to make a fast program correct.

_CLARITY__________________________________

[PAD] Write code to be clear, not clever.
"PIE: Program Intently and Expressively."
Express your intentions clearly to the reader of the code. Unreadable code isn't clever.

[PAD] Comment to communicate.
"Communicate in code"
Document code using well-chosen, meaningful names. Use comments to describe its purpose and constraints. Don't use commenting as a substitute for good code.

[PP] Build Documentation In, Don't Bolt It On.
Documentation created seperately from code is less likely to be correct and up to date.

[R] Any fool can write code that a computer can understand. Good programers write code that humans can understand.

[R] When you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous.

_CODE_REVIEWS________________________________

[PAD] Review all code.
Code reviews are invaluable in improving the quality of the code and keeping the error rate low. if done correctly, reviews can be practical and effective. Review code after each task, using different developers.

[XP] Pair Programming
All production software is built by two programmers, sitting side by side, at the same machine.

[SI] Always review all code.

[CCS] Invest in code reviews.
Re-view code. More eyes will help make more quality. Show your code, and read others'. You'll all learn and benefit.

_COLLECTIVE_CODE_OWNERSHIP___________________

[XP] Collective Code Ownership.
Any pair of programmers can improve any code at any time.

PAD] Emphasize collective ownership of code.
"Practice collective ownership"
Rotate developers across diferent modules and tasks in different areas of the system.

[SI] Architect as a group.

Code reviews are a great way to enhance collective code ownership. Refer to CODE_REVIEWS.


_REFACTORING________________________________________


[XP] Design Improvement - Refactoring
Don't let the sun set on bad code. Keep the code as clean and expressive as possible.

[PP] Don't live with Broken Windows
Fix bad designs, wrong decisions, and poor code when you see them.

[PP] Refactor Early, Refactor Often
Just as you might weed and rearrange a garden, rewrite, rework, re-architect code when it needs it. Fix the root of the problem.

[SI] Use test driven refactoring to clean up untestable code.

[R] When you find you have to add a feature to a program, and the program's code is not structured in a convenient way to add the feature, first refactor the program to make it easy to add the feature, then add the feature.

[R] Before you start refactoring, check that you have a solid suite of tests. The tests must be self-checking.

[R] Refactoring changes the programs in small steps. If you make a mistake, it is easy to find the bug.


_STANDARDS__________________________________________


[XP] Coding Standards
All the code in the system looks as if it was written by a single - very competent - individual.

[ILSD] Standards Exist to Be Chanllenged And Improved
Embody the current best known practices in standards that are always followed while actively encouraging evenryone to challenge and change the standards.

[CCS] Don't sweat the small stuff. (Or: Know what not to standardize.)
Say only what needs saying: Don't enforce personal tastes or obsolete practices.

_TEAMS________________________________________

[XP] Whole Team
All the contributors to an XP project - developers, business analysts, testers, etc. - work together in a single open space, members of one team. The walls of this space are littered with big visible charts and other evidences of their progress.

[PP] Organize Teams Around Functionality
Don't seperate designers from coders, testers from data modelers. Build teams the way you build code.

[PAD] Use stand-up meetings.
Stand-up meetings keep the team on the same page. keep the meeting short, focused, and intense.

[SI] Use daily meetings for frequent course corrections.

[SI] Innovate from the bottom up.

[PAD] Good design evolves from active programmers.
"Architects must write code"
Real insight comes from active coding. Don't use architects who don't code - they can't design without knowing the realities of your system.

[PAD] Be a mentor.
There's fun in sharing what you know - you gain as you give. You motivate others to achieve better results. You improve the overall competence f your team.

[PAD] Keep others informed.
Publish your status , your ideas and the neat things you're looking at. Don't wait for others to ask you the status of your work.

_TOOLS________________________________________

[PP] Costly Tools Don't Produce Better Designs
Beware of vendor type, industry dogma, and the aura of the price tag. Judge tools on their merits.

[SI] Keep critical path technologies familiar.

_VERSION_CONTROL__________________________________

[PP] Always Use Source Code Control
Source code control is a time machine for your work - you can go back.

[PAD] Share code only when ready.
Never check in code that's not ready for others. Deliberately checking in code that doesn't compile or pass its unit tests should be considered an act of criminal project negligence.

[SI] Stay in the sandbox.

[SI] If you need it, check it in.

[CCS] Use a version control system.
The palest of ink is better than the best memory (Chinese proverb): Use a version control system. Never keep files checked out for long periods. Check in after your updated tests pass. Ensure that checked-in code does not break the build.

_BREAK_DEPENDENCIES__________________________________

[ILSD] Break Depenencies
System architecture should support the addition of any fearture at any time.

[PAD] Keep classes focused and components small.
"Write cohesive code."
Avoid the temptation to build large classes or components or miscellaneous catchall classes.

[PAD] Attack problems in isolation.
Seperate a problem area from its surroundings when working on it, especially in a large application.

[PP] Eliminate Effets Between Unrelated Things
Design components that are self-contained, independant, and have a single, well defined purpose.

[PP] Minimize Coupling Between Modules
Avoid coupling by writing "shy" code and applying the Law of Demeter.

[PP] Abstractions Live Longer Than Details
Invest in the abstraction, not the implementation. Abstractions can survive the barrage of changes from different implementations and new technologies.

[PAD] Tell, don't ask.
Don't take on another oblect's or component's job. Tell it what to do, and stick to your own job.

[SI] An encapsulated architecture is a scalable architecture.

[CCS] Give one entity one cohesive responsability.

[CCS] Minimize global and shared data.
Sharing causes contention: Avoid shared data, especially global data. shared data increases coupling, which reduces maintainability and often performance.

[CCS] Hide information.
Don't tell: Don't expose internal information from an entity that provides an abstraction.

[CCS] Prefer composition to inheritance.
Avoid inheritance taxes: Tight coupling is undesirable and should be avoided where possible. Therefore, prefer composition to inheritance unless you know thet the latter benefits your design.

_INCREMENTS__________________________________

[PAD] Write code in short edit/build/test cycles.
"Code in increments."
It's better than coding for an extended period of time. You'll create code that's clearer, simpler, and easier to maintain.

[PAD] Develop in increments.
Release your product with minimal, yet usable, chunks of functionality. Within the development of each increment, use an iterative cycle of one to four weeks or so.

_ROOT_CAUSE__________________________________

[PAD] Don't fall for the quick hack.
"Quick fixes become quicksand."
Invest the energy to keep code clean and out in the open.

[PAD] Keep asking Why.
Don't just accept what you're told at face value. Keep questioning until you understand the root of the issue.

_MISTAKE_PROOF_CODE_____________________________

[PP] Design with Contracts
Use contracts to document and verify that the code does no more and no less than it claims to do.

[PP] Crash Early
A dead program normally does a lot less damage than a crippled one.

[PP] Use Assertions to Prevent the Impossible
Assertions validate your assumptions. Use them to protect your code from an uncertain world;

[PAD] Treat warnings as errors.
Checking in code with warnings is just as bad as checking in code with errors or code that fails its tests. No checked-in code should produce any warnings from the build tools.

[CCS] Compile cleanly at high level warning levels.
Take warnings to heart: Use your compiler's highest warning level. Require clean (warning-free) builds. Understand all warnings. Eliminate warnings by changing your code, not by reducing the warning level.

[CCS] Prefer compile- and link-time errors to run-time errors.

[CCS] Assert liberally to document internal assumptions and invariants.

Also refer to CONTINUOUS_INTEGRATION, TEST-DRIVEN_DEVELOPMENT and CODE_REVIEWS.

_TRACK_ISSUES__________________________________

[SI] Avoid collective memory loss.

[PAD] Maintain a log of problems and their solutions.
Part of fixing a problem is retaining details of the solution so you can find and apply it later.

_DESIGN_STYLE__________________________________

[PAD] Extend systems by substituting code.
"Substitute by contract."
Add and enhance features by substituting classes that honor the interface contract. Delegation is almost always preferable to inheritance.

[CCS] Public inheritance is substitutability.

[CCS] Consider making virtual functions nonpublic, and public functions nonvirtual.
Non Virtual Interface (NVI) pattern.

[CCS] Prefer writing nonmember nonfriend functions.

[PAD] A good design is a map; let it evolve.
Let design guide, Not dictate.

[PP] DRY - Don't Repeat Yourself
Every piece of knowledge must have a single, unamiguous, authoritative representation within a system.

[PP] Program Close to the Problem Domain
Design and code in your user's language.

[PP] Use a Project Glossary
Create and mainain a single source for all the specific terms and vocabulary for a project.

lundi 27 août 2007

FAILURE AND CHANGE NOTIFICATIONS



We've just configured our continuous integration tool to notify all team members by email of failures in the build, and changes commited into the code base.

The failure notifications help to implement the stop-the-line culture. A failure may be a failure to build the application, a failed test case or an assertion raised in the code by a test.

The change notifications help the team members to stay informed of the changes commited by the team. This helps to share the code.


mercredi 22 août 2007

CHANGE TOLERANT CODE

In most of the books I've read concerning software development, we are told to accept change. The authors share several practices to write change tolerant code.
This article is a compilation of these various practices and of personal experience.

  • Use a version-control system. With such a tool, you can roll-back from a change which brought regressions into the code.
  • Work in short iterations and integrate continuously. Always have an operational application, ready to be changed.
  • Design-by-contract with assertions. The assertions will stop at runtime when a contract is broken by a side-effect of a change.
  • Test-driven development. The automated self-checking tests will detect any regression brought into the code by a change.
  • Measure code coverage by tests. You don't a change to affect a non-tested part of the code. Identify the lines of code never exercized by tests, and add some test cases.
  • Apply the Single Responsiblity Principle (SRP). As Robert Martin says in AGILE SOFTWARE DEVELOPMENT:

A class should have only one reason to change.

  • Apply the Common Closure Principle. As Robert Martin says in AGILE SOFTWARE DEVELOPMENT:

The classes in a package should be closed together against the same kind of changes. A change that affects a closed package affects all the classes in that package and no other packages.

  • Use design-patterns. Many design-patterns organize your design to anticipate change.
  • Use layering, information hiding and encapsulation. This limits coupling by regrouping and isolating cohesive code which may be affected by change, therefore limiting the impact of change into the code.
  • Simplicity. It's just easier to change simple code.
  • Write less code. It's just easier when there is less code to change.
  • No repetition. Don't do the same change twice.
  • Stop-the-line. Detect regressions brought by change as soon as possible. Then, stop work, correct the problem and resume work. A continuous-integration tool which detects changes, builds the application, runs the tests and notifies the development team when a failures occurs can really help.
  • Refactor. Refactor the code and the tests to keep them healthy:eliminate complexity and repetition. The code will be easier to change.

MISTAKE-PROOF CODE

In IMPLEMENTING LEAN SOFTWARE DEVELOPMENT, the authors, Mary and Tom Poppendieck give an example of mistake-proofing (pages 6 and 7):
A properly mistake-proofed system will not need inspection. My video cable is an example of mistake-proofing. I can't plug a monitor cable into a computer or video projector upside down because the cable and the plug are keyed.

This example really puzzled me: How can I translate this into my code?
Of course there are the automated self-checking tests, but there is also design-by-contract with assertions.

Just have a look at this short example (in Java). The code illustrates the example of a video projector and a monitor cable.

public class VideoProjector {
/*************************************************
* Connect a monitor cable.
* PRE monitorCable is not null.
* POST ... some post-condition ...
*/
public void plug(MonitorCable monitorCable) {
assert monitorCable != null : "PreCond: monitorCable != null";
// some code ...
}
...

If you call operation plug with a null monitorCable argument, then the assertion halts the application and you get the following message:
run:
Exception in thread "main" java.lang.AssertionError: PreCond: monitorCable !=null
at zeroinspection.VideoProjector.plug(VideoProjector.java:14)

Therefore, the code of classes VideoProjector and MonitorCable are keyed to be a mistake-proof collaboration.

mardi 21 août 2007

STOP-THE-LINE

I've discovered the Stop-the-line culture in IMPLEMENTING LEAN SOFTWARE DEVELOPMENT. FROM CONCEPT TO CASH, by Mary and Top Poppendieck.
The authors describe this practice as follows:
"work is organized so that the slightest abnormality is immediately detected, work stops, and the cause of the problem is remedied before work resumes."
In software development, this culture can be implemented by several practices combined:
  • Test-driven development. Automated self-checking tests check the code does what it is required to do. This enables to detect an abnormality in what the application does.
  • Measure code coverage by tests. Any code never exercised by tests is detected. Never-tested code is just as bad as failing code. This enables to be sure that anormalities may be detected everywhere in the code.
  • Design-by-contract with assertions. The class responsabilites (operations) are described in terms of pre-conditions and post-conditions. The class state is described in term of a class invariant. The pre-conditions, post-conditions and invariants are checked by assertions coded into the application. Therefore, if a contract is broken at runtime (which means a bug is detected) the application immediately stops and requires fixing. The assertions are exercised by the tests. This enables to detect a broken contract as soon as it is introduced into the code.
  • One-action build and test. A one-action script builds the whole application and runs the automated self-checking tests. This enables to dispose of test results easily.
  • Continuous integration. Developpers deliver and synchronize their work as often as possible. This enables to always dispose of an up-to-date and shippable application.
  • Automated build and test. A continuous integration tool automatically builds and tests the application upon detection of a delivered code or test change. This enables to automatically detect abnormalities in the build or in what the code does.
  • Send abnormality notifications. If the automated build and test fail for any reason (the build fails or a test fails), then a notification is sent to the developpers. The notification may be emails or lava lamps. This enables the developpers to be aware that an abnormality has been detected.
These practices enable to detect a defect as soon as possible and to notify the development team.
Now the team has to stop and correct the problem before work resumes.
The best part is that all these practices have many other benefits!

dimanche 19 août 2007

IMPLEMENTING LEAN SOFTWARE DEVELOPMENT, by Mary and Tom Poppendieck

This is a GREAT book!
I appreciated LEAN SOFTWARE DEVELOPMENT, AN AGILE TOOLKIT so much a I had to read the next sequel.
I was glad to have read the first sequel before the second, as the second assumes the first is read and understood, and as there is no duplication between the sequels.
Reading this book wasn't pure pleasure. Indeed, it helped me realize the extend of improvement to perform in my organization. The waste and suboptimization is revealed and is now difficult to tolerate. This should be encouraging, but the book reveals some improvements are way out of control of a development team. It implies the full value stream. This is where the book may become quite discouraging: can you extend the improvements out of the development team? In a big corporate company, this can be more than a challenge...
Among many other things:
I learned that defects waiting in a list are waste, as they are unfinished work and hide other potential bugs.
I really enjoyed the part saying that tests are there to prevent bugs, not find them.
I understood that our practice of design by contract with assertions was a great way to implement the "stop-the-line" culture and to build mistake-proof code.
I learned A LOT on the use of slack to speed-up the time inside a process.
I recognized what I experienced through a CMMi certification.
I RECOMMEND THIS BOOK.

DESIGN PATTERNS EXPLAINED, Alan Shalloway and James Trott

I really enjoyed the way the design-patterns are brought into the code to solve a current problem.
This book helped me understand some patterns, like Bridge for example.

DESIGN PATTERNS, Gamma, Heml, Johnson and Vlissides

This is a must read. I didn't manage to read it in one-go. I haven't even read it all. I find this book hard to read, sometimes hard to understand - but full of great information. I use it as a reference manual, or a catalog.
What I put into practice:
+ Singleton;
+ Facade;
+ Mediator;
+ Observer;
+ Abstract factory;
+ Template method;
+ Adapter;
+ Responsability chain;
+ Proxy;
+ Command;
+ State;
+ Strategy;
+ Visitor;

UML2 ET LES DESIGN-PATTERNS, Craig Larman, Pearson Education

I read this book some years ago.
I enjoyed the GRASP analysis patterns and the lightweight modelling the author uses.

What I put into practice:
+ lightweight modelling using UML.

SHIP IT! by Jared Richardson and William Gwaltney Jr, The Pragmatic Programmers

Another great book from The Pragmatic BookShelf.
When I received the book, I was a little afraid as it is rated for readers having a skill range from beginner to medium.
Finally, I found great insights - very well explained.
What I put into practice:
+ We added a cross-platform build to our one action build;
+ I plan to build a smoke test for our current project;
+ We configured our Continuous Integration tool to send build and change notifications by eMail to the team-members.
I RECOMMEND THIS BOOK.

PROGRAMMING LANGUAGES



I program in C++, Java and Ada95.

I script with UNIX shells.