Wednesday, January 28, 2009

pet project idea

Implement a 'bean-mapper' a la Dozer, but instead of using the xml files, use dynamic proxies, a la LiquidForm.

Tuesday, January 27, 2009

Failure

Failure

"The only failure is the failure to learn from failure" -- Kevin Everett FitzMaurice

A friend of mine notice that in a big company, which recently decided to embrace agile and use Scrum, the Scrum practices are applied in a mechanical way. Actually he called it a 'theater', and he said that the 'agile principles' are important. A colleague had a similar observation, that Scrum is applied in an american-indian-ceremony kind-of way, expecting that the results will fall out of the sky.

Maybe this is related to the 'Shu Ha Ri' training cycle, which:
TheThreeExtremos lately seem to be recommending a ShuHaRi approach to XP: First, follow all the practices. Then, realize TheyreJustRules, and change them (i.e. break some of the original rules). Finally, you don't need to think about the rules anymore. -- GeorgePaci

But in day-to-day business, it is just sloppiness. People don't understand that they are on a learning journey, they don't understand why are they following the practices/rules. Some don't want to learn, they just one to get the job done and go home. Many people are just happy with Ship-It. We've done, it, we are happy, let's go home. No retrospection, no how-can-we-do-it-better-next-time, no 5-whys. There is no striving towards elegance, to do things better. No passion, no motivation. Probably that's why retrospective are the first to be dropped/disregarded.

Does this mean that Agile/(Scrum?) is a culture-thing? How can we change a 'not-my-problem' culture? How can we stop sinking in a pool of problems? How can we start carrying?

ps. via rangawald's delicious, I found Taming Perfectionism.

Friday, January 16, 2009

The Membrane

Suppose we have 4 coupled/chained objects: A, B, C, D, accessible through the properties A.B.C.D, and the objects have the following properties:

A: B, A1, A2
B: C, B1, B2, B3
C: D, C1, C2
D: D1, D2, D3

Usually within a certain area/component, we don't need all that object tree, but just a projection/subset of it: eg. IView { A1, B1, C1, D1. }
In practice, the problem is that most of the people will use/scatter these properties all over their code, leading to maintenance monsters:
- navigation is all over the place, violating the 'Law of Demeter'.
- Testing is getting a lot more difficult: in order to test a user of IView you need to instatiate A, B, C, D, these might have good constructors which force you to instatiate other X objects, etc.
- The amount of code using chained objects/train wrecks will crush future refactorings: if you'll want to reverse the navigation from B.C to C.B, you'll have to change all the usage points, the same goes for changing a data type.

Possible solutions:
a. Define the projection as required by that component/use case, eg IView { A1, B1, C1, D1 } (properties, or getter/setter, etc.)
- Define a repository service IRepository.get(...) -> IView
- Work against your abstraction IRepository/IView

The IView/IRepository could build through:
- DTOs mapping (a la dozer & co.)
- wrap & lazy fetch:
View {
ctor(A a) { _a = a; }
A1 { _a.A1 }
B1 { _a.B.B1}
C1 { _a.B.C.C1 }
D1 { _a.B.C.D1 }
}
(a pretty slick solution might be build with LINQ expressions)
In this way we have isolated our component from external changes, we are depending only on our IRepository/IView, future refactorings will afect only that area.
The IRepository/IView abstractions represent the membrane to the external world. (Ralf refers to the pattern as 'external adapter', probably refering to Alistair Cockburn's 'Hexagonal Architecture' paper, I prefer the Alan Kay's metaphor).

b. Instead of defining the projection IView we could add the required operations on A. This has the benefit of aggregating/reusing common operations on A (usually a root entity).
In some cases it might lead to the polution of A: all the properties/operations beneath the A will emerge into A, transforming the tree into a list. Class A will become too big, containing its data, and n+ operations (C# has region-folding, smalltalk has protocols for organizing big classes)

Final thoughts:
- it is not about DDD/Tell don't Ask vs EJB/DTOs vs XXX, but is about isolation/visibility.
- (Unit) Testing asap helps a lot identifying architecture/design smells.

Friday, January 09, 2009

toString or not toString

suppose we have an Id class, which used as a 'pointer' to some persistent entities.

abstract class Id {
T _raw;
Id(T raw) { _raw = raw; }
@Overrride void toString() { return _raw.toString(); }
}

And the Object#toString() documentation says:
/**
* Returns a string representation of the object. In general, the
* #toString method returns a string that
* "textually represents" this object. The result should
* be a concise but informative representation that is easy for a
* person to read.
* It is recommended that all subclasses override this method.
*
* The #toString method for class Object
* returns a string consisting of the name of the class of which the
* object is an instance, the at-sign character `@', and
* the unsigned hexadecimal representation of the hash code of the
* object. In other words, this method returns a string equal to the
* value of:
* getClass().getName() + '@' + Integer.toHexString(hashCode())
**/

What is the problem?

* we heavily use these Ids in a *lot* of places
* id.toString() is used both for Id -> String conversion, as a part of our design and as textual representation for debugging/logging
* to subclasses AID and BID will have the same textual representation, making future debugging/logging more confusing then necessary
* if we enrich the Id with more data (eg. a timestamp, or entity version, etc.) we can no longer not add this extra data to its textual representation (eg. logging), since toString() is also used for conversion
** it is very hard to find all the usages of the toString method, since every IDE (and the compiler too) considers this method belonging to the Object and not to the abstraction Id (that's why the @Override is there)
*** if we would have worked in a TDD kind-of way, we probably would have started with an interface, IUniqueId, to which we probably would have added a method asString()

concluding advice: when you model your own domain language/design, be careful what you override.