martinfowler.com logo Home Blog Articles Books About Me Contact Me ThoughtWorks

Design bliki


AbundantMutation, AcademicRotation, AccessModifier, Agiledox, AltNetConf, AnemicDomainModel, Annotation, ApplicationBoundary, ApplicationDatabase, AssetCapture, BuildLanguage, BuildingArchitect, CallSuper, CatastrophicFailover, CheaperTalentHypothesis, ClassInstanceVariable, ClockWrapper, Closure, Closures, CobolInference, CodeSmell, CollectionClosureMethod, CommandOrientedInterface, CommandQuerySeparation, ConstructorInitialization, ContextualValidation, ContradictoryObservations, CourtesyImplementation, CurrencyAsValue, CustomerLoyaltySoftware, DataClump, DataModels, DatabaseStyles, DatabaseThaw, DecoratedCommand, DesignPayoffLine, DesignStaminaHypothesis, DesignedInheritance, Detestable, DiffDebugging, DirectingAttitude, DuckInterface, DynamicTypeCheck, DynamicTyping, EagerReadDerivation, EnablingAttitude, EncapsulatedCollection, EnterpriseArchitecture, ErraticTestFailure, EvansClassification, EventInterception, EventPoster, FirstLaw, FixedLengthString, FoundationFramework, GangOfFour, GetterEradicator, HarvestedFramework, HeaderInterface, HierarchicDataModel, HistoryIsNotBunk, HollywoodPrinciple, HumaneInterface, HumaneRegistry, IllustrativeProgramming, ImplicitInterfaceImplementation, InMemoryTestDatabase, IntegrationDatabase, InterfaceImplementationPair, InversionOfControl, JAOO2005, JunitNewInstance, LanguageForLearningObjects, LayProgrammer, LayeringPrinciples, LazyInitialization, LocalDTO, MakingStubs, MinimalInterface, ModelDrivenSoftwareDevelopment, MultipleCanonicalModels, NashvilleProject, NetworkDataModel, OOPSLA2004, OOPSLA2005, ObjectMother, ObservableState, OneLanguage, OpenInheritance, OutputBuildTarget, POJO, PatternShare, PatternsAreNothingNew, PostModernProgramming, PresentationDomainSeparation, ProjectionalEditing, ProtectedData, ProvideServiceStub, PublicCsharpFields, PublishedInterface, RelationalDataModel, ReportingDatabase, RepositoryBasedCode, RequestStreamMap, RoleInterface, RulesEngine, Seal, SecurityAndDesign, Seedwork, SegmentationByFreshness, SelfEncapsulation, SelfTestingCode, SemanticDiff, ServiceCustodian, ServiceOrientedAmbiguity, SetterInitialization, SmalltalkBooks, SoftwareDevelopmentAttitude, SourceBasedCode, SourceEditing, StaticSubstitution, StranglerApplication, SunkCostDrivenArchitecture, TechnicalDebt, TestCancer, TestDouble, TestDrivenDevelopment, TestInvariant, TestingResourcePools, TimeZoneUncertainty, TouchFile, Transactionless, TypeInstanceHomonym, TypedCollection, UbiquitousLanguage, UiPatternsReadings, UseOfXml, ValueObject, VotingMachines, Wardish, Web2.0, Xunit


RequestStreamMap design 1 July 2009 Reactions

Hang around my colleagues at ThoughtWorks and you soon get the impression that the only good Enterprise Service Bus (ESB) is a dead ESB. Jim Webber refers to them as Egregious Spaghetti Boxes. So it's not uncommon to hear tales of attempts to get them out of systems that don't need them.

Battle was joined at one client and it brought to mind my younger days playing D&D. Webber swings but misses as the ESB is AC 2, Evan gets a hit and rolls 2d8 for 6 damage. Erik finally kills it by casting "Summon Request Stream Map".

So what was Erik's decisive spell? Essentially the idea was to take a simple request and show how the data for the request and response made their way through the layers of the application. Erik printed out all the code that you needed to read to understand how this would work - which ran to several pages. He also produced this diagram.

It's currently fashionable in agile circles to do Value Stream Mapping as a way to uncover waste in a software development process. I think of this as a request stream map because it similarly takes a request and shows how it moves through the layers allowing us to visualize what's going on and think about the cost and value of the layers.

Layering is an essential tool for building software applications. But like most essential things in life, excess can be almost as much of a problem as too little. A visualization like this (or the multiple pages of code) can help you find where "just enough" is.

One hazard, however. If you do need to transform data from one form to another, it's usually better to a few little transformations than one big transformation. You want to avoid unnecessary transformations not compress the ones you need.


IllustrativeProgramming design 30 June 2009 Reactions

What's the most common programming language in the world?

I'm not sure how you could go about measuring this, but one thing you'd need to do is consider what we mean by programming. My candidate answer considers that the most popular programming language is one used widely by people who do not consider themselves as programmers. This language is Excel, or more generally spreadsheets.

Spreadsheets are easily used for small tasks, but are also used for surprisingly complex and important things. Often I've seen professional programmers gulp when they realize that some vital business function is being run off some spreadsheet that they'd find too complicated to muck with.

In general, we've not had much success with programming languages for these kind of LayProgrammers. Whenever someone talks about some new environment that's going to allow people to specify complex behavior "without programming" I mention COBOL, which was originally designed to get rid of programmers. So it's important to consider what Excel can teach us about programming environments.

One property of spreadsheets, that I think is important, is its ability to fuse the execution of the program together with its definition. When you look at a spreadsheet, the formulae of the spreadsheet are not immediately apparent, instead what you see is the calculated numbers - an illustration of what the program does.

Using examples as a first class element of a programming environment crops up in other places - UI designers also have this. Providing a concrete illustration of the program output helps people understand what the program definition does, so they can more easily reason about behavior.

So why do I feel we need this particular Neologism? Essentially because I think it deserves more thought. We pass by illustrative programming examples without really thinking about them or what makes them special - or even that they are special in some way. We've used illustrative programming for years, but we've not paid enough attention to it. We've not thought enough about what are its essential qualities and what its strengths and weaknesses are.

I've chosen the term "Illustrative Programming" to describe this, partly because "example" is so heavily used (and illustration isn't) but also because the term "illustration" reinforces the explanatory nature of the example execution. Illustrations are meant to help explain a concept by giving you a different way of looking at it - similarly an illustrative execution is there to help you see what your program does as you change it.

When trying to make a concept explicit like this, it's useful to think about the boundary cases. One boundary is the notion of using projections of program information during editing, such as an IDE that shows you the class hierarchy while you are working on the code. In some ways this is similar, as the hierarchy display is continuously updated as you modify the program, but the crucial difference is that the hierarchy can be derived from static information about the program. Illustrative programming requires information from the actual running of the program.

I also see illustrative programming as a concept beyond the classic REPL loop of dynamic languages. REPL loops allow you to explore execution, but they don't make the examples front and center in the way that a spreadsheet does its values. Illustrative programming techniques put the illustration in the foreground of your editing experience. The program retreats to the background, peeping out only when we want to explore a part of the illustration.

I don't think that illustrative programming is all goodness. One problem I've seen with spreadsheets and with GUI designers is that they do a good job of revealing what a program does, but de-emphasizes program structure. As a result complicated spreadsheets and UI panels are often difficult to understand and modify. They are often riven with uncontrolled copy-and-paste programming.

This strikes me as a consequence of the fact that the program is de-emphasized in favor of the illustrations. As a result the programmers don't think to take care of it. We suffer enough from a lack of care of programs even in regular programming, so it's hardly shocking that this occurs with illustrative programs written by lay programmers. But this problem leads us to create programs that quickly become unmaintainable as they grow. The challenge for future illustrative programming environments is to help develop a well structured program behind the illustrations - although the illustrations may also make us rethink what a well structured program is.

The hard part of this may well be the ability to easily create new abstractions. One of my observations of rich client UI software is that they get tangled because the UI builders think only in terms of screens and controls. My experiments here suggest to me that you need to find the right abstractions for you program, which will take a different form. But these abstractions won't be supported by the screen builder as it can only illustrate the abstractions it knows about.

My colleagues Rebecca Parsons and Neal Ford have been spending a lot of time involved in thinking along these lines too. So here's some thoughts that Neal had in an email exchange

  • I think these tools work best for lay people (thus, your link to LayProgrammers). However, in general, tools like this slow down experienced/power users. When you mention UI panels, the Mac is rife with these types of controls. I spend a great deal of time in Keynote, fiddling with the inspector. At least all those controls are in one place (not like the new ribbon stuff). I would much prefer a markup language I could use to directly define stuff, with macros, snippets, and all the other things I'm accustomed to as a developer.
  • as these tools grow, they get unwieldy (perhaps because they are ceasing to be domain specific enough?) Look at Word, Excel, and PowerPoint. They had to invent new UI metaphors to expose all the functionality of those tools. APIs in programming languages scale much better, with several orders of magnitude more density before they become hard to navigate.
  • All the best-practices and tools don't exist there: refactoring, levels of testing, etc. Also, you loose the connection to text, meaning that macro facilities either don't exist or complex one-offs. I think a good comparison that highlights the limitations of Illustrative Programming is the comparison between bash (large, arcane, powerful, quirky) to Automator. I almost never use Automator because it suffers from Dietzler's Law: it's always lacking 10% of what I need. I gladly deal with the crufty surface area of bash because of the more power afforded.
  • I share your bullishness around these types of tools, but they are a long time from being useful for full-bore Agile development. I hope they mature fast.

--Neal Ford

One of the few people to take illustrative programming seriously is Jonathan Edwards. He's come up with many very imaginative ideas as to what such an environment should look like. His vision of illustrative programming is also closely bound to the notions of projectional editing and controlled copy-and-paste.

The trigger for me in wanting to coin a term here, is the use of illustrative programming by Language Workbenches by people like IntentionalSoftware. These Language Workbenches encourage you to build illustrative DSLs. Using illustration is important in this case since this should help engage lay-programmers, which is one of the aims of using DSLs. The challenge is to do this without falling into the trap of poor program structure.


DynamicTypeCheck design 2 June 2009 Reactions

Recently some of our developers ran into the accusation that with a dynamic language like ruby you use so many dynamic type checks that you end up effectively writing your own type system. So they thought, since we've written a lot of real ruby code - how often do we make dynamic type checks? Michael Schubert gathered up the data.

The table below contains the data. We define a dynamic type check as the use of the methods is_a?, kind_of?, and instance_of?. The lines of code come from the standard rake stats command in rails.

Project IDCodeTestLOC /
type check
test LOC /
code LOC
type
checks
Lines
of Code
type
checks
Lines
of Code
A16133180985614480.7
B141913801712325900.9
C02607029811.1
D74265340698331.0
E3229619609768813843.3
F18~9500N/AN/A528N/A
G02455032901.3
H92220664045752.9
I23106332123319191.2
J1964046124885115862.2
K175769698486791.7

The moral of this data is that you shouldn't expect to see a lot of type check calls in your ruby code base. This, of course, is true of any dynamic language. It was generally considered bad form in Smalltalk circles I inhabited too.

The methods that were checked for in this data aren't the only ones that can be considered a dynamic type check. Other cases are respond_to? and aClass === anInstance. Our folks felt that these cases were no more common than the ones they checked for.

Most uses are those of dealing with liberal input - eg where a method parameter can be a string, symbol, or array. These crop up in DSLish situations where you want liberal input for the high readability.


ContradictoryObservations design 3 March 2009 Reactions

Many computer systems are built to house data and turn it into useful information for humans. When we do this there is a natural desire to make that information consistent. After all what use is there of a computer system that's in two minds about things?

But sometimes computer systems should record contradictory data and help humans deal with that. This issue came foremost to my mind many years ago when working in health care for the UK National Health Service. We were building a conceptual model for health care delivery - essentially a conceptual schema for an electronic health care record.

Looking back on it, there were certainly plenty of things I'd do differently now. But one thing in particular was something very precious and important - the model was very much a collaborative effort between myself, another software developer, two doctors and a nurse. The clinicians understood the model and played a full part in developing it - they were not merely passive reviewers. As a result I think the ideas we developed were particularly valuable in thinking about what a clinical practitioner wants to see in an electronic health care record.

One thing the clinicians were very strong about was this need to capture contradictory information. I might have a note from the Royal Hope Hospital saying my blood type is A and another note from the Sisters of Plenitude saying my blood type is B. This would clearly be nonsense, blood types don't change. But that doesn't mean we cannot record these two bits of data. Without further investigation we don't know which one is correct. Even if we test again and confirm one of them, we can't just throw away the bad one as it may have been the basis for further clinical action. And of course there are lots of cases where the contradiction isn't as clear cut. We may never be able to find out which of two contradictory bits of data was wrong or may find a change over time that is extremely unlikely but not impossible.

The key to handling this issue is to represent my blood type not as an attribute of a person class, but as a fully fledged class in its own right - which we called observation. Each observation applies to a particular patient, but also records such information as when it was made, who made it, and how it was made.

We also saw that observations can be about the absence of things as much as about their presence. So in some circumstances it may not be possible to figure out my blood group, but it is possible to say that it isn't blood group O. This we could represent as an observation of an absence of blood group O. (I have no idea if this example is possible or reasonable, but it can get tricky to think up realistic examples quickly.) Often observing the absence of things is crucial in a diagnostic process.

Using observations changes the way we determine information about a patient. Rather than simply asking for a patient's blood group, we look at all the patient's blood group observations. If they are all the same, then we just use that value. If they differ, we need to delve deeper. In many cases observations do sensibly change over time, so we might look at all the observations of my weight over time to plot how my weight changes.

Although we need to keep contradictory observations, we also need to capture if we think one of them was wrong. Some observations, such as a broken leg, will become untrue over time, but the blood group example above is more likely to be a error. In the erroneous case we have the notion of rejecting one observation with another. So we might have a further test in the Albion Hospital that finds I'm Blood Group A, this observation would then reject the Sisters of Plenitude's observation. Rejecting an observation says that we believe it was never true. We never delete the old observation, instead we mark it as rejected and link it to Albion Hospital's observation.

An important property of information is that it's used to guide behavior. A rejected observation may have been used as evidence for further observations or to justify interventions. Keeping these links in the record is essential since once an observation is rejected we can then follow those links to investigate the consequences. If the observation we've just rejected is a crucial part of evidence for another observation, that should be questioned and maybe rejected as well. Observations thus form a web of evidence that we can examine as we learn more about the patient.

Most of the time, of course, we don't use complicated schemes like this. We mostly program in a world that we assume is consistent. But there are times where we have to step away from that comfortable assumption. When that happens then explicit observations are a useful tool

(If you are interested in more of this, see Chapter 3 of Analysis Patterns. I'm sure I'd write it better if I were to do it again now, but the core concepts still seem to hold up pretty well. I'd also like to call out my colleagues on this work: Tom Cairns, Anne Casey, Mark Thursz, and Hazim Timimi)


TechnicalDebt design 26 February 2009 Reactions

Update: Added a link to Ward Cunningham's video opinion

You have a piece of functionality that you need to add to your system. You see two ways to do it, one is quick to do but is messy - you are sure that it will make further changes harder in the future. The other results in a cleaner design, but will take longer to put in place.

Technical Debt is a wonderful metaphor developed by Ward Cunningham to help us think about this problem. In this metaphor, doing things the quick and dirty way sets us up with a technical debt, which is similar to a financial debt. Like a financial debt, the technical debt incurs interest payments, which come in the form of the extra effort that we have to do in future development because of the quick and dirty design choice. We can choose to continue paying the interest, or we can pay down the principal by refactoring the quick and dirty design into the better design. Although it costs to pay down the principal, we gain by reduced interest payments in the future.

The metaphor also explains why it may be sensible to do the quick and dirty approach. Just as a business incurs some debt to take advantage of a market opportunity developers may incur technical debt to hit an important deadline. The all too common problem is that development organizations let their debt get out of control and spend most of their future development effort paying crippling interest payments.

The tricky thing about technical debt, of course, is that unlike money it's impossible to measure effectively. The interest payments hurt a team's productivity, but since we CannotMeasureProductivity, we can't really see the true effect of our technical debt.

One thing that is easily missed is that you only make money on your loan by delivering. Following the DesignStaminaHypothesis, you need to deliver before you reach the design payoff line to give you any chance of making a gain on your debt. Even below the line you have to trade-off the value you get from early delivery against the interest payments and principal pay-down that you'll incur.

(As far as I can tell, Ward first introduced this concept in an experience report for OOPSLA 1992. It has also been discussed on the wiki.)

Additional Comments

Ward Cunningham has a video talk where he discusses this metaphor he created.

A couple of readers sent in some similarly good names. David Panariti refers to ugly programming as deficit programming. Apparantly he originally started using a few years ago when it fitted in with government policy; I suppose it's natural again now.

Scott Wood suggested "Technical Inflation could be viewed as the ground lost when the current level of technology surpasses that of the foundation of your product to the extent that it begins losing compatibility with the industry. Examples of this would be falling behind in versions of a language to the point where your code is no longer compatible with main stream compilers."

Steve McConnell brings out several good points in the metaphor, particularly how keeping your unintended debt down gives you more room to intentionally take on debt when it's useful to do so. I also like his notion of minimum payments (which are very high to fix issues with embedded systems as opposed to web sites).

(Original posting 3 Aug 2004.)


NashvilleProject design 25 February 2009 Reactions

I spent some time recently with one of my favorite ever ThoughtWorks projects. It's a project that started in 1998, using then new J2EE technology. Over the years it's had a fascinating history: starting with EJBs, ripping them out, going offshore to Bangalore, coming back to Chicago. Many people have moved in and out of the project and the project has varied in head-count between 6 and 60. Overall the project has had over 300 staff-years of effort on it and weighs in at around 100 KLOC.

It's a favorite of mine because it exhibits an important property of my preferred view of software development: a long term support of a business function enabled by a well-designed code-base. The fact that they are still adding useful business value after ten years is an big dollop of kudos. They are able to rapidly add new features when needed so haven't fallen into the typical morass of a legacy app.

On this visit a couple of thoughts grabbed me.

Firstly they've had an interesting evolution in their approach to acceptance tests and how they update them as they add new features. In their original (and common) world view, each time you implement a new story you add one or more tests. This leads you to a simple tracing structure where each story is verified by one or more acceptance tests. But the problem with this approach is that over time the tests grow in complexity with much duplication.

In their new world view there is a suite of acceptance tests that describe the application behavior in SpecificationByExample style. Each time they play a new story, they decide how to update this suite to reflect the new behavior. This breaks the simple story-to-test relationship, but results in a much simpler and coherent suite of tests.

The second interesting aspect of the project is how it continues to work at improving the code base. They came up with a good, if informal, metric for describing this. A few years ago, if they wanted to take on someone new they wanted that person committed for at least a year, so they could get contributions that would be worthwhile after coming up to speed on the code base. Now that time is down to three months. For a ten year old app with that many hands on it, that's quite an achievement.

For me the key purpose of good design is that it allows you to continue working rapidly with the code (the DesignStaminaHypothesis). Assessing how long it takes a developer to be productive with a code base is a good way to sense this design quality. The minimum-commitment length metric is another spin on this same idea. It's not something we can measure objectively, but it is something that a team can consider looking at.

I'm hoping we'll get more people from the project talking about their experiences. They did do a podcast last year (go to thoughtworks podcasts and look for "Keeping Grey Code Fit").


Links
home
bliki
feed 
Translations
Japanese
Spanish
Korean
Chinese
Thai
Categories
agile
design
dsl
leisure
refactoring
ruby
thoughtWorks
tools
uml
writing
Blog Roll
ThoughtBlogs
TW Alumni
Nicholas Carr
Steve Cook
Brian Foote
Simon Harris
Gregor Hohpe
/\ndy Hunt
Ralph Johnson
Patrick Logan
David Ing
Brian Marick
Jeremy Miller
Jimmy Nilsson
Samuel Pepys
Keith Ray
Johanna Rothman
Kathy Sierra
Dave Thomas

martinfowler.com logo mingle logo thoughtworks logo

© Copyright Martin Fowler, all rights reserved