In this series of blog entries, I build an entire ASP.NET MVC Forums application from start to finish. The goal is to discover and promote best-practices for building applications with the ASP.NET MVC framework.
In this first entry, I discuss the overall goals for the forums application. I discuss the importance of avoiding code smells and how software design principles and patterns can help you write code that is resilient to future change. I also justify my choice to use test-driven development while building the Forums application.
What is Good Software?
I don’t want to build just any forums application. The goal is to build the best forums application possible. My modest goal is to build the perfect forums application.
This goal immediately leads to the question: What is good software? What makes one software application better or worse than another software application? At the end of the day, I can’t claim that I have built the perfect forums application without a definition of good software.
Therefore, here’s my definition of good software:
Good software is software that is designed to easily survive change.
There are multiple reasons that you might need to change software (see Feathers page 3):
1) You might need to add a new feature to existing software
2) You might need to fix a bug in existing software
3) You might need to optimize existing software
4) You might need to improve the design of existing software
Badly designed software is difficult to change. Software can be so poorly designed that everyone is afraid to touch it. We’ve all experienced bad software. When software is badly written, you just wish that it would go away. Or worse, given the first opportunity, you just want to rewrite it from scratch.
Avoid Code Smells
Robert and Micah Martin describe the markers of bad software as code smells. The following code smells indicate that software is badly written:
(1) Rigidity – Rigid software is software that requires a cascade of changes when you make a change in one place.
(2) Fragility – Fragile software is software that breaks in multiple places when you make a change.
(3) Needless Complexity – Needlessly complex software is software that is overdesigned to handle any possible change.
(4) Needless Repetition – Needlessly repetitious software contains duplicate code.
(5) Opacity – Opaque software is difficult to understand.
(These code smells are described by Micah and Robert Martin in their book Agile Principles, Patterns, and Practices in C# on page 104. This book is strongly recommended!)
Notice that these code smells are all related to change. Each of these code smells are a barrier to change.
Software Design Principles
By following software design principles, you can write software that is resilient to change. There are several different lists of software design principles. However, there tends to be a lot of overlap between the principles on the different lists.
For example, the Cunningham and Cunningham Wiki describes 11 principles of Object Oriented Design at:
The first 5 principles of Object Oriented Design correspond to the Software Design Principles that Robert Martin (and his son Micah Martin) promotes in the book Agile Principles, Patterns, and Practices in C#. Robert Martin also discusses these principles in the Object Mentor blog:
I found two additional books that contained useful information on Software Design Principles: Head First Design Patterns by Eric Freeman, Elisabeth Freeman, Kathy Sierra, Bert Bates and Head First Object-Oriented Analysis and Design by Brett McLaughlin, Gary Pollice, and David West. The principles discussed in these books are not exactly the same as the Robert Martin principles, but they are close.
The truth is that all of these sources on Software Design Principles originate with Robert Martin’s work. Robert Martin did not invent all of the principles. However, he was the first one to gather the principles into a single list. Here are the Software Design Principles:
· SRP – Single Responsibility Principle
· OCP – Open Closed Principle
· LSP – Liskov Substitution Principle
· ISP – Interface Segregation Principle
· DIP – Dependency Inversion Principle
This collection of principles is collectively known by the acronym SOLID (Yes, SOLID is an acronym of acronyms).
Here is the list of the Software Design Principles from the Head First Design Patterns book:
· Encapsulate what varies
· Favor composition over inheritance
· Program to interfaces and not implementations
· Strive for loosely coupled designs between objects that interact
· Classes should be open for extension but closed for modification
· Depend on abstractions. Do not depend on concrete classes
· Only talk to your friends
· Don’t call me, we’ll call you
· A class should have only one reason to change
Again, there is a lot of overlap between this list of principles and the previous list. For example, the Single Responsibility Principle is the same as the principle that a class should have only one reason to change. However, the emphasis is slightly different. I recommend that you investigate both sources.
What motivates all of these design principles is the desire to build software that can survive change. The principles highlight different principles for creating software that can stand the test of time.
Software Design Patterns
Software Design Patterns represent strategies for applying Software Design Principles. In other words, a Software Design Principle is a good idea and a Software Design Pattern is the tool that you use to implement the good idea (It’s the hammer).
The idea behind Software Design Patterns was originally promoted by the book Design Patterns: Elements of Reusable Object-Oriented Software (This book is known as the Gang of Four book). This book has inspired many other books that describe Software Design Patterns.
The Head First Design Pattern book provides a more user-friendly introduction to the design patterns from the Gang of Four book. The Head First Design book devotes chapters to the following 14 patterns:
Another influential book on Software Design Patterns is Martin Fowler’s book Patterns of Enterprise Application Architecture. This book has a companion website which lists the patterns from the book at:
Software Design Patterns provide you with patterns for making your code more resilient to change. For example, when building the Forums application, we’ll be taking advantage of a Software Design Pattern named the Repository Pattern. Eric Evans, in his book Domain-Driven Design, describes the Repository pattern like this:
A REPOSITORY represents all objects of a certain type as a conceptual set (usually emulated). It acts like a collection, except with more elaborate querying capability. Objects of the appropriate type are added and removed, and the machinery behind the REPOSITORY inserts them or deletes them from the database. (see page 151)
According to Evans, one of the major benefits of the Repository pattern is that it enables you to “decouple application and domain design from persistence technology, multiple database strategies, or even multiple data sources.” (ibid) In other words, the Repository pattern enables you to shield your application from changes in how you perform database access.
We’ll be taking advantage of the Repository pattern in order to isolate our forums application from a particular persistence technology. The forums application will be designed in such a way that we could switch between different data access technologies such as LINQ to SQL, the Entity Framework, or even NHibernate.
I’m going to build the MVC Forums application by using test-driven development. In particular, before I write any application code, I will first write a unit test for the application code.
Test-driven development results in better code for the following reasons:
(1) Building tests for your code provides you with a safety net for change.
(2) Building tests for your code forces you to write loosely coupled code.
(3) Building tests for your code before you write your code forces you to take a user perspective on the code.
Let’s look more closely at each of these benefits.
First, unit tests provide you with a safety net for change. This is a point that Michael Feathers emphasizes again and again in his book Working Effectively with Legacy Code. In fact, he defines legacy code as “simply code without tests” (see xvi).
When your application code is covered by unit tests, you can modify the code without the fear that the modifications will break the functionality of your code. Unit tests make your code safe to refactor. If you can refactor, then you can modify your code using Software Design Patterns which results in better code that is more resilient to change.
Second, practicing test-driven development forces you to write code in a particular way. Testable code tends to be loosely coupled code. A unit test performs a test on a unit of code in isolation. In order to build your application so that it is testable, you need to build the application in such a way that it has isolatable components.
One class is loosely coupled to a second class when you can change the first class without changing the second class. Test-driven development often forces you to write very loosely coupled code. Loosely coupled code is resistant to change.
Finally, writing tests before you write your code forces you to take a user’s perspective on the code. By writing a test first, you take on the same perspective as a developer who will use your code in the future. Since writing tests forces you to think about how a developer (perhaps, your future self) will use your code, the code tends to be better designed.
Short Term Pain, Long Term Gain
Building software using test-driven development requires more upfront effort. Writing tests takes time. However, the idea is that the initial effort required to build the unit tests will pay huge dividends in the future.
There are two ways to be a developer. You can be a cowboy or you can be a craftsman. A cowboy jumps right in and starts coding. A cowboy can build a software application quickly. The problem with being a cowboy is that software must be maintained over time.
A craftsman is patient. A craftsman builds software carefully by hand. A craftsman is careful to build unit tests that cover all the code in an application. It takes longer for a craftsman to create an application. However, after the application is created, it is easier to fix bugs in the application and add new features to the application.
The goal is to build an MVC Forums application that will stand the test of time. It should not only work right now, the application should continue to work in the future as the needs of the people who use the application change.
I’m going to write the application by taking advantage of the Microsoft ASP.NET MVC framework. This framework makes it easy for me to write tests for my code. The ASP.NET MVC Framework was designed from the ground up to support test-driven development.