Anatomy of an Anti-Corruption Layer, Part 1
If change is ever going to come to shops that pedal Anemic Domain Models, you have to be realistic and realize that a widescale refactoring effort isn’t going to happen, especially with billions and billions of dollars running on top of it.
Thus, it is likely that such an initiative would apply to new development onwards, and you are inevitably faced with the task of interacting with the spaghetti that is already there. Enter the Anti-Corruption Layer.
The Anti-Corruption Layer is one of the coolest-sounding aspects of DDD, and is also one for which example implementations are scarce. This two-part series of posts will hopefully change that.
Here is the situation: using the SOA-as-an-excuse-for-procedural-Java excuse, some legacy code exists that we can’t change. It looks like this:
This is the becoming-canonical pen and surface example. There is currently no domain logic; the previous developers only finished persistence and UI code. The entities are bags of getters and setters.
Now you are going DDD, and more generally, OO. The requirement comes up to supplement this system with one piece of domain logic: pens draw on surfaces.
Furthermore, because of the budget and timelines and risk, as much of the legacy code as possible has to be re-used.
What is your approach?
OK, the title gives it away: use an Anti-Corruption Layer. The only new code we’ll really write is the new domain logic:
This is your standard DDD design. Note the choice of where to put the business method is a case of The Spreadsheet Conundrum and isn’t the point of this post.
Now for the glue. According to Evans:
The public interface of the ANTI-CORRUPTION LAYER usually appears as a set of SERVICES, although occasionally it can take the form of an ENTITY. …
Very well. My first attempt at this devolved into simply a collection of adapters for everything. I ended up trying to retro-fit it into an Anti-Corruption Layer. I could tell it was wrong because the domain logic was implemented inside the adapters.
My second attempt follows this reasoning:
- The entities in the legacy system already implement the data side of our Pen and Surface domain objects. So, we will re-use them. PenEntity and SurfaceEntity will be adapted into PenData and SurfaceData, respectively. Pen and Surface each will interact with PenData and SurfaceData as their state.
- Aside from PenData and SurfaceData, the Anti-Corruption Layer has two services: PenLegacyService and SurfaceLegacyService.
- Both Factories and Repositories forward requests to the appropriate Legacy Service. Requests from repositories are forwareded to the legacy DA class. Requests from factories are usually for instances of the adapters of PenData or SurfaceData.
- Each Legacy Service talks to an adapted DA class as a Legacy Repository.
- The Legacy Repository Adapters (sounds enterprisey, no?) talk to a translator that takes in legacy entities and spit out domain objects.
- This Anti-Corruption Layer has to be bi-directional because we’ll still be using the legacy UI system. Therefore, our Repositories have to be adapted as New System DA classes so the legacy system can use them to create transfer objects for the UI.
- The translators have to be two-way to support a bi-directional Anti-Corruption Layer.
Behold the Big Harry Design Up-Front:
The reason I don’t have code today is because I hesitate to advocate a design without code to back it up because the gap between design and implementation reveals difficulties that you didn’t think of before.
This has already reared its head. If the translators have to be two-way, then they need to be friends of Pen and Surface, and I don’t know how I feel about that right now.
I haven’t found very many examples of even design of an Anti-Corruption Layer except for a PDF. Jimmy Nilsson’s book also didn’t focus on this part of DDD. Even so, the examples are much more cooked-up.
I doubt I’d find this situation described anywhere. I have a hunch that most of the common uses of the Anti-Corruption Layer aren’t for using the entities and persistence mechanisms of another system, but rather some other less-fundamental-yet-still-foreign concern.
This sets the stage for the next post, which will hopefully contain a code download that implements the design. It will probably focus on the Anti-Corruption Layer itself and less on other design purities, like interface-oriented design and so forth.