12 essential software development principles and concepts

All 12 of these concepts and principles are important in both software itself and the business of software

12 essential software development principles and concepts

Young developers entering the business may hear a lot of principles and concepts thrown at them all at once. More seasoned developers being pulled into more leadership positions will hear business concepts that they may have avoided but that have wide-reaching technical implications.

Here are the 12 things you may have missed in the last couple of decades but that have some of the greatest significance on software and the business of software.

1. Accountability without authority

If you've been working for more than a little while, you have faced accountability without authority.

The extreme case is holding the janitor accountable for quarterly profitability. No matter how much the janitor cleans, he can't make the company more profitable. If the janitor comes to the sales meetings, he can't make the junior salespeople make more calls; he has little to no influence over the salespeople. If he attends the marketing meeting, he can't really get marketing to craft a new campaign.

Okay, the gap is usually not that big. But any gap between what you're held responsible for and what you can actually affect will be a source of frustration. Accountability without authority is a sign of organizational dysfunction (and every place has some), and it results in revolving door positions. It can only be resolved by giving you more authority or less responsibility.

2. Don't repeat yourself

The "don’t repeat yourself” principle is that you should have one unambiguous authoritative representation in a system. Basically, if you find that you're cutting and pasting a block of code into multiple places, your design is flawed and you should fix that first.

Violations of this principle aren't merely a waste of time; they cause maintenance problems. Every cut-and-pasted bug has to be fixed in multiple places. Also, imagine security flaws replicated.

There are many ways to fix this problem, from just fixing your overall architecture to code generators to dependency injection, but—no matter what—you should fix it!

3. You ain't gonna need it

Implement a feature when you need it, not when you foresee needing it. Because, chances are quite high that you ain’t gonna need it. And if you do later need it, add it when you do.

If you are architecting a module and think of everything that it needs to do this release—and in the future—and try to account for all of that, you get needlessly complex software that supports things that may never even happen.

Remember: You understand the present much better than you can foresee the future. Deal with the present.

4. Minimum viable product

When creating something new, it is best to have it do the least it can do really well rather than have it do everything it *could* do but not quite as well. That’s called the minimum viable product (MVP).

Doing the MVP makes it easier to demonstrate the utility to a user or customer. And there is less to correct if it is wrong, and less invested if it fails.

5. An inch wide and a mile deep

This notion is related to MVP. You can't be all things to all people.

The more a product or company tries to do, the less it does really well and the greater cost and complexity it assumes in doing it. You don’t want to be an inch deep and a mile wide.

It is an issue of focus. Larger organizations or more mature software can create "platforms" and divisions to apply more resources, but small companies need to avoid doing too many things at once.

But even in larger organizations, the “an inch wide and a mile deep” principle should exist. Achieving it should be a principle for each part of the organization or platform. Those separate inches may add up to many feet, but they each must be a mile deep.

6a. Least cost (operational excellence)
6b. Best product (product leadership)
6c. Best total solution (customer intimacy)

The "best," or most effective, organizations are said to pursue one of these three strategies. As a result, these organizations are the cheapest, are the best, or provide the best service.

If you're focused on being the cheapest, you're not going to pursue some of the leading-edge features that would be part of the best product in a category.

If you focus on providing the best service (aka customer intimacy), your product will generally get pulled in multiple directions and be heavily tailored and customized to each customer. This costs you in terms of innovation and usability.

Only two of these goals scale really well: Be the cheapest or have the best product. That’s why you can't call Google customer service when you don't get the search results you wanted.

7. Test first

In a modern IDE, you should test first. That means to write a unit test first and then have it generate your classes and such. This results in higher quality software because it makes highly testable software. It also tends to cause you to follow other design principles, like design by contract.

8. Design by contract

For each routine, you should know what it is going to accomplish and what it needs to accomplish it. You do that by designing by contract. Using that approach avoids side effects, global variables, and other fallacies of the modern era.

9. Beware race conditions

Generally, a race condition is the multithreaded violation of a design by contract.

In its simplest form: If two threads are modifying the same variable and if one thread does it first, things are fine. But if the second thread modifies the variable first, you have an error—that is a race condition.

It isn't always possible to detect these sorts of design flaws. There is no unit test that can catch them because frequently they are intermittent and occur only under load. Heavily defensive design and avoiding cooperation among threads are good ways to prevent race conditions. Still, even with messaging and event-driven software, there are other versions of race conditions that are possible (just less likely). Concurrency is just hard.

10. Conway's Law

Conway’s Law says that you are doomed to develop software that reflects the communication structures of your team. In other words, you can't change the fundamental structure of your software without changing the fundamental structure of your team (which is often more difficult).

11. Fail fast

The “fail fast” principle is beloved in Silicon Valley, but it’s a good one anywhere. Basically, your software should crash boldly and horribly if an error occurs.

Amateur programmers check every variable for null and replace it with something like 0 or an empty string even if there is no way it could be null. Then they let the code continue even though an impossible and invalid situation has occurred. The best developers either let the null pointer exception get thrown or actually throw the error themselves.

In project management, it means chasing every political or technical barrier that might exist as early in the project as possible (aka “kick every bear first”).

In business, it means pursuing the bold plans that prove or disprove the product or business strategy rather than slowly investing in an eventual failure or so-called ramen profitability.

12. The mythical man-month/day/year

Adding more manpower at the end of a project makes the project later. The classic book The Mythical Man-Month) describes many of the errors in software engineering today—yet it was written more than 40 years ago.

The term is also used sardonically to answer "when will it be done?" Well, I have no control over my schedule. If I ever had nothing else to do, I'd have it done in three mythical man-days, but I'm about to have six more meetings where someone asks the same question.

Go explore all 12 of these concepts and principles. They're important concepts in both software itself and the business of software.