Sunday, November 27, 2005 

Deferred Events in UML 2

In the past few days I've spent a handful of minutes working on a draft section on Deferred Events for my UML 2 Manuale di Stile (in Italian). I was also thinking about a good example to introduce the concept, something familiar enough that readers would pick up the idea immediately. Well, today I was printing a document and the printer was already out of paper. I added some paper, pressed a "reset" (sic) button, and got my document. Here it was, my well-known example of deferred event, just waiting for me :-).

Saturday, November 26, 2005 

64 Bits - It's MS-DOS all around :-))

A few weeks ago I was talking with a customer about the challenge and potential rewards of moving their software to 64 bits. In the past few days, I received a call for papers and an article to review on the same topic. Overall, I expect a *lot* of C/C++ software to fail when moved to 64 bits. The reason is simple: too much code has never been written with portability in mind. Readers old enough to remember the MS-DOS era will probably remember how hard it was to port software from the Unix world to MS-DOS. I'm not talking about system programming: even most "computational" stuff like, e.g., a prolog interpreter was hard to port. The reason was not the 640KB limit. Sure, it didn't help, but many Unix workstations in those days had a whooping 2 to 8 MB, so we could reasonably expect to fit some interesting software in 640KB. The problem was that most of that code was crappy (sorry for the fan[atics] :-). Most often, it was written from the ground up with some assumptions, like sizeof( int ) == sizeof( long ) == sizeof( void* ), which simply didn't [down]scale well to poor MS-DOS. You could certainly port such code (in a few cases I did), but it was a long, boring, error prone activity.
Well, guess what? A lot of C/C++ code today is still based on the same assumptions. Moving Windows to a 32 bits model removed all those pesky memory models, but allowed people to keep, or learn, old bad habits. Not to mention assumptions about data types alignment constraints, which are usually ignored in the Intel side of the world.
Bottom line? Expect quite a bit of software to require significant time to be successfully ported to a 64 bits model. Even more so if some third-party component is involved, but that's pretty much obvious.
As usual, we could learn a little more by looking outside the WinTel world once in a while. Hewlett-Packard, for instance, published a little book on the subject, HP-UX 64-bit Porting and Transition Guide back in 1998. Some chapters are individually available in HTML, but I'd suggest you get the complete book in PDF (top-left link).

Wednesday, November 23, 2005 

Interfaces Vs. Delegates (or Events)

Languages influence thought processes and ultimately solutions. Therefore, the mere presence of a keyword or construct in a language tends to influence the way we think about problems when we use that language. Experience also influences the way we see problems and design solutions, so previous experience with a specific language tends do influence the way we approach new languages. I've seen this several times, as programmers moved from C to C++ ("should I use a struct or a class?"), from C++ to Java ("should I use an abstract class or an interface?"), and from all the others, including VB, to C# ("should I use an event/delegate or an interface?"). [Note: Events and delegates are different beasts, but similar enough for what I'm going to say that I will just talk about the delegate as a unified concept]. The Interface Vs. Delegate debate has come up several times during design sessions, and even during a short break in my latest lesson at University of Trieste.
Obviously, I'm not the first to write on this topic:
The Delegates Tutorial on MSDN has some guidelines (scroll near the end, "Delegates vs. Interfaces").
Anders Hejlsberg talks about design and performance issues in Delegates, Components, and Simplexity
Jon Shemitz talks about performance too in Delegates vs. Interfaces (this article has been web-published almost everywhere).
Don Box has some thoughts about design issues in Are delegates the moniker of .NET? (never mind the weird title :-). GotDotNet seems to have major problems :-), so here comes the Google Cache to the rescue (scroll down and you'll find it).
Overall, those articles draw a pretty confused picture :-))) so I'll throw in some colors myself :-). More seriously, sooner or later I'll publish something more comprehensive (and definitive :-) on the subject, but right now, I just want to add a few thoughts about design with interfaces Vs. delegates.
Interfaces and Delegates are both contracts. The implementer has to respect the syntactic contract (typing, and names when you use interfaces). The caller has a role in the contract too - I'll be back to this in a short while, as it makes a difference. Delegates are a "weaker" form of contract (Hejlsberg and Box both seem to agree on this point, although they use different words/metaphors). It is weaker because:
1) it does not group together a set of functions
2) it does not force the name of the method
3) it does not force the method to be a member
4) it does not give identity to the callee
I'll give attention only to (4) right now, because it has been somewhat ignored by other authors. When you implement an interface, and you pass a reference to that interface to someone, you're engaging in a contract which says: whenever you call one of those functions, the same object will handle the call [in different methods]. When you expose a set of delegates, you don't have that guarantee. Calls could be redirected to different objects. This breaks the idea of an interface as a whole contract, switching to a model of methods [delegates, actually] as individual contracts. For most people, that means additional freedom and is therefore welcome. However, the lack of an overall contract is not necessarily a good thing. An interface, in UML 2 speaking, may have an associated Protocol State Machine. A PSM is a behavioral contract, opposed to the syntactic contract most people think about. A behavioral contract is a constraint on both sides: the caller must call functions in a specified order, when the callee is in specified (although abstract) states. However, the contract makes sense because there is one, well determined receiver. You can't enforce a contract among a scattered group of delegates.
Bottom line: read the stuff linked above, but add this: if the concept you have in mind is a single contract, encompassing multiple functions, possibly with an associated PSM, use an interface. If you only have individual contracts in your mind, you can use delegates.
For more on PSM, my italian readers may want to read my UML 2 Manuale di Stile.

Monday, November 21, 2005 

Learning

A question I get asked quite often is how much time I'm spending learning new stuff. I don't have exact numbers, and I'm pretty sure there is a significant variance over months. For instance, if I become interested in some new technology or concept, or if I have to learn some entirely new application domain, numbers may shift heavily on the learning side for a while. Overall, I guess I'm spending about 30% of my professional time teaching, 20% learning, 50% practicing. I usually teach only what I've practiced long enough: that means I'm never the first to come up with courses on newfangled technologies, but I won't feel comfortable teaching what I've never applied in the real world.
This may not be the right balance for you, but any distribution where one (or more :-) of the three figures is near zero won't be doing you any good in the long run. Of course, learning is much more than just reading or listening. A significant portion of the learning time goes into creating the right connections between individual pieces of information. This is how you gain perspective. And finally, everything must be tried out in the real world: practice is the ultimate benchmark of how good, how fit, how useful any principle, method, technique or tool can ever be.

Turning developers into users

While teaching my Project Management course, I discusses a few monitoring tools like Standard Task Units, and mentioned that (unfortunately) I don't know any good software tool to create and maintain those diagrams. A few participants joked (sort of :-) about adapting one of the company's tools to draw those diagrams. Although we weren't serious about that (I guess :-)), this would have had a significant impact on the company: it would have turned all the developers into users, although peculiar users. This does make a difference, because it's an interesting way to remove a conceptual barrier; "thinking like users" is much much easier when we are users :-).
A few years ago we used to say eat your own dog food to encourage companies to use their own products. Judging by what I see every day, I guess that wasn't really appealing :-). For more on the origin of that term, see the Wikipedia.

Sunday, November 13, 2005 

Semantic Blog - 10 minutes :-)

In an old posting I discussed the idea of a custom search engine for the semantic blog, and since then I've decorated my postings with invisible semantic tags. I also said that implementing a simple, custom search engine powered by semantic tags should be a matter of a few hours (in PHP, but anyway :-). Well, today I've spent the first 10 minutes on that, just before leaving. I'm teaching my course in Project Management tomorrow and Tuesday, then travel to another customer site, then at University of Trieste. Quite a week :-).

Friday, November 11, 2005 

A tale of two teams

One of my customers has two teams (about 20 developers each) working on different projects in the same domain. Projects tend to be rather long (in modern speaking :-), taking from 6 to 12 months to complete. Both teams have a somewhat defined development process, though they don't use formal documents. They both use UML, GUI prototyping, a separate testing team. The use different programming languages, but this is probably just marginally related to the difference between the two teams. Because there is a difference.
Team A is approaching new projects with a somewhat long preparation. Marketing is providing sketchy requirements, and they have to do their best with that (as it's unfortunately common, they don't seem to get along well). They will build prototypes several times before the user interaction is approved. They will analyze the problem in depth, build design models, then go ahead and implement the system, with some degree of iteration between design and coding, trying to avoid requirement creeps.
Team B is approaching new projects with a shorter preparation. They are not using an XP or agile approach. Quite the opposite, they will have a solid design as well before they start. The team, however, can afford a shorter preparation because they did some part of if during the previous release. Of course, that means they didn't went in the larval state of coding for as long as Team A did. They resurfaced often, thinking about the next product, experimenting with new technologies, talking with marketing guys about what could be next, trying to influence marketing as well, and so on. There is definitely less conflict between Team B and marketing, although it must be said that they talk to different people than Team A does.
The teams didn't chose their style. They are, I believe, the natural consequence of the personality, beliefs, and attitudes of their managers. However, members of one team are much happier than the others (guess which? :-). Now, I understand happiness may not be concern #1 in most work environments, but it should be. If you're not happy with your job, there is no way you can perform at your best. Multiply this by 20, do a little math, and you'll see how much money is being wasted (both current money, in terms of salary, and future money, in terms of revenue from what they're building).

Wednesday, November 09, 2005 

Sudoku - Structural and Procedural Complexity

I never played sudoku until a few days ago, when I was too tired to do anything useful during while traveling, and found one on a newspaper.
I usually don't like games with complex rules, so I guess I should like sudoku - rules are extremely simple, but the game can be challenging.
However, I quickly became more interested in thinking about a good object oriented design for a sudoku solver. Writing a solver is relatively easy, especially if you use simple strategies and maybe some backtracking (of course, better heuristics would make backtracking unnecessary in many cases). Still, if you structure your code around the algorithmic side, you'll end up with the usual mess :-) of procedural complexity.
Some of the solving strategies, on the other hand, seems to have a very natural object oriented flavor. Rows, columns and squares all have their own individual strategies. The outer square may get involved only when crossing strategies are concerned. Cells may contribute with their own intelligence (e.g. by keeping track of allowed configuration). Sure thing, you can bring procedural complexity down to a very elegant and manageable level, probably without any sensible impact on performance.
The OO model, however, won't be simple. We lack a very desirable property in the description above: low data coupling. Actually, the outer square, the inside squares, rows and columns are all inter-dependent on some level, as they share the underlying cells. This would make the structure more complex than I would like to. Add some kind of GUI, and you may end up with some kind of observer on steroids.
Is there a way to keep procedural complexity to a minimum for this problem, without ending up with high structural complexity? I don't have much time to think about it right now, but I could always turn this into a small scale design problem for one of my introductory courses :-)

Friday, November 04, 2005 

Two quotations of the day

1) "All models are wrong… some models are useful" (Prof. George E.P. Box, University of Wisconsin).
Models are wrong because you can always find a detail in the real thing that isn't represented in the model. That's why they are models and not the real thing. Some models are useful, that is, they abstract away irrelevant details, therefore making the important (remaining) details more visible, easier to manipulate and to reason about. A model that is useful for a specific purpose may therefore be totally useless for another, if the necessary details are not in the model. However, if you build a model by adding all the details needed to reason about each and every aspect of the thing, you're making your models useless: in the end, they won't abstract away anything, therefore making your reasoning just as hard as with the real thing.
Therefore, I would go even further and say "All models are wrong... some models are useful, exactly because they're wrong - but in the right way. See also The Power of Incompleteness.
2) "How does a one-year project get to be two years late? One day at a time" (Fred Brooks).
Gerald Weinberg changed this into: "How does a one-year project get to be two years late? One day at a time, with everybody's eyes closed". I wish I could add more, but I can't :-)

Wednesday, November 02, 2005 

Stop thinking "feature", think "value"

So, your project is going to be late and over budget. Does that make you and incompetent manager? An incompetent architect? An incompetent developer? Well, it depends.
No, it does not depend on whether your original plan was "right", but then requirements changed and new features crept in. That always happens. The critical question is: if we ship now, do we have enough value in our product?
Optimizing delivered value is not easy. It requires fundamental skills at every level:
manager: must be able to define the value of all features. Business value, marketing value, user value. Pick one (hopefully the most important) but be systematic along a project. Must be able to see the small value-delivering product inside a list of features. This ability is sorely lacking in many projects I see. That makes management's life easier, but this is not what I would call good management.
designer: must create a modular architecture, where features with low value can be plugged in later. Must avoid overambitious infrastructures which will postpone delivery of value. Or, must be able to provide real numbers on the risk and ROI of those infrastructures. Must design a system so that high value features can be implemented sooner than low value features.
developer: should tactically optimize for value. Should advise the designers and the managers on value-optimizing opportunities they may not be able to see. Should write working code, test it, and then move the next value-creating feature. Should avoid half-working code like the plague. Half-working features have no value.
At all levels, we must understand that we are embarking into a knowledge discovery journey. Customers will change their mind as they gain new knowledge. So will managers. So will designers. So will developers. We must be able to design some flexibility into our product, and change (even dramatically change) our plans throughout the journey. I still value the time spent planning and designing. But plans are a flexible, working tool, not a promise carved in stone.
So, your project is going to be late and over budget. But if we ship today, will we deliver enough value? If so, you did a good job, no matter what. Features can wait. Value can't.
See also the concepts of Incremental Funding and Minimum Marketable Features, that I've already mentioned elsewhere.

Labels: