`
| |
|
June 26th, 2009
I’m just reviewing a project’s code. I found a common pattern used in their code base. Every class implements an Interface. Each interface is only implemented by one class. Even more interesting, this interface is not exposed outside. In other words, its not exposed as part of the API.
Then my question is
Why do we need the interface? Why can’t we just use the class directly?
Apparently there is no valid answer. Some told me,
- Spring forces you to have interfaces.
- Some told me their mocking framework does not support mocking a class.
- This is also not true. Most mocking frameworks come with a class extension. Some new frameworks, don’t even distinguish between an interface and a class.
Anyway, we don’t need one stupid interface for every class we create. YAGNI. When we need it, we’ll create it. This is one form of speculative generality code smell.
Go ahead, kill it!
Tweet This Post Plurk This Post Buzz This Post Delicious This Post Digg This Post Ping This Post Reddit This Post Stumble This Post
Posted in Agile, Design, Programming | 4 Comments »
June 26th, 2009
Here is a sample of code (happens to be from a test) which I think is not communicative.
public class ContactNumberTest {
final String exampleCountryCode1 = "91";
final String exampleCountryCode2 = "1";
final String exampleNumber1 = "8012345678";
final String exampleNumber2 = "2028569635";
ContactNumber phoneNumberA = new ContactNumber(exampleCountryCode1,exampleNumber1);
ContactNumber phoneNumberB = new ContactNumber(exampleCountryCode1,exampleNumber1);
ContactNumber phoneNumberC = new ContactNumber(exampleCountryCode2,exampleNumber2);
@Test
public void testEquals() {
//Symmetry
assertTrue(phoneNumberA.equals(phoneNumberB));
assertTrue(phoneNumberB.equals(phoneNumberA));
//Reflexivity
assertTrue(phoneNumberA.equals(phoneNumberA));
//Not equals
assertFalse(phoneNumberA.equals(phoneNumberC));
}
@Test
public void testHashcode() {
assertTrue(phoneNumberA.hashCode() == phoneNumberB.hashCode());
}
}
I know you must be wondering why in the first place someone is writing tests for equals and hashCode. I agree. Its not required. But lets say someone really needs to.
This is how I would refactor the code to make it more communicative.
public class ContactNumberTest {
private final String indiaCountryCode = "+91";
private final String usCountryCode = "+1";
private final String cellNumber = "8012345678";
private final String mobileNumber = "2028569635";
private final ContactNumber indianNumber = new ContactNumber(indiaCountryCode, cellNumber);
private final ContactNumber sameIndianNumber = new ContactNumber(indiaCountryCode, cellNumber);
private final ContactNumber usNumber = new ContactNumber(usCountryCode, mobileNumber);
private final Map users = new HashMap();
private String userName;
@Test
public void isSymmetrical() {
assertNotSame(indianNumber, sameIndianNumber);
assertEquals(indianNumber, sameIndianNumber);
assertEquals(sameIndianNumber, indianNumber);
}
@Test
public void isReflexive() {
assertEquals(indianNumber, indianNumber);
}
@Test
public void isTransitive() {
ContactNumber newIndianNumber = new ContactNumber(indiaCountryCode, cellNumber);
assertEquals(indianNumber, sameIndianNumber);
assertEquals(sameIndianNumber, newIndianNumber);
assertEquals(newIndianNumber, indianNumber);
}
@Test
public void areNotAlwaysEqual() {
assertFalse(indianNumber.equals(usNumber));
}
@Test
public void equalsIsExceptionFree() {
assertFalse(indianNumber.equals(null));
}
@Test
public void isHashFriendly() {
addUser(”Foo”).usingKey(indianNumber);
assertEquals(”Foo”, users.get(indianNumber));
addUser(”Bar”).usingKey(sameIndianNumber);
assertEquals(1, users.size());
}
private void usingKey(final ContactNumber number) {
users.put(number, userName);
}
private ContactNumberTest addUser(final String userName) {
this.userName = userName;
return this;
}
}
Tweet This Post Plurk This Post Buzz This Post Delicious This Post Digg This Post Ping This Post Reddit This Post Stumble This Post
Posted in Agile, Design, Programming, Testing | 4 Comments »
June 23rd, 2009
Posted in Community, Design | No Comments »
June 21st, 2009
Till a year ago, I used to think of command & control as micro-management. Last year I heard Mary Poppendieck give a different perspective about it in her keynote(pdf). That’s when I realized that Command & Control means quite opposite of micro-management.
We all know Command and Control comes from US Army. During wars, the Commanders would direct (command) the troops on ground about the next move (goal/mission). And then the staff (troops) on ground would figure out the best strategy to achieve the mission. This is very different from micro-management.
Once the Commanders gives the commands, there is no way s/he can control the situation on ground. Tactical decisions are made by the staff on the war field and strategic decisions are made by Commanders and others outside the war fields, based on their knowledge about situation on the ground.
(no plan survives contact with the real enemy).
The heart of mission command:
Commanders should issue only the most essential orders. These provide general instructions outlining the principal objective and specific missions. Tactical details are left to subordinates.
“The advantage which a commander thinks he can attain through continued personal intervention is largely illusory.”
http://www.dtic.mil/dticasd/sbir/sbir043/a30a.pdf
Tweet This Post Plurk This Post Buzz This Post Delicious This Post Digg This Post Ping This Post Reddit This Post Stumble This Post
Posted in Agile | 4 Comments »
June 15th, 2009
For the last 3 odd years, I’ve been exploring the use of behavior (verbs, instead of Nouns, Test) as my test class names. The verb describes what behavior you expect from your system (program).
For example for a Veterinarian Information System (system responsible for billing and patient history), I would have tests called:
ChargeAccountForServices with the following test methods:
makePaymentsAgainstAnAccount()
completePaymentsResultInZeroAmountDueOnReceipt()
incompletePaymentsDisplaysDueAmountOnTheReceipt()
Another test class: GenerateBillsForClientAccount with
notifyIfAccountIsNotDueForPayment()
billContainsTotalCostOfAllServicesTaken()
And another test class: ManageClientVisits with
trackAllServicesTakenByThePatient()
skipVisitIfPatientDidNotTakeAnyService()
These tests helped us flush out Objects like Account, Procedure, Visit and so on…. When we started we had no idea we’ll need these objects.
This style is mostly influenced from a pairing session with Corey Haines post our discussion about “There is no Spoon” @ the SDTConf 2006.
For more about this approach…read my last post…There is No Spoon (Objects)
Tweet This Post Plurk This Post Buzz This Post Delicious This Post Digg This Post Ping This Post Reddit This Post Stumble This Post
Posted in Design, Programming, Testing | 3 Comments »
June 15th, 2009
In OO, frequently, we get caught up in modeling our objects based on our perspective of the real world. Since everyone’s perspective is different we end up with a lot of thrashing and confusion. We end up arguing about these models in the air, baselessly. For example in a Veterinarian Information System (system responsible for billing and patient history), we end up arguing whether the Patient class should have a getShot(Vaccination) or should the Doctor class have a giveShot(Vaccination) method. In the end (when we finally start implementing the system) we realize that it really does not matter who gives the shot or takes the shot. What really matters is that we have recorded what shot was given to which patient. So we end up creating a Visit class with a method called add(Procedure).
Long story short, there are no real-world objects, its all how we perceive things. If we try to model our software based on our understanding of the real world, the software would also be as complex as our understanding of the real world. Since in software we are dealing with creating abstractions, we really want to focus on behavior rather than Objects. TDD is a great way to do this.
We start off with a test which expects that our system will exhibit some Behavior. At this point, we don’t know or care about which Object/s will provide this behavior. To make the tests work, we start creating methods that we need from our objects on the test for the time being. Once we have our test working, then we ask yourself, where does this behavior really belong? Sometimes real world objects pop-up. Sometimes we create Objects that don’t exist in real world. This is important because it helps us make our design simpler and more expressive. Slowly we expect more behavior from our system (by writing new tests) which starts flushing out our objects.
Tweet This Post Plurk This Post Buzz This Post Delicious This Post Digg This Post Ping This Post Reddit This Post Stumble This Post
Posted in Design, Programming | 1 Comment »
June 13th, 2009
I don’t like the I<something> naming convention for interfaces for various reasons.
Let me explain with an example. Lets say we have IAccount interface. Why is this bad?
- All I care is, I’m talking to an Account, it really does not matter whether its an interface, abstract class or a concrete class. So the I in the name is noise for me.
- It might turn out that, I might only ever have one type of Account. Why do I need to create an interface then? Its the speculative generality code smell and violating the YAGNI principle. If someday I’ll need multiple types of Accounts, I’ll create it then. Its probably going to be as much effort to create it then v/s doing it now. Minus all the maintenance overhead.
- Let’s say we’ve multiple types of Accounts. Instead of calling it IAccount and the child classes as AccountImpl1 or SavingAccountImpl, I would rather refer to it as Account and the different types of account as SavingAccount or CreditAccount. It might also turn out that, there is common behavior between the two types of Account. At that point instead of having IAccount and creating another Abstract class called AbstractAccount I would just change the Account interface to be an abstract class. I don’t want to lock myself into an Interface.
Personally I think the whole I<something> is a hang-over from C++ and its precursors.
Some people also argue that using the I<something> convention is easy for them to know whether its an interface or not (esp. coz they don’t want to spend time typing new Account() and then realizing that its an interface).
The way I look at it is good IDEs will show the appropriate icon and that can help you avoid this issue to some extent. But even if it did not, to me its not a big deal. The number of times the code is read is far more than its written. Maintaining one extra poorly named Interface is far more expensive than the minuscule time saved in typing.
P.S: I’m certainly not discouraging people from creating interfaces. What I don’t like is having only one class inheriting from an interface. May be if you are exposing an API, you might still be able to convenience me. But in most cases people use this convention through out their code base and not just at the boundaries of their system.
In lot of cases I find myself starting off with an Interface, because when I’m developing some class, I don’t want to start building its collaborator. But then when I start TDDing that class, I’ll change the interface to a concrete class. Later my tests might drive different types of subclass and I might introduce an Interface or an Abstract class as suitable. And may be sometime in the future I might break the hierarchy and use composition instead. Guess what, we are dealing with evolutionary design.
Tweet This Post Plurk This Post Buzz This Post Delicious This Post Digg This Post Ping This Post Reddit This Post Stumble This Post
Posted in Design, Programming | 6 Comments »
June 13th, 2009
Recently Brett Schuchert from Object Mentor has started posting code snippets on his blog and inviting people to refactor it. Similar to the Daily Refactoring Teaser that I’m conducting at Directi. (I’m planning to make it public soon).
Following is my refactored solution (take 1) to the poorly written code.
Wrote some Acceptance Test to understand how the RpnCalculator works:

Then I updated the perform method to
@Deprecated
public void perform(final String operatorName) {
perform(operators.get(operatorName));
}
public void perform(final Operator operator) {
operator.eval(stack);
currentMode = Mode.inserting;
}
Notice I’ve deprecated the old method which takes String. I want to kill primitive obsession at its root.
Had to temporarily add the following map (this should go away once our deprecated method is knocked off).
private static Map operators = new HashMap() {
{
put(”+”, Operator.ADD);
put(”-”, Operator.SUBTRACT);
put(”!”, Operator.FACTORIAL);
}
@Override
public Operator get(final Object key) {
if (!super.containsKey(key)) {
throw new MathOperatorNotFoundException();
}
return super.get(key);
}
};
Defined various Operators
private static abstract class Operator {
private static final Operator ADD = new BinaryOperator() {
@Override
protected int eval(final int op1, final int op2) {
return op1 + op2;
}
};
private static final Operator SUBTRACT = new BinaryOperator() {
@Override
protected int eval(final int op1, final int op2) {
return op2 - op1;
}
};
private static final Operator FACTORIAL = new UnaryOperator() {
@Override
protected int eval(final int op1) {
int result = 1;
int currentOperandValue = op1;
while (currentOperandValue > 1) {
result *= currentOperandValue;
--currentOperandValue;
}
return result;
}
};
public abstract void eval(final OperandStack stack);
}
Declared two types of Operators (BinaryOperator and UnaryOperator) to avoid duplication and to make it easy for adding new operators.
public static abstract class BinaryOperator extends Operator {
@Override
public void eval(final OperandStack s) {
s.push(eval(s.pop(), s.pop()));
}
protected abstract int eval(int op1, int op2);
}
and
public static abstract class UnaryOperator extends Operator {
@Override
public void eval(final OperandStack s) {
s.push(eval(s.pop()));
}
protected abstract int eval(int op1);
}
Tweet This Post Plurk This Post Buzz This Post Delicious This Post Digg This Post Ping This Post Reddit This Post Stumble This Post
Posted in Agile, Design, Java, Programming, Testing | No Comments »
|