lol I don’t know if the grammar of the title makes any sense, but I’ve gotta have something for a title.
I read about the class design of Ward Cunningham’s FIT testing framework, at http://fit.c2.com/. That’s a fabulous framework, and my favorite integration or acceptance testing framework that I’ve seen yet.
But the implmentation sets aside some of of the core religious beliefs that I was raisied with in the Java community. The classes in the FIT framework rely heavily on a lot of code design features I’ve been allergic to over the years. Like, doing heavy lifting in the constructor. Exposing all methods as public. And the tests in framework itself are simple, because a test class exposes public fields as the input of the test — not setters! — and the methods are the testable outputs.
I’m starting a new project at home, for no better reason than to try to keep my brain alive, and I’ve been working on it seriously for about an hour every month or so. The rest of my free time is consumed by my little girls. But as I’m putting this project together, I’m thinking about it differently than usual.
First, I’m going to do very little encapsulation. No getters and setters. And all methods are public except maybe the really obscure helper methods that I spin off to make the code readable. Here’s what I’m thinking.
After playing around with Python for the last couple years, I’ve come to like the sparse directness of that language. I still love the structure and compile-time guarantees that Java provides, but I’m beginning to think some of it smacks of religion. For example, one of the most prominent practices in Java is to create Data Transfer Objects — i.e. classes that have no functionality, only private fields and then getters and setters for those fields. In many cases, these “dumb” data objects are generated code, so you *can’t* modify them if you wanted to — the next code generation cycle would just wipe out your changes.
Really a DTO is just a glorified C struct with getters and setters thrown in. I hate building systems that way, but there are lots of practical reasons why they are so prevalent in the industry.
But if you have a dumb data object, why do you need getters and setters? I can use reflection just as easily on attributes as on getter and setter methods. And the underlying representation of the data isn’t going to change — the getter and setter are always just going to have the same type as the underlying field. So why add all those silly lines of code to provide accessors and mutators?
People have had unease with getters and setters for a long time. Some of the more recent languages are wrestling with that, and define attributes as the default way to get at a class’s data, with optional hooks for adding actual functionality around them. So I think I’m just discovering an old pain, not anything new.
Secondly, in the context of making things private, could that be another straw man that’s been around for a long time? In most code bases, the bulk of the code just relates to the system itself. Most classes are not part of the outward-facing API. So why not make everything, or nearly everything public? In the context of the system I’m building, I can always right-click in eclipse and “search for references” and find out exactly what classes are referring to my methods. Inside a code system, restricting access to methods is more about making the code easy to understand and work with than about providing a consistent API to some unknown external system.
What if I defined encapsulation at the library or module level, rather than at the class level? So there is the code for the “engine”, which is all public methods and public fields to keep it simple and light. But then there’s another jar which represents the public interface into the engine, and *that’s* where the encapsulation happens. All the access into the engine is through well-defined interfaces which are implemented by the classes in the engine. If I want to limit access to items inside the engine, I do it with the definition of the interface package.
I may end up creating some accessors after all, because the public interface may require them. And I may get stuck putting my DTOs in the public interface after all because they are the input and return types for my public, outward-facing methods. But I think its better to design the engine classes with the visibility determined by the requirements of the API than by just religiously making everything as obscure as I possibly can for no good reason.
Anyway, I’ll play with this system and see how it works out. Maybe I’ll discover that religious practice has a stronger basis than just faith.
EDIT: lol I think I just re-invented groovy 😉