Please re-subscribe to the feed

Hi, folks. I’m really sorry. Please re-subscribe to this feed. I couldn’t figure out how to make this work for you. If you don’t re-subscribe, then this is the last new article you will receive.

9 years ago
Comments
A model for improving the names of variables, fields, interfaces, classes and namespaces in a system. Practise this and more in my course, Agile Design: Beyond the Basics.

A model for improving the names of variables, fields, interfaces, classes and namespaces in a system. Practise this and more in my course, Agile Design: Beyond the Basics.

9 years ago
Comments
Announcing a European Tour in 2011

imageI’m touring Europe in 2011. I have planned some public courses and some conferences, and am searching for private consulting and training work. Over the coming weeks I will reveal where I’m appearing on the map. The colors on the map provide a hint! If you’d like to invite me to your event, then please visit here. See you later this year!

9 years ago
Comments
The Continuum of Names: an example

I found someone trying to work on improving names in their code, and gave them a little advice. It gives a reasonable example of some of the things I think about when naming.

9 years ago
Comments
The Continuum of Names: a quick summary

Emma López (@hell03610) shared with the world her notes from my XP2011 session, “A Simple Approach to Modular Design”. In it, she summarises a model I teach about how to improve names in code. I do plan to write about this in more detail this summer.

9 years ago
Comments

Code rejects inheritance-based reuse! An example.

We’ve read this before: don’t reuse code by subclassing. Instead, compose objects into a loose network that share responsibility for the system’s behavior. While practising, working through Growing Object-Oriented Systems, I reached the point where Steve and Nat started writing microtests, and decided to stray from the text and try it out on my own. I reached the stage where the first two system tests pass, but in the process, I introduced much cyclic dependency and duplication, particularly related to sending and parsing chat messages. In preparing to address this problem, I noticed some duplication in how the auction handles its incoming chats: sometimes it updated the UI, and sometimes it didn’t. I figured I’d turn those into two chat message handlers, separating the UI behavior from the non-UI behavior, and in so doing, introduced some temporary duplication.

You can probably see a straightforward way to start removing this duplication. To illustrate it, look at the following code snippet.

So we have two classes with a common field, a common method signature, and similar method bodies. Extract Superclass seems logical, even though I can’t think of a decent name for this class so far. No worry: it will come to me.

Next, we have to extract the parts that differ from the parts the match each other. I did that by introducing new methods.

Next, we make processMessage() identical in both classes, so as to pull it up into FooMessageListener. And here, we find our first warning sign about this refactoring. The signatures of handleBiddingStateEvent() don’t match:

  • BidsForSniperMessageListener.handleBiddingStateEvent(Chat, BiddingState)
  • UpdatesMainWindowMessageListener.handleBiddingStateEvent(BiddingState)

In order to find out whether this will become a problem, I have to add Chat to the parameter list for UpdatesMainWindowMessageListener’s implementation of the method, at least for now. I imagine I could do something more clever, but I’m not sure that introducing a closure over a Chat object would simplify matters. I can put that on my “to try” list for now. In the meantime, I add the Chat parameter. See the diff.

Now to turn similar processMessage() implementations into identical ones, I introduced an empty method. This is another warning sign, since I can’t envision a “default” UI update. Still, I reserve judgment until I have more evidence, and introduce the necessary changes. See the diff.

Now that processMessage() looks identical in both subclasses, we can pull it up into FooMessageListener, for which we still don’t have a good name. Either see the diff or look at the final result below.

Now that I look at this last version of Main, I see the value in having attempted this refactoring. It clarifies quite well the specific reasons why I won’t let inheritance play a long-term role in this part of the design. Specifically, look at the little problems with this design.

  • I still can’t think of a good name for FooMessageListener, although maybe you’re screaming one at me as you read. (Sorry; I can’t hear you.)
  • BidsForSniperMessageListener.handleAllOtherEvents() doesn’t need to do anything, which might or might not be a problem, but often points to the Refused Bequest smell.
  • UpdatesMainWindowMessageListener.handleBiddingStateEvent() doesn’t need its chat parameter.
  • Both subclasses need a reference back to Main, but the superclass FooMessageListener doesn’t need it. Of course, that says more about Main in general than the FooMessageListener hierarchy: Main violates the Single Responsibility Principle in a variety of delightful ways. That’s why we’re here.

So let me talk this through: we have subclasses of FooMessageListener that respond to the same logical stimuli, but different subclasses need different data and sometimes a subclasses doesn’t need to respond to the stimuli at all. That sounds an awful lot like an event mechanism to me.

And if you look ahead in Steve and Nat’s book, that’s not surprising.

So how do we get from here to there? I plan to attack it this way:

  1. Make FooMessageListener an event source for this new type of event, which I’ll tentatively call an AuctionEvent.
  2. Turn the subclasses into AuctionEventListeners.
  3. Inline stuff back into place.

You can follow the detailed changes on this branch starting with this commit.

By the end of this session, I ended up with a new Auction Event concept, which has started separating the “chat message” concept from the “auction changed” event. It does, however, lead to other questions, which I’ve highlighted with SMELL and REFACTOR comments, so look for them. For now, I feel good that, while introducing a hierarchy had its problems, it helped me see how specifically to eliminate it. I trusted the mechanics, and it helped me see where to go next. I know I need to introduce an “auction closed” event and perhaps need to introduce an AuctionEvent object to eliminate the need for type checking in AuctionEventSourceMessageListener. We’ll go there next time, but in the meantime, peruse the current state of the code.

If you prefer, look at the changes in moving from MessageListeners to AuctionEventListeners.

I hope I’ve shown how a code base can reject an attempt to reuse code by inheritance, prefering instead, in this case, composition implemented as an event chain.

9 years ago
Comments

Integrated Tests Are A Scam: no conflict with GOOS

I’ve taken this verbatim from a thread in the Google group for Steve Freeman and Nat Pryce’s excellent work, Growing Object-Oriented Systems Guided by Tests. As I’ve said before, they’ve written the book I wish I’d written. I quote Rick Pingry below.

My partner and I were just looking at a video you made a while back about integration tests being snake oil. The GOOS book of course talks about Acceptance Tests, but perhaps you are making a differentiation between acceptance tests and integration tests. I bring it up in this thread because I think it is relevant.

Short version: Don’t use end-to-end tests to avoid flaws in the basic correctness of your system.

The crux of the problem: The Average Person™ conflates “Acceptance test” (help the Customer feel good that the feature is present) with “System test” (help the Programmer feel good that the system components work together correctly) because they tend both to be end-to-end tests. As a result, the Average Person doesn’t write enough microtests.

GOOS uses Acceptance Tests to guide programming and help Programmers know when they’ve built enough stuff. Because they choose to implement those tests in Java, the Average Reader™ might interpret those tests as System Tests, and believe that they serve the purpose of making sure the whole system works. Even when GOOS does use them as System Tests, the book also shows many, many microtests, thereby avoiding the logic error that the Average Person™ makes.

In there you take the approach that you should mock ALL collaborators. In a bit of code we wrote recently, we did that very thing, but find that making changes to how the thing works is hard. Refactoring becomes harder. (I wrote about this before and got lots of great advice from you guys, but I think I understand better about what is going on now so I can speak more intelligently about it). The tests become glue that makes any kind of change to HOW a class is implemented difficult if you ever want to extract an internal. The GOOS book and this thread talk about a difference between peers and internals, and I get the impression that you should mock the peers and not mock the internals. I am not so sure now after hearing your talk about that. Am I missing something?

No. I agree about using test doubles for peers, not internals. I simply use the painful pressure from trying to use test doubles for all collaborators to help me classify them as peers or internals. Sometimes I guess well about that classification as a shortcut, but when I don’t guess well, I can always take the long route.

If you are mocking out every collaboration between every class in your system, how do you refactor anything without breaking tests? Are you supposed to be able to refactor without breaking tests? Could you provide an example of how you do that?

I tend more often to throw away tests than break them. If changing a client leads to changing a peer interface, then I switch to revising the contract tests for that interface. Sometimes this means throwing tests away, because sometimes this means throwing an interface away.

I’m afraid I have no example to show you, because contrived examples don’t demonstrate the point adequately, and I don’t own the IP rights to the real-life examples I’ve used.

(Source: bit.ly)

9 years ago
Comments

Long Names: a smell? or a clue?

Sometimes I want name a method or class with a long name. I wrote about this once before. I stumbled upon someone claiming that he only used long names because he didn’t take the time to think of a shorter name. I offer a different reason.

I use long names when I don’t have enough evidence yet of a pattern that will let me shorten the name.

If I create a new thing, and it’s the only of that type of thing in my system so far, then I’ll name it something long and descriptive. As I add similar things to it, those new things will overlap their names with the first thing. I’ll use that as a sign to remove structural duplication. As I do, I’ll remove that word or phrase from the longer names, making them shorter. Assuming that I keep this up, the long names will shorten as I generalise the system in the direction of design changes the need for which I have real evidence. I could speculate, but that usually lands me in the soup.

10 years ago
Comments
Why not? JUnit 3 and 4 on One Page

…if you print it in duplex mode, that is.

10 years ago
Comments
By popular demand: JUnit 4 on One Page

You asked for it; you get it.

10 years ago
Comments




Blue Theme by David