A collection of lessons learned by various developers in the trenches. The book starts off with a quote of Aristotle “We are what we repeatedly do. Excellence, then, is not an act, but a habit.”. The book strengthens this argument by stating “Extraordinary products are merely side effects of good habits.”. So the first tip of the book is “Choose your habits”. Do not follow something just because it is popular or well known or is practised by others around you.

The author says that there are three aspects that one needs to pay attention to:

Techniques: How the project is developed? I.e. Daily meetings, Code Reviews, Maintaining a To Do List etc.

Tools and Infrastructure

The author highlights the need for a proper tool for Source Control Management. The author also issues a warning that the right tool should be chosen. A tool should not be chosen because it is backed by a big ticket organization. Vendors would push for “supertools”, but one needs to exercise discretion when choosing between the tools.

Good Development Practices

Develop in a Sandbox, i.e. changes of one developer should not impact the other until the changes are ready.

Each developer should have a copy of everything they need for development, this includes web server, application server, database server, most importantly source code and anything else.

Once all the changes by the developer are finished they should check it in to the Source Control so that the others can pick up and integrate it with their code and make any changes they need to make to integrate.

The checked in changes should be fine grained.

Tools Required for ensuring Good Development Practices

SCM

Build Scripts

Track Issues

What to keep in SCM?

While it can be debated whether runtimes like Java need to be kept in the SCM, it is important that all the third party libraries (jars, dlls) and configuration templates be available in the SCM. Note that configuration templates need to be available as the contents itself can change from environment to environment.

Anything that is generated as part of the build process (jars, dlls, exes, war) should not be stored in the SCM.

What a Good SCM should offer

Ensure that the usage of SCM is painless to the developers. The interactions with the SCM should be fast enough to ensure that the developers do not hesitate to use it.

A minimal set of activities that should be supported by the SCM are

Check out the entire project.

Look at the differences between your edits and the latest code in the SCM.

View the history for a specific file—who changed this file and when did they do it?

Update your local copy with other developers’ changes.

Push (or commit) your changes to the SCM.

Remove (or back out) the last changes you pushed into the SCM.

Retrieve a copy of the code tree as it existed last Tuesday.

Script the Build

Once the required artefacts are checked out from the SCM it should be possible for any developer to run a script and have a working system (sandbox) of her own to work on. For this one needs a Build Script. This should be a completely automated build requiring no manual intervention or steps. This build script should be outside of the IDE so that it can be used irrespective of the IDE being used. The IDE could use the same script for local builds.Once the one step/command build script is ready, automate the build. Ideally everytime a code is checked in the following should be done.

Checkout the latest code and build

Run a set of smoke tests to ensure that the basic functionality is not broken.

Configure the build system to notify the stakeholders of new code checked, the build and the test results.

This is Continuous Integration

Tracking the Issues

It is important to track the issues that are reported for the application so that they can be tracked and fixed.At a bare minimum one needs to know the following about an issue:

What version of the product has the issue?

Which customer encountered the issue?

How severe is it?

Was the problem reproduced in-house (and by whom, so they can help you if you’re unable to reproduce the problem)?

What was the customer’s environment (operating system, database, etc.)?

In what version of your product did the issue first occur?

In what version of your product was it fixed?

Who fixed it?

Who verified the fix?

Some more that will help in the long term

During what phase of the project was the bug introduced?

The root cause of the bug

The sources that were changed to fix the problem. If the checkin policy demands that the checkin comment indicate the reason for the fixes, then it should be possible to correlate the checkin with the issue that they fixed or requirement that they addressed.

How long did it take to fix the error? (Time to analyze, Fix, Test)

Some warning signs that things are not OK with the issue system

The system isn’t being used.

Too many small issues have been logged in the system

Issue-related metrics are used to evaluate team member performance.

Tracking Features

Just as it is important to track the issues, it is important to track the features that have been planned for the application.The system used to track issues may also be used to track the features as long as it provides the ability to identify them separately.

Test Harness

Have a good Test Harness which can be used to run automated tests on the system.

Use a standard Test Harness which can generate all the required reports.

Ensure that every team member uses the same tool.

Ensure that the tool can be run from the command line. This will enable driving it from an external script or a tool.

Ensure that the tool is flexible to test multiple types of applications and not specific to a particular type.

Different types of testing needs to be planned for

Unit Testing – Testing small pieces of code. This forces the developers to break up the code into smaller pieces. This makes is easier to maintain and understand, reduces copy paste, ensures that overall functionality is, if at all, minimally impacted by refactoring.

Functional Testing – Testing all the functions of the application.

Performance Testing – Testing the application to ensure that the application is performing within acceptable limits and meets the SLAs.

Load Testing – This is similar to the Performance Testing. The goal of this is to ensure that the application does not collapse under load.

Smoke Testing – This is a light-weight testing which will test the key functionality of the application. This should be included as part of Continuous Integration so that any breakage in key functionality comes to light very quickly.

Integration Testing – This ensures that the integration of the modules within the application and the integration of the application with the external systems is functioning correctly.

Mock Client Testing – This mocks the client requests and ensures that the client get the right response and within the expected time period.

Pragmatic Project Techniques

Some of the good practices to follow when working in projects are as follows:

Maintaining a list of activities to do. This should be visible and accessible to everybody on the project. Even the client should have visibility to the list so that they are check the speed and prioritize the items in the list. Each item should have a target time. The list should reflect the current status and should not be out of date.

Having Tech Leads in the project is important. The Tech lead should guide the team in the selection and utilization of the technology. Tech lead should be responsible to ensure that the deadlines are realistic. The Tech lead should act as the bridge between the developers and the management. It is an important role to be played by a person with the right temperament.

Coordinating and Communicating on daily basis is very important. Meetings need to be setup on a daily basis. These meetings should be short and to the point, with everybody sharing details of what they are doing and what they plan to do. Team should highlight any problem they are facing. The solutions for these problems should not be part of this meeting, but should happen separately.

Code review is a very crucial part of the project and every piece of code should be reviewed. Some good practices of code review are

Review only a small amount of code at any time

A code should not be reviewed by more than two people

Code should be reviewed frequently, possibly several times a day

Consider pair programming as a continuous code review process.

Tracer Bullet Development

Just like it is possible to fire a Tracer Bullet in the night to track the path before aiming the real bullet, it should be possible to predict the path of the project using the process opted for.

Process

Have a process to follow.The process followed should not claim exclusivity in success of projects. If it does so, then suspect it.Follow a process that embraces periodic reevaluation and inclusion of whatever practices work well for the projects.

Executing

Define the layers that will exist in the application.

Define the interfaces between the layers.

Let each layer be developed by a separate team, relying on the interface promised by the adjacent layers.

Keep it flexible so that the interface can be changed as it is hard to get the interfaces perfect the first time around.

First create the large classes like the Database Connection Manager, Log Manager etc required for each layer, then write the fine grained classes.

Collaboration between the teams developing the different layers is key to the success. These collaborations will Trace the Path that the project will take.

Do not let an architect sitting in an ivory tower dictate the architecture.

It is dangerous to have one person driving the whole project. If this person leaves, the project will come to a standstill.

Create stubs, or mock the interfaces of the adjacent layers so that it becomes easy to test.

Code the tough and key pieces first and test them before addressing the simpler ones. It may take time to show progress, but when the progress happens it will be very quick.

Common Problems and How to fix Them

What to do when legacy code is inherited?

Build it – Learn to build it and script the build.

Automate it – Automate the build.

Test it – Test to understand what the system does and write automated test cases.

Don’t change legacy code unless you can test it.

Some other tips from the chapter

If a code is found unsuitable for automated test, then refactor the code slowly so that it becomes amenable to automated testing.

If a project keeps breaking repeatedly, automated test cases, emulating the user actions will help reduce the incidents.

Ensure that the automated tests are updated with change in code/logic whenever required, otherwise these would become useless.

It is important to have a Continuous Intergration so that the automated tests can be run regularly.

Early checkins (in fact daily or more than once a day) and quick updates by the developers is important so that the integration problems are detected as early as possible.

It is important to communicating with the customers and getting regular feedback.

Best way to show the customer the progress of the project is to show them a working demo of the application.

Introduce a process change when the team is not under pressure. Point out the benefit the stakeholders will have with the new process. Show them the benefit of the process/practice rather than talk and preach about it.

A wonderful Dilbert quote from the book“I love deadlines. I especially love the swooshing sound they make as they go flying by.” — Scott Adams