Thursday, July 09, 2009
DVCS(hg) vs SVN workflows
We have the following scenarios:
1. We have to do a rather big refactoring, which will take several weeks.
- With svn: we create a 'feature branch' where we'll do the refactoring. We update daily from trunk, we push to trunk regularly/at the end. The feature branch is allowed to be CI-red. (Due to an svn issue merging back-and-forth became a problem for svn-merge-tracking, and we had to do a tree-diff on 2 local sandboxes)
- With hg: you just create a clone-branch, you work on it, you can merge with<->from trunk regularly,
whithout any merging problems.
- Guerilla tactics: shadow the svn trunk/branch with some hg repositories and to the merges with hg (no tree-diff), at the end push the changes to svn
2. Junior (remote) developer needs help fixing a unit-test.
- With svn: do a branch, svn switch to it, push the code with the broken tests, fix them, merge back to trunk.
- With webex: do a remote session an explain the fix
- With hg: just pull the changes, make a fix, push them back to the remote developer. (hint: hg is more network-friendly then svn)
3. An interface between 2 components is changed radically. Both the user & the implementation must be changed.
- With svn: do a branch, do all the changes, merge to trunk
- With hg: change the interface in a cloned repository, then share this repository between the user & implementer. They can work in parallel, the last one finishing pulls the changes from the other one and does the integration.
4. Junior developer, friday@17.00, before a 3 week holiday, wants to commit his _weekly_ changes. He cannot create a local ci build within 1 hour so he doesn't commit anything.
- He shouldn't integrate friday@17.00. (but he did)
- With svn: create a branch, svn switch, push your changes to the server
- With hg: a colleague could pull the changes an do the integration + push the changes, without the need to go through the server.
5. Always keep the code green.
- With svn: run the CI on the pre-commit hook (TeamCity does it). The code get's in the repository only if the build is green
- With hg: maintain 2 repositories: in the 1st one we push the changes, which are peeked by the CI, validate, and on success pushed to another repository. (or just do a rollback; much easier with hg)
A lot of the hg power comes from the fact that is changeset-based (unlike svn) and merges are really easy. Another big plus point goes to the distributed nature of hg: it enables more flexible workflows; in a centralized vcs all the communication is done through the server.
links: hg, git
Thursday, May 07, 2009
Monday, May 04, 2009
15 Min. IoC
Monday, February 23, 2009
Programming Abstractions
Abstraction helps up the percentage of interesting code vr.s boring grunt work code, by minimizing the amount of boring grunt work code. If you can turn five lines of code, replicated ten thousand times, into one line of code, replicated ten thousand times, you’ve just turned a 50 KLOC project into a 10KLOC project, doable at least 5 times faster (and probably more like 25 times faster). Get the crap work out of the way fast, so you can get on to the more interesting stuff.
I’m not even talking about leaving your language of choice, I’m talking about thinking outside the box, or even just thinking. But learning new languages is an advantage in making programming not suck, because if nothing else, it gives you new tools for your tool box, new ways to consider abstracting the code. And some languages are better than others, and the more you know, the more likely you are to know a good one. And if you don’t know the better language, you can’t use it.
My initial response to the DailyWTF post was that it was another classic example of the starving child in Africa syndrome. You’ve seen the pictures. A child in some hell-hole of a third world, generally Africa but parts of Asia and South America qualify as well. The child is hungry, maybe starving, disease ridden, bug infested, and destined for a life that was nasty, brutish, and short. But they’re smiling away, happy as can be, simply because they don’t know any better. Everyone they’ve ever known, seen, or even heard of has been in exactly the same boat they are. That’s just what life is like. I often times think that many programmers are just like that staving child. They put up with, indeed don’t even see anything wrong with, having to write half a dozen lines of code just to set some UI properties, because they’ve never known any better. Bug ridden, virus invested, bloated, slow, impossible to maintain, that’s just what programming is.
The second post is convincing me that the situation is much, much worse than that. That it’s not just ignorance is the problem. It’s not just that many programmers don’t know any better, it’s that many programmers don’t want to know any better, and are looking for an excuse, any excuse, to stay ignorant. It’s as if that starving child doesn’t want food, and would reject food if offered.
The reason that post is causing to me think this is because I’ve heard this argument before. All of them. See, I lived through the last great paradigm shift, when the industry moved from Procedural to Object Oriented- and heard the dying remnants of the one before that, from unstructured to procedural programming. I’ve heard all these arguments, or should I say excuses, before- from people trying to avoid learning C++ and Java.
Slightly related: Erik Meijer @ JAOO2008: 'Why Functional Programming (Still) Matters'
Friday, February 06, 2009
Failure, take two
James Shore - The Decline and Fall of Agile
Martin Fowler - Flaccid Scrum
Ron Jeffries - Context My Foot
Want to succeed at software? Then it can’t be business as usual.
Wednesday, January 28, 2009
pet project idea
Tuesday, January 27, 2009
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
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
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
* 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.
Thursday, November 27, 2008
Pragmatic Compromise
are not the guys who are going to maintain that code? Have you noticed that these guys bully you into delivering features fast, and later they come complaining ' Why is the quality so poor? '.
Even if quality is not seen as corporate asset, make it a part of your professional ethics.
Tuesday, November 11, 2008
DynamicQuery
(post inspired by AutoBoundary proxymatic)
Apparently yes: check-out the LiquidForm.
There are some other alternatives, but java is not there yet.
Monday, November 10, 2008
Scrum Log
It's amazing how much clarity you get at the end of an iteration: the retrospective.
Monday, November 03, 2008
Dark Syntax Highlight
Brackets: 128,255,0
Keywords: 217,167,15
Comments: 0,185,0
Tasks,ToDos: 0,255,0
Thursday, October 23, 2008
API Usability
The first feedback we get from (unit-)tests. Unfortunately a lot of people don't do that.
Another point is that the tests (partially) lie about how the component is used: they represent how the author assumes the component will be used. Feedback from customers and refactorings should follow...
Wednesday, October 22, 2008
Filter support for PropertyConfigurator
Filters are chained to an appender in a specified order. However, the runtime representation of a .properties files is basically a hashtable, and there is no ordering defined on the keys of a plain hashmap. Any implicit ordering of the lines in the properties file is lost when it is parsed. To overcome this, filters are identified by unique IDs, and filters are added to the appender in the lexicographic order of the IDs.
Keeping the notations used by the log4j source code, filters are configured as follows:
log4j.appender.appenderName.filter.ID=fully.qualified.name.of.filter.class
log4j.appender.appenderName.filter.ID.option1=value1
...
log4j.appender.appenderName.filter.ID.optionN=valueN
You can download the patch directly from the log4j bug tracker. It can be applied to the current HEAD of the 1.2 branch, more exactly to 1.2.15.
Friday, October 10, 2008
Coder
Maybe we should call developers 'anti-coders'.
Tuesday, August 19, 2008
Option/Maybe monad is a generic NullObject
ps. Thought's on Validation: Scala/liftweb has an nice Can.
Monday, August 11, 2008
Scala Marketing Challenge
This is a tough sell. If we look at the Change Function:
ChangeFunction = F(PerceivedCrisis/PerceivedPainOfAdoption).
(btw. read Erik Meijer's paper: 'Confessions of a Used Programming Language Salesman', it's really, really good.)
So we'll have to ask ourselves what problem is Scala trying to solve, and how much it'll cost. IMHO, Scala is trying to make programming easier. It partially addresses the concurrency problem, but it is not its main-focus, I would say is the ScalaActors are a good side-effect of Scala's good (language + library) design.
What we'll have to pay in order to make the 'switch': the syntax is slightly different. Functions are 1st level citizens. (but functions/closure are scary). Operator overload is also scary (funny enough, method overload is not scary: we are afraid of symbols but we are not afraid of words). Then we have for a good generic support we have 'Generics of a Higher Type', type covariance/contra-variance. Pretty scary... booh! Did I say that IDE support is not yet at java's level?
On the other side we have a huge number of java developers. They are satisfied. Not really happy, not really sad. Ok, java is not that great, but it has been like this for years, why change? To be more effective? Probably to sell that to a manager you'll need 5 independent studies to show that scala is better then java and you'll need at least one big company to push the language. ('if they use it, we could use it too')
Regarding concurrency: a lot of java developers have problems to right correct code, so probably concurrency is the least of their problems. Other developers we'll say 'we have java.util.concurrency'.
If you look at the package you'll see they offer concurrency primitives, and to write shared-state concurrent programs is very hard. You'll have to think a lot more about object isolation and the threading context.
In conclusion:
- UserPerceivedCrisis: small
- PerceivePainOfAdoption: big
ChangeFunction -tends-to-> small.
sorry, scala...
Friday, August 08, 2008
Thursday, July 31, 2008
hg vs git, pull+merge vs rebase
GIT encourages rebasing, which leads to rebasing of your public and other people's
code. This is bad.
Mercurial, which hashes a changeset's place in history as well as it's
content, discourages rebasing. Rebasing happens in private with mq patch queues.
Public trees are merged. This is good.
Either style is possible with both tools. The difference is the default emphasis.
Defaults matter.
Linus Torvalds on rebasing:
* http://kerneltrap.org/Linux/Git_Management
* http://lwn.net/Articles/291302/
* http://lwn.net/Articles/291303/
* http://lwn.net/Articles/291304/
Matt Mackall on synchronizing (pull + merge, don't push, don't rebase):
* http://www.selenic.com/pipermail/mercurial/2008-July/020116.html
* http://www.selenic.com/pipermail/mercurial/2008-July/020131.html