Posts

How Big Is Your Object's Interface? The Answer Might Surprise You!

We have a Person object, eddie . Part of the responsibilities of a Person object is to operate a Car , accessible as eddie.getCar() . Car s are made of parts like Door s and Seat s and an Engine . Starting a Car entails starting its Engine . So how would we start eddie 's Engine ? eddie.getCar().getEngine().start(); This accomplishes the task, but we see a violation of the Law of Demeter in this code. We can see this quite plainly: look at all the dots! But what is this "law," and who passed it? I don't think Congress concerns itself with these matters (at least not yet). How bad can writing code like this really be? To understand why we should follow Demeter, we have to see what happens when we don't. Our Person , eddie seems to have a very simple interface so far, a getCar() method. He just has that one method, but that method gives us back a Car with a getEngine() method. That method then gives us an Engine with a start() method. Each intermedi...

This One Subtle Bug You Might Not See Coming

Sometimes bugs are obvious. You used a ++ where you should have used a -- . Other times, bugs are much less obvious. A regular expression was missing an escape of a . . Then there are those bugs that are so subtle and insidious that they deserve their own blog post just to document and excoriate them. This post is about one of those bugs. Fortunately for me, this wasn't my bug. It was a bug hidden in a Programmers.SE question . The questioner was blaming himself for not seeing or understanding a change in an external library, and he was desperately looking for a way to write better code to account for such changes in the external library. What did that library do? There was a method that returned a long, where the long was milliseconds since epoch. In the update, the method was changed so that it still returned a long, but the long now represented nanoseconds since epoch. Putting aside the discussion about whether a long has enough precision, this change is a special type of a...

Moving Sideways with Lateral Abstractions?

When I'm doing design and refactoring, part of me worries that I'm just creating a mess of objects and classes. One of the kinds of mess that I feel I make the most are lateral abstractions. What I mean by lateral abstraction is an abstraction that is at the same level as the code I abstracted it out of. It doesn't add very much to the conversation, and it doesn't introduce a finer vocabulary than was already there. When looking over the code I wrote in Writing a Better Code Narrative , I get a slight feeling in the back of my head that some of that code is lateral abstraction. Without re-posting all of the code (which can be found here ), I started with a CommandParser class that read a string of character commands and "executed" those commands to produce a new output string. The original code was intentionally hairy, but I refactored it down into a series of Command classes to encapsulate the individual behaviors, and a CommandFactory to encapsulate the...

Two Great Takeaways from GOOS

I recently just finished reading Growing Object-Oriented Software, Guided by Tests (or GOOS for short) by Nat Pryce and Steve Freeman. I highly recommend every developer pick up a copy and give it a read. It is full of great advice for building a well-tested, high quality application. I wanted to pick out two particular gems I found towards the end of the book that I felt are really powerful. [W]e like to have names for the relationships between objects as well as objects themselves. As the legends say, if we have something's true name, we can control it. – Growing Object-Oriented Software Guided by Tests , page 244 (authors' emphasis) They are talking specifically about preferring to mock interfaces rather than concrete implementations, but this concept bubbles up generally throughout the book. They use interfaces extensively, even noting that their use is above average, to tease out concepts and relationships in the code. Many in the community feel that interfaces are j...

YAGNI vs Refactoring

I am currently reading through Growing Object-Oriented Software Guided by Tests by Nat Pryce and Steve Freeman. It is a great read and I highly recommend it. They describe a methodology for building high-quality software from the ground up, using all levels of testing to ensure that quality and functionality. Early in the book, they cover many concepts that are commonly heard in the developer community, including YAGNI and refactoring . Later in the book, they use a "real-world", messy example to demonstrate their methodology. At the end of chapter 16, about halfway through their real-world example, something struck me in their observations for the chapter. They are leaving the example in an ugly state in need of refactoring. In their observations, they state: So now that everything works we can get on with more features, right? Wrong. We don't believe that "working" is the same thing as "finished." … [W]e can either clean it up now, while it...

This 1 Weird Trick to Almost Any Design Pattern!

I was answering a question on Programmers.SE the other day, as I am wont to do from time to time, and something interesting struck me. As I was constructing my answer, I found myself looking for a design pattern to name that would be apropos for the situation (I settled on the command pattern ), and while I was grasping for the right one, I thought, I want the one where we put an object in between. It hit me: that's almost all of them! That's right, nearly every design pattern is basically just "create an intermediate object to encapsulate what you want." For example, we have the command pattern: create an object that calls behavior in the way that we want. We have the adapter pattern : create an object that transforms what we have to what we want. We have the strategy pattern : create an object that will polymorphically perform a behavior we want. As I realized that, I felt like, while design patterns offer a great way to name and model a certain solution when...

Interfaces and the Need to Know Implementations

In many languages, interfaces and abstract classes serve as constructs for abstractions. Other languages rely on duck typing for the same purpose. Either way, we hide the underlying complexity of implementations under simpler façades. Though we may use these abstractions, all too often we don't trust these abstractions. Developers frequently talk about how they can't use an abstract type. They need to know exactly what concrete type of object they are dealing with. But in many cases, we don't or even can't know. It's possible that it is some second- or third-party type that we've never seen. How could we possibly trust some unknown code that is just shoved willy-nilly into ours? But do we really need to know the concrete runtime type? Knowing can simplify debugging. When I need to chase a bug, I need to know where to look. If it is in some indeterminate subtype, how will I be able to track it down? This is a legitimate concern. But tools help there. Mod...