Articles and thoughts on Java technologies, software engineering practices, and agile methods.
Analytics
Sunday, September 30, 2012
Team Geek Book Review
The book focuses on the social aspect of software development, team culture, and personal interactions. Although it surrounds a technical field, the book does not dive into any technical jargon. There is no elaboration on the merits of elegant design patterns or database bottle neck optimizations. Through simple stories and anecdotes, the authors mentor the reader through the obstacles of the IT office place. From hairy pointed bosses, to the perfectionist, to the ego maniac, the authors have encountered a variety of situations and offer the reader practical advice.
Saturday, February 4, 2012
That's Not Agile!
Recently I have been reading Andy Hunt's books and I find them very insightful. The latest book I am reading is "Practices of An Agile Developer", which he co-authored along with Venkat Subramanium. At the beginning of each section they place a little quote which represents a "devilish" thought. They are entertaining to read, so I thought I would pick out some of my favorite and post them along with my thoughts. If you are agile minded like myself, you will certainly think "That's not Agile!"
Blame Game
"The first and most important step in addressing a problem is to determine who caused it. Find that moron! Once you’ve established fault, then you can make sure the problem doesn’t happen again. Ever."This attitude is rooted in the blame game. Agile is about providing solutions, not assigning blame. If you run into this atmosphere, try to bring a positive outlook to it and solve the problem first. Allow room for a retrospective to mitigate problems in the future, but for pete's sake, don't blame.
Hack
"You don’t need to really understand that piece of code; it seems to work OK as is. Oh, but it just needs one small tweak. Just add one to the result, and it works. Go ahead and put that in; it’s probably fine."Under time pressure, this thought will definitely come up in any reasonable person's mind. If you think about it, this mindset is a hack. Responsible developer's should understand what they are getting into. This doesn't mean getting into analysis paralysis, but always look for ways to understand, refactor, and improve the code. The trade off in doing that must always be a consideration, but a hack mindset only leads to distressed code in the end. Weigh the options. Refactoring and understanding the code you are working will pay for itself quickly.
Egotism
“You have a lot invested in your design. You’ve put your heart and soul into it. You know it’s better than anyone else’s. Don’t even bother listening to their ideas; they’ll just confuse the issue.”Agile is about collaboration and learning. I have run into this egotistic attitude many times in my career. I would hope an agile team is about ideas, not who is behind the idea. In addition, even if you have a design, it means nothing until you prove it out in code. Tracer bullet the idea instead of arguing, and you will probably come up with a better design in the end anyways if you consider others' input. Don't invest too much in upfront design. If you do, you are missing out on evolving your design.
Stagnant
“That’s the way you’ve always done it, and with good reason. It usually works for you just fine. The ways you learned when you first started are clearly the best ways. Not much has changed since then, really.”I'll just say it. This is my favorite. That's not agile! At all. In an environment of continous improvement and value creation, this is the last thing you should hear. Especially in the technology field, we need to brace for change and accept that new ideas may be better then the old. I'll borrow a quote from the athletic arena, "If you ain't improving constantly, you are getting passed up."
Feel free to add your own quotes based on your past experiences.
Saturday, November 12, 2011
Pragmatic Thinking: Novice vs Expert
Wednesday, September 21, 2011
4 Groovy Tips You May Not Know
Recently I decided that even though I am adequetely familiar with the language, I wanted to read Programming In Groovy by Venkat Subramanium. I was pleasantly surprised that I learned some useful tips. Below are some tips that I learned:
1. Variant Looping Mechanisms
In addition to the traditional looping constructs, such as "for (i in iterm)" or range (0..5), Groovy provides alternate ways to loop.
Use the upto function to operate on a range of values:
def sum = 0 10.upto(15) { sum += it } println sum result: 75
Use the step function to skip values:
3.step(20, 3) { print "$it " } result: 3 6 9 12 15 18
Saturday, July 23, 2011
Interviewing Agile Candidates
This means the group has opened up several positions for agile developers. It also means that the core members of the group have to interview several candidates to fill 6-10 positions. Not only does this take time and effort, but it also takes a disciplined approach to obtain the best candidates.
Along the way, we have developed a patterned approach to interviewing candidates. So far it has yielded high quality agile members joining the team. I hope to give an brief overview of the approach taken.
Team Members Participate in Interview
The interview process does not just involve the manager and the new candidate. We include a few members of the team during the interview as well. This gives the benefit of various perspectives and also establishes team ownership of the decision to bring on an individual. Existing team members, along with the managers, get exposure to the new candidate for up to 3 hours possibly (we first do a phone screen, then a face to face). This amount of exposure across team members only helps with obtaining high quality developers.
Wednesday, July 21, 2010
Software Principles are like some Life Principles
Software and Life
In life we have ethics and morals that we live by. Ethics and morals manifest themselves as life principles. They give us a framework to become better people, respect one another, and ultimately improve our quality of life.
In the software industry we have software design principles. They are rules we operate under in order to make the products we develop elegant, easy to understand, and maintainable. Software products run our economy or make our day to day lives easier, and software principles play a large role in allowing that to happen.
However, software design principles are not meant to be dogmatic. They are not meant to be strictly adhered to. The use of software principles should be evaluated within the prism of trade offs. Software principles are essentially rules of thumbs and can be broken if it's the most pragmatic thing to do.
Software principles are like some life principles . . . but unlike others. To illustrate my point, let's consider some life principles that can be considered absolute, i.e, should never be broken no matter what the circumstances.
Don't Cheat, and Be Nice
Take the rule "Don't cheat." Under no circumstances would I teach my son that it is permissible to cheat. It's not OK to cheat on a test at school. It's not OK to cheat on your taxes, and its not OK to cheat on a board game at home. No matter what the context, big or small, cheating is not beneficial. It only hurts others and ultimately your self. Software principles aren't like the cheating principle.
Another example would be "Never treat a person as a means to an end." It is unethical to use a person strictly as a means to an end with disregard to their humanity. People should be treated as human beings, not as objects. Under no circumstances, would I teach my child to "use" someone just for the sake of personal gain and devoid of respect. Software principles aren't like ethical principles . . . we can break them if needed.
So what are software principles like then, and what software principles am I talking about? Most life principles we live by are general rules of thumb, they are not absolutes. Software principles are like that. Here are a few examples of what I mean:
DRY
We live by the principle of "Always tell the truth", but this rule doesn't always apply. Take for example white lies. If your wife asks you, "Do I look fat in this dress?", you would be asinine to say yes. Most us would say "No honey, you look great!" Even though your beautiful wife may be slightly overweight (no big deal in my eyes, personally.)
In software, we have the DRY principle: Don't Repeat Yourself. This should be something you mostly do and can greatly contribute to clean code. But would you really want to create a full fledged Template or Strategy Method Pattern to save 1 or 2 lines of code? Sometimes violating the DRY principle can avoid excessive pattern usage, which can cripple a project and make code unintelligible. Evaluate the trade offs for DRY and make the best decision.
Law Of Demeter
How about the life principle of "Always eat healthy"? Yes, we should eat healthy and watch our diet, in general, so we can live a quality life. But we are allowed to break the rule on holidays and eat the fried turkey and pecan pie. It is permissible to go out with the guys and down some beers and wings once in a while. It's not going to kill you. If eating unhealthy is the exception, it is fine.
The Law of Demeter is a software principle that enables loose coupling and limits the knowledge of one component to another. Following this rule keeps your code understandable and limits dependencies. But even though its called a "law", it should be viewed more as a guideline. If you are dealing with an anemic object, and just need to get some data, it is permissible to for a client to dig through objects to get what it needs. The alternative would be to blow up the API with several needless methods, which is a documented disadvantage of Law of Demeter.
Conclusion
When designing software, we should understand that software principles should be followed in order to produce quality code. However, use them in a pragmatic manner and don't pursue a software principle so hard that it makes your life and code, miserable. Evaluate your design in terms of trade offs. After all, we certainly have life principles that we don't always follow, and software principles are the same way. Do what's best for value added effort and leave the dogma behind.
Monday, March 22, 2010
5 Ways to Think Wisely in Development
The most recent book I read is Kluge: The Haphazard Construction of the Human Mind, by Gary Marcus. Marcus argues that the human mind is not the elegantly designed organ that we conventionally perceive it as, rather it is a cobbled together contraption which is a product of evolution. He offers explanations on why our minds do clumsy things, such as forget where our car is parked, or why we can't remember what we ate for breakfast.
Without getting into the details, he points out several characteristics of the human brain that are products of evolution. Our cognitive makeup contains several bugs which can be referenced by psychological terms, some of which include: context driven memory, confirmation bias, motivated reasoning, and framing. (I'll leave the explanation of these terms to the book itself.) He also gives recommendations on how to overcome these mental pitfalls. It is a fascinating for the laymen psychologist.
So what does all this have to do with developing software? From Marcus' exploration of the mind, I see several recommendations that can help us become better software developers. Many of the technical and social decisions we make as part of a software team are often afflicted by the "kluges" of the mind. Some basic and common sense tactics can help offset these imperfections, not to mention a help us becomes clearer thinkers, wiser developers, and better teammates.
1. When possible, consider alternative hypotheses.
Often when we have an idea, we get stuck on it and want to see it through to the finish, just for the satisfaction of feeling good about ourselves. It could be a design pattern we see for a problem, or it could be some performance enhancement we think needs done. We tend to not evaluate our own ideas in a dispassionate or objective way. One of the simplest things we can do to improve our capacity to think and come up with good solutions is to consider an alternative track. Contemplate on the opposite and counter your own initial ideas. This can go a long way on improving your own initial thoughts or could lead to an entirely better solution.
2. Imagine your decisions will be spot-checked.
Research has shown that people who believe that they will have to justify their answers are less biased than people who don't. Hold yourself accountable for any decisions you make, technical or otherwise. If we do this, we will tend to invest more cognitive effort and make correspondingly better decisions based on analysis, not just feelings or habits. A good practice would be to write down rationale for any sophisticated decision made and make sure the reasoning is sound. This could be notes for yourself, or published to the software team in a collaborative tool such as a wiki.
3. Always weigh benefits against costs.
There is always some feature or tool that is cool to use or enticing to learn. We should always weigh the benefits versus the costs before we proceed down a certain route. The feature may be cool to the developers, but how much business value does it provide? Does it help the business save money? The new ORM tool looks great and has some added benefits, but what cost will it incur versus the technical savings?
The inverse argument should be considered just as much. A refactoring may incur some cost to implement upfront, but will payoff in the long run by resulting in more maintainable and defect free code. The new integration testing tool may require a week of investment, but could reap dividends by allowing the team to write automated tests and eliminate the painstaking manual and repeated tests. Sometimes the initial pain is worth enduring to get a long term benefit.
4. Whenever possible, don't make important decisions when you are tired or have other things on your mind.
Marcus describes how we have two portions of the brain: the reflexive and the deliberative. The reflexive portion of the brain evolved early on and controls our bodily motions. It also controls ours emotions and fight or flight responses. The deliberative portion of the brain is the most recently evolved and controls rational thinking and logic.
When making decisions related to software, make sure you are well rested and not stressed. Get enough sleep and keep your hunger under control. When your health is not optimal, your reflexive portion of the brain activates and overrides the rational part. This inhibits rational thinking and can especially inhibit complicated problem solving. In order to make the best technical and team decisions, keep in a rested state to leverage the rational part of the mind.
5. Distance yourself.
Our mind is set up to ponder the near and defer future decisions for a later time. It's always about the now and the urgency of the present. The release needs to be done immediately, and we get into fire fighter mode where everything is an emergency. Or...The debate is on about the new design and we must engage in the battle and win the argument!
It's always best to take a step back and distance yourself from the situation. Imagine you are watching from afar and try to judge the situation objectively. Of course, the here and now is always important, but it's also important to balance situation by distancing yourself. Doing so will help assess the situation fairly. It can also let the reflexive portion of the brain simmer down and let the deliberative mind step in to take control when needed.
Even though we are rational people in a technical field, we are human after all. We are products of our ancestors and emotions and rationality are both part of our makeup, although not always in the correct proportion. However, simple mindful steps can be taken to offset any shortcomings we have.
Saturday, October 31, 2009
The Perils of Not Unit Testing
Unit testing is a widely accepted practice in most development shops in this day and age, especially with the advent of the tool JUnit. JUnit was so widely effective and used early on that it has been included in the default distribution of eclipse as long as I can remember and I have been programming professionally in Java for about 8 years. However, the drawbacks of not unit testing are concrete and arise acutely from time to time. This article aims to give a few specific examples of the perils of not unit testing.
Unit Testing Benefits
Unit testing has several basic tangible benefits that has reduced the painstaking troubles of the days when it was not widely used. Without getting into the specifics of the needs and arguments for unit testing, let's simply highlight the benefits as they are universally accepted by Java development professionals, especially within the Agile community.
- an automated regression unit test suite has the ability to isolate bugs by unit, as tests focus on a unit and mock out all other dependencies
- unit tests give feedback to the developer immediately during the test, code, test, code rhythm of development
- unit tests find defects early in the life cycle.
- units tests provide a safety net that facilitates necessary refactoring to improve the design of code without breaking existing functionality
- unit tests, along with a code coverage tool, can produce tangible metrics such as code coverage which is valuable given good quality of tests
- unit tests provide an executable example of how client code can use the various interfaces of the code base.
- the code resulting from unit testing is typically more readable and concise, as code which is not so is difficult to unit test. Thus it follows that code which is written in tandem with unit tests tends to be more modular and higher quality.
Let's explore by example how not unit testing can adversely affect code and allow bugs to easily enter a code base. The focus will be on the method level where methods are simple and straight forward, yet there still can be problems when code is not unit tested.
Example 1: Reuse some code, but you introduce a bug
This example illustrates a situation where a developer has good intentions of reusing some code, but due to a lack of unit testing, the developer unintentionally introduces a bug. If unit tests exists, the developer could have safely refactored and could rely on the unit tests to inform him some requirement had not been covered.
Let's introduce a simple scenario where a clothing store has as system that has users input sales of its clothes. Two objects in the system are: Shirt and ShirtSaleValidator. The ShirtSaleValidator checks the Shirt to see if the sale prices inputted are correct. In this case, a shirt sale price has to be between $0.01 and $15. (Note this example is overly simplified, but still illustrates the benefits of unit testing.)
Coder Joe implementes the isShirtSalePriceValid method but writes no unit tests. He follows the requirements correctly. The code is correct.
package com.assarconsulting.store.model;
public class Shirt {
private Double salePrice;
private String type;
public Shirt() {
}
public Double getSalePrice() {
return salePrice;
}
public void setSalePrice(Double salePrice) {
this.salePrice = salePrice;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
package com.assarconsulting.store.validator;
import com.assarconsulting.store.model.Shirt;
import com.assarconsulting.store.utils.PriceUtility;
public class ShirtSaleValidator {
public ShirtSaleValidator() {
}
public boolean isShirtSalePriceValid(Shirt shirt) {
if (shirt.getSalePrice() > 0 && shirt.getSalePrice() <= 15.00) {
return true;
}
return false;
}
}
Coder Bob comes along and he is "refactor" minded, he loves the DRY principle and wants to reuse code. During some other requirement he implemented a Range object. He sees its usage in the shirt pricing requirement as well. Note that Bob is not extensively familiar with Joe's requirement, but familiar enough to feel competent enough to make a change. In addition, their group abides by the Extreme Programming principle of collective ownership.
Thus, Bob nobly makes the change to reuse some code. He quickly translates the existing code to use the utility method, and moves on satisfied.
package com.assarconsulting.store.validator;
import com.assarconsulting.store.model.Shirt;
import com.assarconsulting.store.utils.Range;
public class ShirtSaleValidator {
public ShirtSaleValidator() {
}
public boolean isShirtSalePriceValid(Shirt shirt) {
Range< Double > range = new Range< Double >(new Double(0), new Double(15));
if (range.isValueWithinRange(shirt.getSalePrice())) {
return true;
}
return false;
}
}
package com.assarconsulting.store.utils;
import java.io.Serializable;
public class Range< T extends Comparable> implements Serializable
{
private T lower;
private T upper;
public Range(T lower, T upper)
{
this.lower = lower;
this.upper = upper;
}
public boolean isValueWithinRange(T value)
{
return lower.compareTo(value) <= 0 && upper.compareTo(value) >= 0;
}
public T getLower() {
return lower;
}
public T getUpper() {
return upper;
}
}
Since there were no unit tests, a bug was created and never caught at time of implementation. This bug will go unnoticed until a developer or user specifically runs manual tests through the UI or some other client. What is the bug? The new code allows 0 to be a price of the Shirt, which is not specified by requirements.
This could have been easily caught if there was an existing set of unit tests to regression test this requirement. We could have a minimum set of simple tests that checked the range of prices for a shirt. The set of unit tests could run on each check in of code or each build. For example, the test suit could have asserted the following.
- $0 = price executes isShirtSalePriceValid to false
- $0.01 = price executes isShirtSalePriceValid to true
- $5 = price executes isShirtSalePriceValid to true
- $15 = price executes isShirtSalePriceValid to true
- $16 = price executes isShirtSalePriceValid to false
- $100 = price executes isShirtSalePriceValid to false
Peril - Imagine hundreds of business requirements that are more complicated than this without unit testing. The compounding effect of not unit testing resulting in bugs, repeated code and difficult maintenance could be exponential compared to the safety net and reduced cost unit testing provides.
Example 2: Code not unit tested yields untestable code, which leads to unclean, hard to understand code.
Let's continue the clothing store system example, which involves pricing of a shirt object. The business would like to introduce Fall Shirt Sale, which can be described as:
For the Fall, a shirt is eligible to be discounted by 20% if it is priced less than $10 and is a Polo brand. The Fall sales last from Sept 1, 2009 till Nov 15th 2009.
This functionality will be implemented in the ShirtSaleValidator class by Coder Joe who plans not to write unit tests. Since testing methods is not on his radar, he is not concerned with making the method testable, ie, making short and concise methods to not introduce too much McCabe's cyclomatic complexity. Increased complexity is difficult to unit test as many test cases are necessary to achieve code coverage. His code is correct, but may turn out something like below.
package com.assarconsulting.store.validator;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import com.assarconsulting.store.model.Shirt;
import com.assarconsulting.store.utils.PriceUtility;
public class ShirtSaleValidator {
private Calendar START_FALL_SALE_AFTER = new GregorianCalendar(2009, Calendar.AUGUST, 31);
private Calendar END_FALL_SALE_BEFORE = new GregorianCalendar(2009, Calendar.NOVEMBER, 16);
public ShirtSaleValidator() {
}
public boolean isShirtEligibleForFallSaleNotTestable(Shirt shirt) {
Date today = new Date();
if (today.after(START_FALL_SALE_AFTER.getTime()) && today.before(END_FALL_SALE_BEFORE.getTime())) {
if (shirt.getSalePrice() > 0 && shirt.getSalePrice() <= 10 ) {
if (shirt.getType().equals("Polo")) {
return true;
}
}
}
return false;
}
}
The problems with this code are numerous, including misplacement of logic according to OO principles and lack of Enums.
However, putting these other concerns aside, let's focus on the readability of this this method. It is hard to ascertain the meaning of this code by just looking at it in a short amount of time. A developer has to study the code to figure out what requirements it is addressed. This is not optimal.
Now's lets think about the testability of this method. If anyone was to test Joe's code, after he decided to leave it this way due to his NOT unit testing, it would be very difficult to test. The code contains 3 nested if statements where 2 of them have 'ands' and they all net result in many paths through the code. The inputs to this test would be a nightmare. I view this type of code as a consequence of not following TDD, i.e. writing code without the intention of testing it.
A more TDD oriented way of writing this code would be as follows.
package com.assarconsulting.store.validator;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import com.assarconsulting.store.model.Shirt;
import com.assarconsulting.store.utils.PriceUtility;
public class ShirtSaleValidator {
private Calendar START_FALL_SALE_AFTER = new GregorianCalendar(2009, Calendar.AUGUST, 31);
private Calendar END_FALL_SALE_BEFORE = new GregorianCalendar(2009, Calendar.NOVEMBER, 16);
public ShirtSaleValidator() {
}
public boolean isShirtEligibleForFallSale(Shirt shirt) {
return isFallSaleInSession() &&
isShirtLessThanTen(shirt) &&
isShirtPolo(shirt);
}
protected boolean isFallSaleInSession() {
Date today = new Date();
return today.after(START_FALL_SALE_AFTER.getTime()) && today.before(END_FALL_SALE_BEFORE.getTime());
}
protected boolean isShirtLessThanTen(Shirt shirt) {
return shirt.getSalePrice() > 0 && shirt.getSalePrice() <= 10;
}
protected boolean isShirtPolo(Shirt shirt) {
return shirt.getType().equals("Polo");
}
}
From this code we can see that the method isShirtEligibleForFallSale() reads much like the requirement. The methods that compose it are readable. The requirements are broken up amongst the methods. We can test each component of the requirement separately with 2-3 test methods each. The code is clean and with a set of unit tests, there is proof of its correctness and a safety net for refactoring.
Peril - Writing code without the intention of testing can result in badly structured code as well as difficult to maintain code.
Conclusion
The above examples are only simple illustrations of the drawbacks of foregoing unit testing. The summation and compounding effect of the perils of not unit testing can make development difficult and costly to a system. I hope the illustrations above communicate the importance of unit testing code.
Source Code
peril-not-unit-testing.zip
Sunday, July 12, 2009
Clearing up the mud - Explaining the various "driven developments"
In recent years within the object oriented and agile community, several approaches to software design and development have materialized and are in use by professional software developers. Test Driven Design (TDD), Domain Driven Design (DDD), Behavior Driven Design (BDD) and Feature Driven Design (DDD) are some of the more well known approaches. While these philosophies all imbibe the classic agile principles of an incremental and iterative mindset to software development, they subtly differ from each other. Each approach focuses on a different aspect. This articles aims to highlight the subtle differences between the approaches and hopefully expose that knowledge so the readers can leverage key aspects of these "driven designs" in their own development.
Test Driven Development
Test Driven Development is probably the most well known development approach in the agile community today. TDD took root in the Xtreme Programming space and was notably brought into the public arena by Kent Beck's book, "Test-driven Development by Example". The focus of TDD is to write tests before you write writing code, but in an iterative manner. Robert C Martin drives home the point when he emphasizes his three Laws of TDD:
- You are not allowed to write any production code unless it is to make a failing unit test pass.
- You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
- You are not allowed to write any more production code than is sufficient to pass the one failing unit test.
TDD focus is to think about what a specific module was created to do and how it's clients expect to interact with it. The approach with TDD is aimed to get the developer to focus on the behavior of a class rather than the implementation. Thus a test is written specifying an expected behavior. Then code is written to satisfy that behavior. Another test is written with an additional behavior. Subsequently more code is written to satisfy this additional behavior. Thus, as a result you have written code to satisfy some desired behavior of a system, no more, no less. Within this rhythm of development, refactoring for cleaner code and better design can confidently take place due to the fact that a suite of tests has been developed along the way to ensure no functionality has been broken. Ron Jeffries, an XP founder refers to this habit as RefactorMercilessly
The definition of TDD is not as much about whether unit tests are written or...integration tests are written... or whether a unit test should test a class in total isolation... as much as it is about specifying the behavior of modules through executable tests and then satisfying that behavior with code. TDD guides the design of code with the added benefit of providing a safety net of regression tests to allow for refactoring.
Domain Driven Design
Eric Evan's book Domain Driven Design has become very popular in the last decade. Few teams claim to exclusively follow domain driven design, but many teams who are agile aware or keep up with the latest trends tend to adopt particular practices and philosophies from DDD.
The main goal of domain driven design is to tackle a complex domain. The premise is based on the thought that most software projects are overly complex and not understandable. This complexity is not due to the technical elements of the project such as networking, databases or platform, but rather the domain itself. The domain is defined as the core business activity of the user. In turn, the main philosophy of DDD is the primary effort for design of a complex project should be on the domain and domain logic, and complex domain designs should be based on a model.
Eric Evan's book enumerates several defined principles and practices, each of which is well thought out and applicable. In essence, that is the beauty of Evan's approach: that subtleties and gray areas of complexity become defined and named through domain driven design.
At its core there are a few distinct concepts which exemplify domain driven design.
- ubiquitious language
- domain model
- knowledge rich domain
- layered architecture
Ubiquitous language in its simplest meaning is the attempt to bridge the gap between the language of the business and languange of the system. The motive behind the ubiquitous language is that the complexity of a project can become unmanageable when a business term or concept is part of the system but is not reflected with the same language in the objects of the system. This tends to create an understanding gap between the business experts who define the behavior of the system and the developers who implement the behaviors of the system. A project that uses the concept of the ubiquitous language strives to incorporate business names, entities, and terminology into their objects.
A domain model is another fundamental base of domain driven design. A complex business domain will result in a complex software project. In order to understand the business domain and translate that knowledge into an object oriented system objects are necessary. A domain model is an attempt to capture knowledge learned about the business into objects. Note that the domain model does not have to be an exact depiction of the actual objects used in the system. Many projects maintain a "concept" domain model, which models the known entities, relationships and structure of a system. The main purpose of a domain model is to understand the business domain and build a visual depiction of knowledge so it can be shared amongst team members. It is not a detailed design diagram of the objects of the system but rather a precisely modeled understanding of the business in the form of objects. The domain model is a living diagram and is updated and maintained as understanding evolves.
A knowledge rich domain essentially means that domain objects in the system contain related behavior. Many projects follow the anemic domain pattern in which their domain objects contain data with getters and setter methods but do not contain any behavior methods. The behaviors are implemented "managers" or "controllers." DDD advocates that behaviors related to an object should be contained in that object. Several added benefits are gained from a knowledge rich domain. Behavior logic is contained in one object, often reducing duplicated code resulting in a gain in reuse. Objects are more encapsulated and follow the "tell don't ask" principle. Systems with knowledge rich domains are often more understandable and intuitive as an object manages its own data and its related behaviors can be found with that object, resulting in better maintenance.
Layered Architecture is a technique in designing software in order to separate concerns of a system, reduce coupling, and to isolate the domain layer of a system. An enterprise software system indelibly has several common concerns. A user interface accepts actions from a user, data must be saved to a database, transactions must be managed to maintain integrity of data, and business logic must be implemented. The question arises of where do all these concerns get implemented within a system. If these concerns are flattened into the presentation layer, this can lead to brittle software where one change could trickle to several areas and possibly unrelated areas of a system, thus making maintenance a headache. Changes become unintuitive to implement and scattered across a system. Layered architecture is fundamental concept not original to domain driven design, but nicely complements the idea of separating the domain layer. Evans concisely states the essence of the pattern:Follow standard architectural patterns to provide loose coupling to the layers above. Concentrate all the code related to the domain model in one layer and isolate it from the user interface, application, and infrastructure code. The domain objects, free of the responsibility of displaying themselves, storing themselves, managing application tasks, and so forth, can be focused on expressing the domain model. This allows a model to evolve to be rich enough and clear enough to capture essential business knowledge and put it to work.
The typical breakdown of a system with layered architecture has the following layers:
- User Interface (Presentation Layer)
- Application Layer
- Domain Layer
- Infrastructure and Technical Services Layer (Persistance Layer)
- the UI to be free of business logic and available to concentrate on presentation logic
- the application layer to be thin, meaning it directs flow and delegates work to domain objects. It also addresses the concerns of transaction management, security and other enterprise services
- the infrastructure layer to focus of data related concerns such as connections to a database, CRUD operations that can be reused across various modules, and possibly ORM specific API calls such as a criteria query or abstracted SQL language (ejb-ql or hql).
Behavior Driven Development
Behavior Driven Develeopment was first coined and introduced by Dan North, now of ThoughtWorks. He explains his original ideas in the post Introducing BDD. BDD is a extension upon TDD and does not contest the fundamental values of TDD. Dave Astels, another strong proponent of BDD, explains that "Behavior Driven Development is what you are doing already if you are doing Test Driven Developement very well." The core of BDD consists of focusing the on behavior of software and defining that behavior through executable specification. The motive behing BDD was that the users of Test Driven Development tended to move away from focusing on behavior and a testing mentality would take over as tests were written.
An example of allowing a "testing mentality" to take over your test driven development process would be as follows:
- I create a test for class PersonService and its method findPersonByName, which is intended to retrieve a Person object who has the name "bob" from a database. Note that I intend class to use a DAO of somesort to do data retrieval.
- I create the PersonService, Person, and PersonDAO class.
- Now I get back to my test and create my necessary mocks which may be for the Person and PersonDAO class. During this process I set up those mock objects to have dummy data or for them to expect invocation calls.
Testing based on implementation knowledge can also lead brittle tests that break, due to the fact they are dependent on the structure of your code and not just the behavior. For example, if the PersonService.findPersonByName ever evolved to call another service, like maybe a logger, the test would may have to be updated to create a new mock. Thus, creating a test that finds a person now must be updated because I added a cross-cutting concern such as logging? This seems to break the "test only one thing" rule of thumb. This could trickle to hundreds of tests! This is an example of tests that are dependent on the internal object structure of a system and not the behavior.
Due to the motive of BDD, its proponents focused on correcting the false impressions of the test driven development and introduced the term "behavior driven." This led to introducing naming conventions on test classes and test methods with the intention of leading the developer to think more in terms of the behavior of the system. BDD also relaxes the constraints on only creating pure unit tests, where a class or module is tested in isolation. BDD developers often create tests which test a few modules together or one that hits the database, or a even a traditional pure unit test which is isolated. The behavior specification is what is important and is the focus, not the implementation.
An example test class exemplifying BDD conventions is below. Notice the test class name has "behavior" and the test method name has "should" :
WindowControl should close windows
public class WindowControlBehavior {
@Test
public void shouldCloseWindows() {
//Given
WindowControl control = new WindowControl("My frame");
AFrame frame = new Aframe();
//When
control.closeWindow();
//Then
ensureThat(!frame.isShowing());
}
}
Feature Driven Development
Jeff De Luca and Peter Coad are the founders of Feature Driven Development. FDD is a methodology created in the agile spirit and ment to address the problems of the traditional waterfall process. Overall, it is a management methodology for software, but it also contains a few integrated ideas in the realms of requirements analysis and domain modeling. The sum of its ideas creates a methodology that is structured and easy to follow. It is a simple, iterative, and well defined process.
FDD is defined by these simple steps
- Develop an overall model
- Build a features list
- Plan by feature
- Design by feature
- Build by feature


Step 1 "Develop an overall model" asserts that a project should spend sufficient time developing a domain model for the problem attempting to be solved. This borrows elements from domain driven design, and well as traditional object modeling. This exercise facilitates understanding between managers, business members, and developers. It also well defines the problem and domain.
[action][result][object]
Example features are:
- Calculate the total amount of a Sale
- Display the history of all user comments
Conclusion
Although the various "driven designs" or "driven developments" may sound the same initially, there are subtle differences to each once the details are explored. In my experience, if a project has mindful team members that are familiar with one or more of these approaches, various practices and principles are adopted within the project. Rarely does a project purely and dogmatically adopt one single approach. Most of the time various team members bring differing expertise and experience, thus the project becomes an amalgamation of several methodologies, but still upholds the agile spirit.To be more concrete, early in my career I was on a small project that first explored agile principles. Feature Driven Development was the approach that most fit our goals and we followed the process. However, as we learned more about various approaches such as Domain Driven Design and Test Driven Development, we integrated practices such as maintaining the domain model and a test first development strategy. In fact the whole project was done under the umbrella of RUP, the Rational Unified Process, a more tradional methodology! Thus you can see that each project should consider its own needs and adopt what is best for success.
What practices have you used on your projects? Which ones do you find the most effective?
References
Presentation - Plano Java Mug - Sept 12, 2009
Clearing the Mudd
DDD
Layered Architecture
Domain Driven Design Community
FDD
Feature Driven Development Overview Presentation
Feature Driven Development (FDD) Methodology
BDD
Introducing BDD
Behavior Driven Design Community
What Drives Design