What Cant Who Do? 13
I have a fresh idea. When someone is supposed to change their workstyle to do TDD, and they say “we can’t do that”, how about we assume they’re telling the truth.
The first word is “we”. It may well be that the speaker and the people he represents might not be able to do the work. They’re not saying that it can’t be done. They’re only saying that they can’t do it.
The next word is “can’t” and that’s an interesting word, too. It might mean that they lack the ability or knowledge. That’s ideal, because such things can be taught and can be led. The other sense is that they are not allowed. If it’s like that, then there is going to be some political work going on. But at least you know what you’re getting into.
The other tell is the word “that”. Maybe they should describe what it is that they can’t do, and you can tell if the thing they can’t do is the same thing that you are wanting them to do. Sometimes it is not.
Coercive Immediacy 10
I have been thinking a lot about the “short reach” idea, and tryng to reach beyond it to capture the thing that the good agile project teams have and several others are missing. At the same time, I’ve been reading up on some agile tools (including one by a guy I know) in my spare time. In addition, I am on a mailing list for multisite agile development. Finally, I have been pondering how to work this agile stuff when the developers cannot be co-located due to shortage of office space or shortage of common areas.
I realized that the whole “short reach” thing creates a kind of coercive immediacy.
The corkboard with all the story cards in their four columns has that kind of immediacy. I can’t walk past it without assessing how far we are in the current iteration. I can certainly ignore a web page, or a display in some application on my computer. I can’t walk into the common area past that board without thinking.
Likewise, I could ignore an app that holds story status and backlog, but the cork board is where I go to show that I’ve completed a task and to get the next task. If my stories were assigned to me (rather than allowing self-organization) then I could neglect the corkboard too. I would not have to look at it or think about it. I could hold “my” story card at “my” desk until I decided I was done. When we are self-organizing, we are always thinking about who could help us, when we can get done, and what is the best way to truly complete this story and move on.
A partner has coercive immediacy. When you are programming in pairs, you don’t answer the phone unless you have to. IM and mail can wait. Interruptions are less welcome. Having two people on the story pushes one to focus. Also, the pair partner is always there to catch the sloppy shortcut, the poor naming, the ill-considered algorithm.
The customer team member also participates, and both feeds and feels the coercive immediacy of the team. Rather than make a guess, the programmer feels the nearness of the customer, and it’s much easier to ask than guess.
I think that TDD shows this most of all. I can’t choose to ignore the red bar. I write a line of code or two, and now my tests pass. The immediacy would be gone with it, except that I know I have some cheesy, minimal-effort code and I can’t leave it that way. I need a better test. When a test fails in some area where I’m not working, I feel the immediacy.
With distribution, multi-site, tools, and the rest I fear that we lose the coercive immediacy of Agile development. If we don’t have a partner in our way/face, then we lose something. If the status board is a tool somewhere, even a really nice tool, but I have to remember to ask for it to see it, then it is not in my way. It doesn’t inspire me.
My thought now is that an agile management tool won’t help unless it is something we have to live with all the time, during pairing, as part of the test/code/refactor cycle. It has to be in our faces, over our heads, and not just tickling the edge of our awareness like a more polite version of “clippy”.
Short Reach 32
I’m always trying to find newer, better, shorter, more powerful ways to explain what Agile is about. I suppose I’m some kind of obsessive about expressive power and economy.
Finally I decided that Agile, as I understand it today, is about the short reach.
It seems to me that all of the agile practices are about shortening our reach, the distance in time-and-space that one leaves an assumption, decision, or line of code untested and unconfirmed. All the practices seem to follow this one rule.
- The customer/analyst is keep in the same room, in the same short reach.
- We feed back the iterations to the customer/analyst so that his every decision has a shorter reach.
- We do iterations to ensure our planning has short reach.
- We keep our teammates very close, in the same room, so that it’s a shorter reach to them.
- The test is written first, so that implementation has shorter feedback on correctness.
- We compile/test frequently because our code time should have a short reach.
- We pair so that our code is instantly vetted through a peer. We don’t pile it up and review it after the tests pass.
- Our planning is based on “yesterday’s weather”, data collected a very short time ago.
- We don’t plan the team structure and the assignments, we self-organize so that tasks are waiting for the shortest time possible.
- We talk face-to-face, not across chat and email and official company documents.
- Tell-dont-ask and the Law of Demeter guide us in keeping the reach of our objects very short.
- We use unit tests to exercise a class directly, and we isolate with mocks to reduce the reach of our tests through the system.
- Shared code ownership means that the guy sitting behind your keyboard has all the permission he needs to do excellent work, even if it impacts existing design.
- Test-first development means that the guy who makes a change knows very quickly whether his change is safe or not. He doesn’t have to wait until the week before integration when the “real” tests are run.
Where does Agile run into logistical or operational difficulties? Wherever a long reach is required or imposed. Where an organization chooses to continue in waterfall-style management, where the team is distributed among managers with appointed “point of contact” and “official channels”, and where the developers are not placed in a common work area agility is very difficult.
I’m not saying that agile techniques can’t work for large companies, but that is an area where a lot of experts are trying (maybe succeeding) to extend the agile techniques and where the average “agilist” finds challenges. When it works, it is almost certain it will be because someone has found a way to shorten the reach of the teams so that all they need to know is never more than a few seconds or minutes away.
At least that’s my half-baked observation of the day. Let me know if I’m wrong here. Or if I’m more right than I think I am.
Using VIM 10
It isn’t done yet, but I figured I would post my work in progress in the meantime for feedback. It’s a little article about the proper use of the VIM editor. I tried to mix in some keystroke quick-reference with the philosophy of the tool in a way that might make it a bit more accessible.
When it’s done (Ha!) I will probably find new places to store it, but for now it’s at my personal blog.
Don’t be afraid to offer corrective assistance, or to recommend sections.
The Two Things Agile 13
For Agile, maybe the Two Things are:
- We can do better/faster this week.
- And this way next week will be better yet.
Code is a Liability 39
I have thought for a long time that code is liability, and that viewing code as a liability has the power to transform our art. I read articles about code-as-a-corporate-asset and most of them are pretty good articles about wringing the value from the code you have, but I still feel that there’s something essentially wrong about it.
Programs are a great means to an end. Don’t get me wrong, I’m in favor of having software and I’m greatly in favor of writing software. I think we would be in pretty poor shape without it. But I can’t call code an asset.
Functionality is clearly an asset. When we can inter-operate with various services (possibly even web services) our businesses produce more business results more quickly. We use software to control machines and to increase public safety in more ways than most of us know (talk to the guys who write the software that controls your car, the over-the-road trucks, forklifts, industrial robots, and aircraft). Software makes our life better and it’s a wonderful thing. I’m all in favor of software functionality and you have to write code to get it.
Our bosses and clients will pay good money to get the functionality they want, and they want it right now! If we could give them what they want without writing a line, it would be a tremendous win. If we could do it with one line or two lines of well-considered code, we would be heroes! Why is doing less so valuable if code is an asset? Clearly less code is better.
Sadly, most companies have to deal with heaping, shaggy mounds of code. Code takes up time and space. It has to be managed. It has to be versioned. It hast to be tracked, and planned. It has to be updated, and packaged, and revised. It needs backup to save us from having to reproduce it by hand. It has to be reviewed (hopefully in an efficient way like pairing). It often drives companies to expand staff and dedicate people to manage it (version control administrators, managers, build czars, consultants, contractors, metric-gathering tool specialists, etc).
Old code gets in the way of new code. Having more code will typically slow development, and will certainly reduce your ability to incorporate new programmers. Of course you’ll need more programmers because you have all this code to deal with. Size has a cost.
The problem doesn’t go away if you artificially reduce the code. Folding a lot of effects into few lines of code makes the code worse. Adding voluminous documentation makes the code worse. Moving it into metadata and models and other forms doesn’t make it any smaller, and often makes it worse. Hand-crafted code is almost always more readable, smaller, more optimal, more focused, more literary in its style than generated code or funky data tables. Since there has to be code, it might as well be the best code we can write. Coding well takes human beings who value minimalism.
It seems that the trick with the functionality/code game is in trying to maintain a positive balance.
We reach a point on some projects where we are producing a positive number of functions with a net loss in lines of code. That’s a wonderful time. We reduce the line count by simplifying the code and eliminating duplication. Sometimes we refactor our code into a more compact form and then only add a very few lines of code to produce a change. If code were an asset, then those moments would be failures instead of triumphs.
Code size reduction is a very good thing. I want the simplest, the smallest, the least code possible, with the least risk of breaking something else in the system. I don’t want big functions that touch everything in sight. I don’t want long complicated blocks of if/else statements. I don’t want monster functions which conglomerate dozens of operations in a single, fat interface. Shallow is good. Short is good. Less code is good. More code is a liability. This isn’t about typing less, it’s about owning less.
This is the point of view that makes test-first (TDD) so important. TDD/BDD has us encode the functionality (the asset) first, and then write minimal code to realize the specified feature. If code is a liability, and function is an asset, this is exactly the right way to do things.
And maybe, just maybe, it might explain why one might open-source less-important useful systems.
It's a Poor Coach Who Slaps The Kids 10
Today I was remembering a bit of advice I received back in the late 80s when I started trying to work with people more. I’d been a programmer for a while, and mainly survived by reading a lot and practicing what I read. I taught myself most of all the programming I knew (I did have some good mentoring peers). I wasn’t much of a people person.
A fellow named Kevin worked on a project with me in the DC area. One day he had the kindness to take me aside. He explained to me how to work with people. He taught me that when someone had an error in their understanding I shouldn’t tell them they were wrong, but rather tell them they were right except for the part where there was an error. He helped me more than he knows. We only had the one project together, and he went on to a different employer and I went on to become me.
He told me that a good coach doesn’t tear down his kids. He doesn’t tell they they stand like a sissy or throw like a girl. Instead, a good coach will let them know what’s right and what’s valuable about what they’re doing, and then explain what to add to their technique to get better results. And he doesn’t tell them everything all at once.
Now I’m a coach. I teach development methods, including agile methods, including TDD. I now work with people more than technology. I also work with a lot of other coaches from time to time. The best ones seem to intuitively understand when to criticize and how, and when to hold their tongues.
In the warm rush of enthusiasm and passion for the art of development, we coaches have to continually remind ourselves that it’s the poor coach indeed who slaps the kids around. We have to instead meet them where they are and look for ways to help them get the results they want.
Kevin’s lesson continues to teach.
Single Ownership in C++ (intro to auto_ptr) 20
I find a lot of C++ programmers experience memory management differently than I do. I used to have the same kinds of problems that they have, but I learned an important rule: every heap object has exactly one owner, and n borrowers.
The way that I realize this is using reference types. Of course, all good C++ programmers write their functions to use the canonical “const T&” parameters whenever possible. Using a reference means that we have an actual object and not a null reference (side effect: no null checks) and we have simple dot notation (side effect: less typing), but I also use this to mean that we are borrowing the object, not owning it. Likewise, if we have to drop the ‘const’, we are still borrowing.
What about passing by pointer? I only do that if I absolutely must accept 0 (null) as a possible value. I always hate to do that. I would rather have an object outright than a pointer that I dereference. If the function is being called by a framework, I don’t get a choice. I might do something like this:void functionName(const Snorkle* snorkleWithNull) { if (0 == snorkleWithNull) { throw SomeIdiotPassedMeANull(); const Snorkle& snorkle = snorkleWithNull; // ... work with snorkle, ignore snorkleWithNull ... }However sick that seems (and it does) it reverts back to the const reference case quickly and I’m left with a reference to a real object. It keeps me from forgetting to dereference when I’m in a hurry, and keeps me from casting. I have to work extra-hard to do bad things, and that’s a good thing. On the other hand, in modern TDD style, with refactoring, it can double the length of a function (hence feeling sick).
Either way, if you are a borrower, you have no right to delete the object. You can reference it for the duration of your function, or (if the intent is that you will have a short-lived object) for the duration of the object lifetime, but no ownership is given by pointer or reference. Remember that we still have a risk of the pointer being dangled, so holding a reference/pointer for longer than a method call should be considered fairly dangerous and must be done rather intentionally.
But what about transfer of ownership? That’s what the auto_ptr in <memory> is for. Yes, it’s a template. If I can’t use templates, I’ll make up something new that acts roughly the same. The auto_ptr is the one structure in C++ that undeniably says “owner”. When I receive an object via auto_ptr, I am now the owner. When I return an auto_ptr from a function, I’ve clearly given up ownership.
The recipient of the auto_ptr has to do something with the referenced object, or else it will be deleted when the auto_ptr passes out of scope. If the recipient decided to release the auto_ptr, they can keep a normal pointer or reference in whatever structure pleases them. They can make a copy and delete the original (remember the warning about dangling).
The trick is to remember that 99% of the time, you want to be a borrower, and that any class that is going to hold a borrower’s reference to an object needs an algorithmic guarantee that the referenced object will outlive the reference.
The scary part is for an object to have a large number of long-term borrowers, because there is the constant fear that one might outlive the owner. In that case, you need to hang the auto_ptr on the shelf and go get some bigger magic. You might actually need the smart pointer. I have created reference-counting pointer templates in several projects, which will cause C++ to act more like a garbage-collecting language. I know that there are 3rd-party libraries for garbage-collecting. If I find myself in a situation where there are a number of long-term borrowers, I will definitely move in one of these directions again. It is too important to leave object ownership up to chance or naming convention.
Solution Probleming 20
I’ve been fortunate enough to have spent most of the past three weeks teaching advanced Object-Oriented Design with patterns. The students have been wonderful and helpful and brilliant, so the classes have gone very well.
As I introduced students to Visitors, Adaptors, Chain of Responsibility, and mult-level State patterns, I was reminded of the problem that was rampant in the 90s: Having learned a catalog of patterns, many OO designers could not wait to put them into practice. Rather than using patterns to solve problems, they began to look for ways to apply these pattern solutions.
I call it “solution probleming”, which is of course the opposite of “problem solving.”
It wasn’t just the patterns community, it was software tools and it was frameworks and languages. A company I know used to say “I don’t know what the problem is, but the solution is DB2, CICS, and COBOL.” That’s solution probleming. It’s one of the reason that so many of us strive to not be product-based consultants. We want to solve problems, not just shoehorn prefab solutions into people’s applications.
I think any well-developed software developer’s immune system should be wary of the smell of solution probleming. It’s one of the best ways I know to overcomplicate and overengineer a solution - which is one of the worst ways to develop software.
Many 14
We’ve talked about Zero, and One, so all that’s left of the big Three Numbers is “many”.
Many is more than one. More than one object that must be used in the same way, more than one implementation of an algorithm, more than one implementation of an interface. An API wrapper implemented once for production, and once for testing is Many. One real object and one mock is Many.
Many gives power to the Liskov Substitution Principle. If there are many (more than one) objects to be used in the same way, then it is imperative that an interface is created for them so that they may be used interchangeably (transparently) by the client.
Many objects of the same interface (“type”) may be used one-at-a-time (by reference) or in groups (containers and loops). We don’t write code that calls A and B and C in the same way because that would be “three” and we don’t believe in 3. We believe in Many. It’s a loop over a list. If we’re treating the objects similarly, we should exalt the similarity by putting them in a loop, rather than stress individuality by coding two statements for making the call.
By the way, don’t confuse Many with “two things with similar structure”. Many refers to “more than one thing with similar usage” in the LSP-compliant sense. It doesn’t demand that you create base classes to capture some essential similarities, only that you create interfaces and loops as required.
In a multi-generational GC, the theory is that some things by nature have short lifespans, and others by nature have long lifespans. Most objects are created and deleted, and a few may make it to the third-generation cache where they’re almost never examined (comparatively) for collection. Many has a similar theory. Objects that occur once are singular things, but once they start to multiply they are expected to multiply more in the future. Not only does the “interfaces & loops” keep the code clean, it recognizes the Many things as an extension point in the code. That’s double-benefit if we listen to our code as it goes from one to many.