Revealing Interfaces
Making Usage Patterns Explicit in Code
In nearly every OO application there’s at least one large class. By large, I mean a class that has 15 or more methods. We expect classes to have focus and it’s hard to make the case that a class with that many methods is about one thing. There will be some sort of grouping. Sometimes it’s explicit in the names of the methods, sometimes it’s not. Classes like this can be hard to understand. When we do try to understand them, we often inadvertently make it harder for ourselves - we concentrate on the class itself rather than its surroundings.
In statically typed languages there’s a trick we can use that makes the relationships between groups of methods and other classes far more explicit. Once they are, we may see some way to break down a large class. Even if we don’t, the code becomes more understandable.
Let’s look at an example.
I’m showing the skeleton of this class rather than all of its code because, well, who wants to scroll through a blog post that far. Hopefully, you agree that this is moving toward being a large class.
public class StationManagement {
public void initStation(Employee employee) {
...
}
public void closeStation() {
...
}
public void setStocker(Stocker stocker) {
...
}
...
public void closeDay(DayRecord record) {
...
}
public DailyReport getReport(DayRecord record) {
...
}
public void changeShift(Employee employee) {
...
}
}
One of the things that we can’t see by looking at the code is who the users are of the individual methods. But, since we’re working in a statically typed language, we can easily figure it out. Here’s the trick.
public interface X {
}
public class StationManagement implements X {
...
}
What I’ve done here is declare an empty interface and set up the code so that StationManagement implements it. I’m calling the interface X because I’m not sure what it should be called yet.
Now that we have that empty interface we can go to a place in the code where a StationManagement object is passed as a reference..
public void operateStation(StationManagement station) {
...
}
and change the type to X.
public void operateStation(X station) {
...
}
Once we do that, something magical happens. In most IDEs, every place a method is called on that reference gets a red squiggly line indicating that the method can’t be found. If you we aren’t working in an IDE, we’ll get an error when we compile. It’s not as immediate, but it's still the feedback we need.
public void operateStation(X station) {
...
station.initStation(operator);
...
}
Error: initStation(Employee) not found on interface X
These errors are easy to fix. We just look at the name missing method that is called out by the compiler, find it on our class and copy its signature to our interface.
Once we’ve eliminated the errors, we have an interface that describes the role that our original class plays in this context. We can change the name of this new interface from ‘X’ to the role name and end up with code that better documents the way that the original class is used. What we do next is up to us. Sometimes we see a role and realize that it should be its own class. When we break it out our 15+ method huge class becomes smaller. Other times, its fine just to stop and leave things as they are. After all, we’re in a much better position. Anyone looking at the class can see how it is used and what methods are used in particular contexts.
It’s a shame we can’t use this trick in dynamically typed languages. I’ve done something close: passing an object of type Object and using it to discover the methods being used at runtime but it is not as direct and it depends on having enough coverage to make sure you are really hitting their calls.
Chalk one up for statically typed OO languages.
Try revealing interfaces someplace in your code. It's a high impact, low cost technique for learning more about what your classes are and what they could be.