Revealing Hidden Objects: Can DDD Improve Your Code?

May 9, 2017 — Leave a comment

Code that’s easier to understand, maintain, and extend — that’s the promise of Object-Oriented Programming. But the reality for many iOS developers is that our objects are bloated. They know too much, and do too much. What if our code has hidden objects, waiting to be found?

Each hidden object could provide a new abstraction, a new tool. They could make the code more manageable. Is there a way to discover these hidden objects? Domain Driven Design (DDD) provides a way.

(Disclosure: Please note that the book links below are affiliate links. If you buy anything, I earn a commission, at no extra cost to you.)

Eric Evans’ Domain Driven Design is a book with many facets. One of my big takeaways is that our code often contains concepts that are hidden. The book’s challenge to me is to recognize implicit concepts, and make them explicit.

I stumbled upon this in the TDD sample app. While applying a principle from the book to the Fetch Characters Marvel Service, I uncovered a useful class.

Canceling a data task

In an earlier article, we TDD’d the requirement that the URLSessionDataTask receive a resume message. Right now, the code (including a spike test) looks like this:

func fetchCharacters(requestModel: FetchCharactersRequestModel) {
    guard let url = makeURL(requestModel: requestModel) else {
        return
    }
    let dataTask = session.dataTask(with: url) { data, response, error in
        print("error: \(String(describing: error))")
        print("response: \(String(describing: response))")
        let str = String(data: data ?? Data(), encoding: .utf8)
        print("data: \(String(describing: str))")
    }
    dataTask.resume()
}

But one of the user stories of the Marvel Browser is “User implicitly cancels current request by navigating away.” So we need to hold on to this data task so we can send it a cancel message.

Easy. Put it in a property, right? Then the Service will have two methods, fetchCharacters and cancel.

I’ve done this before in production code, and started down this same path. But as I took another look, something started to bother me.

Services according to DDD

In the Domain Driven Design book, Eric Evans writes the following about Services.

A good Service has three characteristics.

  1. The operation relates to a domain concept that is not a natural part of an Entity or Value Object.
  2. The interface is defined in terms of other elements of the domain model.
  3. The operation is stateless.

Let’s see. Number one, check. Also number two, since fetchCharacters takes a request model Value Object.

Number three. Stateless. This would no longer be true if I tracked the data task in a property. But I need this state-ful information. If the Service doesn’t keep track of the state, what does?

Then it hit me. I need a new object.

  • I need state.
  • But the state shouldn’t be intrinsic to the Service.
  • So the state should be extrinsic, passed in to the Service.

Let’s draw a Sequence Diagram

At this point, I started to get confused about what the domain model objects were, and how they interacted. I decided to make a diagram.

I was taught to use CRC cards to help flesh out Object-Oriented Designs. But I’m currently reading Practical Object-Oriented Design in Ruby by Sandi Metz. The book uses Sequence Diagrams, which I see as a spiritual descendant of CRC cards.

With CRC cards, you simulate message-sending by conversation. With Sequence Diagrams, you draw them. So here we go:

Sequence Diagram for Fetch Characters Marvel Service

Click to see larger version

My simple little Service has a surprising number of collaborators! At first glance, it may look overcomplicated. But the diagram helped me understand the Fetch Characters request. Every object plays an important role, and is there for a reason.

NetworkRequest is the newly uncovered Entity. On any system that uses Foundation, it’s a wrapper for a URLSessionTask. But the idea is portable. We could use this term across client platforms of all types. This would help us create a Ubiquitous Language that we share across teams. And that would bring a host of benefits.

Benefits of stateless Services

Why is it important to keep a Service stateless? Consider what would have happened if I’d kept the data task as a property.

I could have one Fetch Character request, at most.

Now I don’t know if I’ll ever need more than one active request. But there’s no such restriction on the actual service. Modeling it that way would have added a limitation that doesn’t reflect reality.

People seem to have given up on the idea that OOP creates reusable objects. But one thing preventing object reuse is creating objects that know too much. A stateless Service can be used in a greater variety of situations.

Domain Driven Design leads us to better code

Just by following a single part of Domain Driven Design, I uncovered a hidden Entity. Making it extrinsic improved my Service. Now I have two objects that are more focused, which makes them both more reusable.

What other improvements lie ahead, waiting to be refactored? I’m betting the patterns and mindset of DDD will lead me to better models.

What about you? Have you made any DDD-inspired changes in your iOS code? Even if you can’t share the details, let us know in the comments below.

Jon Reid

Posts Twitter Facebook Google+

I've been practicing Test Driven Development (TDD) since 2001. Learn more on my About page.

No Comments

Be the first to start the conversation.

Leave a Reply

Text formatting is available via select HTML.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> 

*