Why spend your life developing software unless you care about doing it well?

Think! About Your Work

Turn off the autopilot and take control. Constantly critique and appraise your work.

The Cat Ate My Source Code

Provide Options, Don’t Make Lame Excuses

Instead of excuses, provide options. Don’t say it can’t be done; explain what can be done to salvage the situation.

Software Entropy

One broken window, left unrepaired for any substantial length of time, instills in the inhabitants of the building a sense of abandonment—a sense that the powers that be don’t care about the building. So another window gets broken. People start littering. Graffiti appears. Serious structural damage begins. In a relatively short space of time, the building becomes damaged beyond the owner’s desire to fix it, and the sense of abandonment becomes reality.

Don’t Live with Broken Windows

Don’t mess up the carpet when fixing the broken window.

Stone Soup and Boiled Frogs

It’s time to bring out the stones. Work out what you can reasonably ask for. Develop it well. Once you’ve got it, show people, and let them marvel. Then say “of course, it would be better if we added….”

People find it easier to join an ongoing success.

Be a Catalyst for Change

Most software disasters start out too small to notice, and most project overruns happen a day at a time.

If you take a frog and drop it into boiling water, it will jump straight back out again. However, if you place the frog in a pan of cold water, then gradually heat it, the frog won’t notice the slow increase in temperature and will stay put until cooked.

Don’t be like the frog. Keep an eye on the big picture.

Remember the Big Picture

Good enough soup

The scope and quality of the system you produce should be specified as part of that system’s requirements.

Make Quality a Requirements Issue

Great software today is often preferable to perfect software tomorrow. Know When to Stop

Your Knowledge Portfolio

An investment in knowledge always pays the best interest.

Building Your Portfolio

Invest Regularly in Your Knowledge Portfolio

Goals

You need to ensure that the knowledge in your portfolio is accurate and unswayed by either vendor or media hype.

Critically Analyze What You Read and Hear

Communicate

It’s Both What You Say and the Way You Say It

The Evils of Duplication

The problem arises when you need to change a representation of things that are across all the code base. Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

DRY—Don’t Repeat Yourself

Types of duplication:

Make it easy to reuse

Orthogonality

Two or more things are orthogonal if changes in one do not affect any of the others. Also called cohesion. Write “shy” code.

Eliminate Effects Between Unrelated Things

Benefits:

Reversibility

Be prepared for changes.

There are no Final Decisions.

Tracer Bullets

In new projects your users requirements may be vague. Use of new algorithms, techniques, languages, or libraries unknowns will come. And environment will change over time before you are done. We’re looking for something that gets us from a requirement to some aspect of the final system quickly, visibly, and repeatably.

Use Tracer Bullets to Find the Target

Advantages:

Tracer Bullets Don’t Always Hit Their Target

Tracer bullets show what you’re hitting. This may not always be the target. You then adjust your aim until they’re on target. That’s the point.

Tracer Code versus Prototyping

With a prototype, you’re aiming to explore specific aspects of the final system. Tracer code is used to know how the application as a whole hangs together.

Prototyping generates disposable code. Tracer code is lean but complete, and forms part of the skeleton of the final system.

Prototypes and Post-it Notes

We build software prototypes to analyze and expose risk, and to offer chances for correction at a greatly reduced cost.

Prototype anything that:

Samples:

Prototype to Learn

Avoid details:

Prototyping Architecture:

Never deploy the prototype

Domain Languages

Program Close to the Problem domain

Estimating

Estimate to Avoid Surprises

How Accurate Is Accurate Enough?

First: Do they need high accuracy, or are they looking for a ballpark figure?

Second: Scale time estimates properly

Duration Quote estimate in
1-15 days days
3-8 weeks weeks
8-30 weeks months
30+ weeks think hard before giving an estimate

Where Do Estimates Come From?

Ask someone who’s been in a similar situation in the past.

Estimating Project Schedules

The only way to determine the timetable for a project is by gaining experience on that same project. Practice incremental development, repeating the following steps:

The refinement and confidence in the schedule gets better and better each iteration

Iterate the Schedule with the Code

What to Say When Asked for an Estimate

“I’ll get back to you.”

Challenges

Start keeping a log of your estimates. For each, track how accurate you turned out to be. If your error was greater than 50%, try to find out where your estimate went wrong.

Keep Knowledge in plain text

The Power of Plain Text

Drawbacks

The Power of Text

Shell Games

Use the power of command Shells

Can’t you do everything equally well by pointing and clicking in a GUI? No. A benefit of GUIs is WYSIWYG—what you see is what you get. The disadvantage is WYSIAYG—what you see is all you get.

Power Editing

Use a Single Editor Well

Editor “must” features

17.-Source Code Control

Always Use Source Code Control

18.-Debugging

Fix the Problem, Not the Blame

Don’t Panic

A Debugging Mindset

Don’t waste a single neuron on the train of thought that begins “but that can’t happen” because quite clearly it can, and has. Try to discover the root cause of a problem, not just this particular appearance of it.

Where to Start

Debugging Strategies

Bug Reproduction

Visualize Your Data

Use the tools that the debugger offers you. Pen and paper can also help.

Tracing

Now what happens before and after.

Rubber Ducking

Explain the bug to someone else.

Process of Elimination

It is possible that a bug exists in the OS, the compiler, or a third-party product—but this should not be your first thought.

“select” Isn’t Broken

The Element of Surprise

Don’t Assume It—Prove It

Debugging Checklist

Text Manipulation

Learn a Text Manipulation Language

Code Generators

Write Code That Writes Code Two main types of code generators:

Code Generators Needn’t Be Complex

Keep the input format simple, and the code generator becomes simple.

Code Generators Needn’t Generate Code

You can use code generators to write just about any output: HTML, XML, plain text - any text that might be an input somewhere else in your project.

You can’t write Perfect Software

No one in the brief history of computing has ever written a piece of perfect software. Pragmatic Programmers don’t trust themselves, either.

Design by Contract

A correct program is one that does no more and no less than it claims to do. Use:

Design with Contracts

Write “lazy” code: be strict in what you will accept before you begin, and promise as little as possible in return.

Implementing DBC

Simply enumerating at design time:

Assertions

You can use assertions to apply DBC in some range. (Assertions are not propagated in subclasses)

DBC enforce Crashing Early

Invariants

Dead Programs Tell No Lies

All errors give you information. Pragmatic Programmers tell themselves that if there is an error, something very, very bad has happened.

Crash Early

A dead program normally does a lot less damage than a crippled one.

When your code discovers that something that was supposed to be impossible just happened, your program is no longer viable.

Assertive Programming

If It Can’t Happen, Use Assertions to Ensure That It Won’t

When to Use Exceptions

Use Exceptions for Exceptional Problems

What Is Exceptional?

The program must run if all the exception handlers are removed If your code tries to open a file for reading and that file does not exist, should an exception be raised

How to Balance Resources

When managing resources: memory, transactions, threads, flies, timers—all kinds of things with limited availability, we have to close, finish, delete, deallocate them when we are done.

Finish What You Start

Nest Allocations

Objects and Exceptions

Use finally to free resources.

Decoupling and the Law of Demeter

Minimize Coupling

Be careful about how many other modules you interact with and how you came to interact with them.

Traversing relationships between objects directly can quickly lead to a combinatorial explosion.


	book.pages().last().text().

	// Instead, we're supposed to go with:

	book.textOfLastPage()

Symptoms:

  1. Large projects where the command to link a unit test is longer than the test program itself
  2. “Simple” changes to one module that propagate through unrelated modules in the system
  3. Developers who are afraid to change code because they aren’t sure what might be affected

The Law of Demeter for Functions

The Law of Demeter for functions states that any method of an object should call only methods belonging to:


class Demeter {
	private A a;
	void m(B b) {
		a.hello(); 							//itself
		b.hello(); 							//any parameters that were passed to the method
		new Z().hello(); 					// any object it created
		Singleton.INSTANCE.hello(); 		// any directly held component
	}
}

Minimize Coupling Between Modules

Does It Really Make a Difference?

Using The Law of Demeter will make your code more adaptable and robust, but at a cost: you will be writing a large number of wrapper methods that simply forward the request on to a delegate. imposing both a runtime cost and a space overhead. Balance the pros and cons for your particular application.

Metaprogramming

“Out with the details!” Get them out of the code. While we’re at it, we can make our code highly configurable and “soft”—that is, easily adaptable to changes.

Dynamic Configuration

Configure, Don’t Integrate

Metadata-Driven Applications

We want to configure and drive the application via metadata as much as possible. Program for the general case, and put the specifics somewhere else —outside the compiled code base

Put Abstractions in Code Details in Metadata

Benefits:

When to Configure

A flexible approach is to write programs that can reload their configuration while they’re running.

Temporal Coupling

Two aspects of time:

We need to allow for concurrency and to think about decoupling any time or order dependencies. Reduce any time-based dependencies

Workflow

Use activity diagrams to maximize parallelism by identifying activities that could be performed in parallel, but aren’t.

Analyze Workflow to Improve Concurrency

Architecture

Balance load among multiple consumer processes: the hungry consumer model.

In a hungry consumer model, you replace the central scheduler with a number of independent consumer tasks and a centralized work queue. Each consumer task grabs a piece from the work queue and goes on about the business of processing it. As each task finishes its work, it goes back to the queue for some more. This way, if any particular task gets bogged down, the others can pick up the slack, and each individual component can proceed at its own pace. Each component is temporally decoupled from the others.

Design Using Services

Design for Concurrency

Programming with threads imposes some design constraints—and that’s a good thing.

Cleaner Interfaces

Thinking about concurrency and time-ordered dependencies can lead you to design cleaner interfaces as well.

Always Design for Concurrency

Deployment

You can be flexible as to how the application is deployed: standalone, client-server, or n-tier.

If we design to allow for concurrency, we can more easily meet scalability or performance requirements when the time comes—and if the time never comes, we still have the benefit of a cleaner design.

It’s Just a View

Publish/Subscribe

Objects should be able to register to receive only the events they need, and should never be sent events they don’t need.

Use this publish/subscribe mechanism to implement a very important design concept: the separation of a model from views of the model.

Model-View-Controller

Separates the model from both the GUI that represents it and the controls that manage the view.

Advantage:

Separate Views from Models

Beyond GUIs

The controller is more of a coordination mechanism, and doesn’t have to be related to any sort of input device.

Blackboards

A blackboard system lets us decouple our objects from each other completely, providing a forum where knowledge consumers and producers can exchange data anonymously and asynchronously.

Blackboard Implementations

With Blackboard systems, you can store active objects—not just data—on the blackboard, and retrieve them by partial matching of fields (via templates and wildcards) or by subtypes.

Functions that a Blackboard system should have:

Organizing Your Blackboard by partitioning it when working on large cases.

Use Blackboards to Coordinate Workflow

Program by Coincidence

We should avoid programming by coincidence—relying on luck and accidental successes— in favor of programming deliberately. Don’t Program by Coincidence

How to Program Deliberately

Algorithm Speed

Pragmatic Programmers estimate the resources that algorithms use—time, processor, memory, and so on.

Use: Big O Notation

	bool IsFirstElementNull(IList<string> elements)
	{
    	return elements[0] == null;
	}

	Int BinarySearch(list, target)
	{
	   lo = 1, hi = size(list)
	   while (lo <= hi){
	      mid = lo + (hi-lo)/2
	      if (list[mid] == target) return mid
	      else if (list[mid] < target) lo = mid+1
	      else hi = mid-1
	   }
	}


	bool ContainsValue(IList<string> elements, string value)
	{
	    foreach (var element in elements)
	    {
	        if (element == value) return true;
	    }

	    return false;
	}


	bool ContainsDuplicates(IList<string> elements)
	{
	    for (var outer = 0; outer < elements.Count; outer++)
	    {
	        for (var inner = 0; inner < elements.Count; inner++)
	        {
	            // Don't compare with self
	            if (outer == inner) continue;

	            if (elements[outer] == elements[inner]) return true;
	        }
	    }

	    return false;
	}


	int Fibonacci(int number)
	{
	    if (number <= 1) return number;

	    return Fibonacci(number - 2) + Fibonacci(number - 1);
	}

Common Sense Estimation

Estimate the Order of Your Algorithms

Test Your Estimates

Best Isn’t Always Best

Be pragmatic about choosing appropriate algorithms—the fastest one is not always the best for the job.

Be wary of premature optimization. Make sure an algorithm really is a bottleneck before investing time improving it.

Refactoring

Code needs to evolve; it’s not a static thing.

When Should You Refactor?

Refactor Early, Refactor Often

How Do You Refactor?

Code That’s Easy to Test

Build testability into the software from the very beginning, and test each piece thoroughly before trying to wire them together.

Unit Testing

Testing done on each module, in isolation, to verify its behavior. A software unit test is code that exercises a module.

Testing Against Contract

This will tell us two things:

  1. Whether the code meet the contract
  2. Whether the contract means what we think it means.

Design to Test

There’s no better way to fix errors than by avoiding them in the first place. Build the tests before you implement the code.

Writing Unit Tests

By making the test code readily accessible, you are providing developers who may use your code with two invaluable resources:

  1. Examples of how to use all the functionality of your module
  2. A means to build regression tests to validate any future changes to the code

You must run them, and run them often.

Using Test Harnesses

Test harnesses should include the following capabilities:

Build a Test Window

A Culture of Testing

Test Your Software, or Your Users Will

Evil Wizards

If you do use a wizard, and you don’t understand all the code that it produces, you won’t be in control of your own application.

Don’t Use Wizard Code You Don’t Understand

The Requirements Pit

Perfection is achieved, not when there is nothing left to add, but when there is nothing left to take away….

Don’t Gather Requirements—Dig for Them

Digging for Requirements

Policy may end up as metadata in the application.

Gathering requirements in this way naturally leads you to a system that is well factored to support metadata.

Work with a User to Think Like a User

Documenting Requirements

Use “use cases”

Overspecifying

Requirements are not architecture. Requirements are not design, nor are they the user interface. Requirements are need.

Seeing Further

Abstractions Live Longer than Details

Just One More Wafer-Thin Mint…

What can we do to prevent requirements from creeping up on us?

The key to managing growth of requirements is to point out each new feature’s impact on the schedule to the project sponsors.

Maintain a Glossary

It’s very hard to succeed on a project where the users and developers refer to the same thing by different names or, even worse, refer to different things by the same name.

Use a Project Glossary

Get the Word Out

Publishing project documents to internal Web sites for easy access by all participants.

Solving Impossible Puzzles

Degrees of Freedom

The key to solving puzzles is both to recognize the constraints placed on you and to recognize the degrees of freedom you do have, for in those you’ll find your solution.

Don’t Think Outside the Box—Find the Box

There Must Be an Easier Way!

If you can not find the solution, step back and ask yourself these questions:

Not Until You’re Ready

If you sit down to start typing and there’s some nagging doubt in your mind, heed it.

Listen to Nagging Doubts—Start When You’re Ready

Good Judgment or Procrastination?

Start prototyping. Choose an area that you feel will be difficult and begin producing some kind of proof of concept, and be sure to remember why you’re doing it and that it is a prototype.

The Specification Trap

Writing a specification is quite a responsibility.

You should know when to stop:

Some Things Are Better Done than Described

Circles and Arrows

Don’t Be a Slave to Formal Methods

Formal methods have some serious shortcomings:

Do Methods Pay Off?

Never underestimate the cost of adopting new tools and methods.

Should We Use Formal Methods?

Absolutely but remember that is just one more tool in the toolbox.

Expensive Tools Do Not Produce Better Designs

Pragmatic Teams

Pragmatic techniques that help an individual can work for teams.

No Broken Windows

Quality is a team issue.

Teams as a whole should not tolerate broken windows—those small imperfections that no one fixes.

Quality can come only from the individual contributions of all team members.

Boiled Frogs

People assume that someone else is handling an issue, or that the team leader must have OK’d a change that your user is requesting. Fight this.

Communicate

The team as an entity needs to communicate clearly with the rest of the world.

People look forward to meetings with them, because they know that they’ll see a well-prepared performance that makes everyone feel good.

There is a simple marketing trick that helps teams communicate as one: generate a brand.

Don’t Repeat Yourself

Appoint a member as the project librarian.

Orthogonality

It is a mistake to think that the activities of a project—analysis, design, coding, and testing—can happen in isolation. They can’t. These are different views of the same problem, and artificially separating them can cause a boatload of trouble.

Organize Around Functionality, Not Job Functions

Organize our resources using the same techniques we use to organize code, using techniques such as contracts (Design by Contract), decoupling (Decoupling and the Law of Demeter), and orthogonality (Orthogonality), and we help isolate the team as a whole from the effects of change.

Automation

Automation is an essential component of every project team

Know When to Stop Adding Paint

Ubiquitous Automation

All on Automatic

Don’t Use Manual Procedures

Using cron, we can schedule backups, nightly build, Web site… unattended, automatically.

Compiling the Project

We want to check out, build, test, and ship with a single command

Build Automation

A build is a procedure that takes an empty directory (and a known compilation environment) and builds the project from scratch, producing whatever you hope to produce as a final deliverable.

When you don’t run tests regularly, you may discover that the application broke due to a code change made three months ago. Good luck finding that one.

Nightly build run it every night.

Final builds (to ship as products), may have different requirements from the regular nightly build.

Automatic Administrivia

Our goal is to maintain an automatic, unattended, content-driven workflow.

The Cobbler’s Children

Let the computer do the repetitious, the mundane—it will do a better job of it than we would. We’ve got more important and more difficult things to do.

Ruthless testing

Pragmatic Programmers are driven to find our bugs now, so we don’t have to endure the shame of others finding our bugs later.

Test Early. Test Often. Test Automatically.

Tests that run with every build are the most effective.

The earlier a bug is found, the cheaper it is to remedy. “Code a little, test a little”.

Coding Ain’t Done til All the Tests Run

3 Main aspects:

1.-What to Test

2.-How to Test

Use Saboteurs to Test Your Testing

Test State Coverage, Not Code Coverage

3.-When to Test

As soon as any production code exists, it needs to be tested. Most testing should be done automatically.

Tightening the Net

If a bug slips through the net of existing tests, you need to add a new test to trap it next time.

Find Bugs Once

It’s All Writing

If there’s a discrepancy, the code is what matters—for better or worse.

Treat English as Just Another Programming Language

Build Documentation In, Don’t Bolt It On

Comments in Code

In general, comments should discuss why something is done, its purpose and its goal.

Remember that you (and others after you) will be reading the code many hundreds of times, but only writing it a few times.

Even worse than meaningless names are misleading names.

One of the most important pieces of information that should appear in the source file is the author’s name—not necessarily who edited the file last, but the owner.

Executable Documents

Create documents that create schemas. The only way to change the schema is to change the document.

Technical Writers

We want the writers to embrace the same basic principles that a Pragmatic Programmer does—especially honoring the DRY principle, orthogonality, the model-view concept, and the use of automation and scripting.

Paper documentation can become out of date as soon as it’s printed.

Publish it online, on the Web.

Remember to put a date stamp or version number on each Web page.

Using a markup system, you have the flexibility to implement as many different output formats as you need.

Markup Languages

Documentation and code are different views of the same underlying model, but the view is all that should be different.

Great Expectations

The success of a project is measured by how well it meets the expectations of its users.

Gently Exceed Your Users’ Expectations

Communicating Expectations

Users initially come to you with some vision of what they want. You cannot just ignore it.

Everyone should understand what’s expected and how it will be built.

The Extra Mile

Give users that little bit more than they were expecting.

Pride and Prejudice

Pragmatic Programmers don’t shirk from responsibility. Instead, we rejoice in accepting challenges and in making our expertise well known.

We want to see pride of ownership. “I wrote this, and I stand behind my work.”

Sign Your Work

Based on The Pragmatic Programmer Book by Andy Hunt and Dave Thomas