It’s very hard to make objects declarative. Scalar Driven Development can help you to model your objects as declarative parts of application.

First things first. Imperative programming covers 99% of code. We’re still writing the same procedural code, that we did in C 50 years ago. We are done with it. It’s time to cure our brains.

Scalars are Declarative

Scalar Driven Development is a way to model our objects as declarative parts, some results, that will be computed later.

We define the interface first, where we denote our Scalar object.

Here is an example:

interface User extends Scalar<Json>{
  @Override
  Json value();
}

Our Scalar from User is a JSON document. By the way, Scalar<T> taken from cactoos library.

Then we are creating a few implementations for it:

final class Simple implements User {
  
  private final String username;
  
  @Override
  public Json value() {
    return new MutableJson().with("urn", this.username);
  }
}

No big deal, just giving username and building a JSON document from it. Someday, the logic will scale or change completely. But we want our object to stay the same, while adding new features. The Decorator will be in charge:

final class Validated implements User {
  
  private final Scalar<Json> user;
  
  @Override
  public Json value() {
    // validate json
    return this.user.value();
  }
}

Now we can validate our username before applying it to JSON document storage. Frankly speaking, it’s not a plain decorator, we are chaining a scalar by passing it.

final class Flushed implements User {

  private final Scalar<Json> user;
  private final Documents docs;

  @Override
  public Json value() {
    this.docs.apply(this.user.value());
  }
}

That’s a composition of objects, where each of them is a good citizen of a pipeline. Each of them is represented as a small result, as a part of a bigger one.

Delayed calls

Nothing will be computed until value() is called:

new Flushed(
  new Validated(
    new Simple(
      "Aliaksei"
    )
  ),
  docs  
).value(); // trigger pipeline

Scalars vs. Workers

XmlParser, BookMapper, UserValidator. Who are they?! I think they are great candidates for refactoring…

Scalars also will help you to avoid evil suffix of your objects: -ER, a.k.a Worker, we just need to define our results of manipulations with objects as other objects, that’s how Scalar is born.

Declarative programming means you define results of manipulations with objects as other objects”.

Let’s see an example: we need to map HttpRequest to Song object:

interface Mapper<F, T> {
  T to(F from);
}

final class SongMapper implements Mapper<HttpRequest, Song> {
  @Override
  public Song to(final HttpRequest rq) {
    return new Song(rq.path("name"));
  }
}

// call it
final SongMapper mapper = new SongMapper();
final Song song = mapper.to(request);

SongMapper encapsulates nothing, frankly speaking it’s not even a class, it’s nothing more than a set of procedures. More than that, SongMapper represent nothing from a real-world. We are just treating it like some smart object to manage our dumb DTOs.

Instead of doing such procedural things, we can go with SDD; it will make our objects more declarative:

final class SongFromHttp implements Scalar<Song> {
  
  private final HttpRequest request;
  
  @Override
  public Song value() {
    return new Song(this.request.path("name"));
  }
}

// call it
final Song song = new SongFromHttp(request).value();

The same functionality, but now:

  1. we are treating SongFromHttpas real-world entity.
  2. SongFromHttp has a state inside self: object encapsulates HttpRequest
  3. thanks to 2., we can perform lazy computation of SongFromHttp#value()

Watch this:

Summary

What are we learning here? Here is my summary of what SDD means:

  1. State (your object must encapsulate something)
  2. Declarative (scalars are treated as parts of other objects, as some results)
  3. Delayed calls (unless value() is called, nothing will happen)
  4. Absence of getters (there is value(), no sense to violate encapsulation)

There are a few real-world examples of how we maintain those ‘scalars’ in our projects: eo-kafka, cmig, cactoos and many more at EO-CQRS.

That’s it.

P.S
@l3r8yJ called this way of development - Scalar Driven Development (SDD).