Blog

Nov 07 2013

Comments

When Should You Use Clojure's Object-Oriented Features?

In the world of object-oriented programming, it is common to create classes to represent data elements from your domain. These classes run into all kinds of trouble. First, they tend to breed closely coupled classes like DTOs and XML type mappers. Second, they rarely contain any intelligence and sometimes don't contain any behavior at all. Third, proliferating concrete classes can make it hard to see common abstractions trying to escape.

In the past, I answered all of those objections by arguing that they were "merely" bad design. It is possible to do good OO design that doesn't suffer from those failings. I've reluctantly come to believe that the majority of OO code will never escape those failings. Common style, frameworks, and tools all push toward a design dominated by "god classes" and data containers.

Instead of fighting that, I've decided to embrace it. If your objects are just going to be data containers, then embrace the data! Don't hide it away inside objects, and don't fragment your namespace of functions over the data by splitting them across dozens of classes.

Now when I build applications in Clojure I tend not to use Clojure's OO constructs, protocols and types, for the domain data passing through the system. I've followed Rich and Stu down the path of values and data structures.

I do find Clojure's OO constructs valuable for the structure of the system itself. I like to use protocols to limn the boundaries between subsystems. They provide exactly the degree of information hiding I want. We've been evolving a common idiom for creating instances of protocols, where we have an implementation as a type together with a constructor function. The constructor function is considered public, while the type is meant to be private.

(defprotocol IMarshaller
  (marshall   [_ data] "Marshall data, return a ByteBuffer ready to transmit.")
  (unmarshall [_ bbuf] "Unmarshall data from the ByteBuffer"))

(deftype EdnMarshaller []
  IMarshaller
  (marshall   [_ data] (io/clj->bbuf data))
  (unmarshall [_ bbuf] (io/bbuf->clj bbuf)))

(defn edn-marshaller [] (EdnMarshaller.))

Most of what we pass across subsystem boundaries are primitives and data structures of primitives. This particular example uses Java ByteBuffer objects, but we treat them like immutable value objects so I'll call them "primitives" for the sake of argument.

That troika of protocol, type, and constructor appears fairly often, but there are some variants.

In this example, the functions on the type are small enough that you could simply reify the protocol inside the constructor function:

(defn edn-marshaller [] 
  (reify IMarshaller
    (marshall   [_ data] (io/clj->bbuf data))
    (unmarshall [_ bbuf] (io/bbuf->clj bbuf))))

This works best when the constructor only takes one set of arguments. I would split this out when there are optional or variadic arguments to the constructor function.

Using objects to represent subsystems gives us information hiding and polymorphism. That's exactly what we need. Using data structures for the application data gives us leverage over those data structures. One more thing to consider is when and how to avoid coupling data structure shapes across subsystems, but that's a topic for a future post.

Nov 01 2013

Comments

Oct 29 2013

Comments

Lynn Grogan - Cognicast Episode 044

cover art

We talk to Lynn Grogan, Cognitect's Events Manager, about her 211-mile hike along the John Muir Trail in California.

Listen to or download this episode.

Read More »

Oct 15 2013

Comments

Kevin Lynagh - Cognicast Episode 043

cover art

In this episode, we talk to Kevin Lynagh about the many interesting things he has been up to lately. These include being invited to Hacker School and producing Weathertron, a native iOS weather app written using ClojureScript.

Listen to or download this episode.

Read More »

Oct 08 2013

Comments

Ambrose Bonnaire-Sergeant - Cognicast Episode 042

cover art

Ambrose Bonnaire-Sergeant has made quite a splash recently with his campaign to fund development of core.typed, a library that provides a gradual type system for Clojure. In this episode, we talk extensively with Ambrose about core.typed just minutes before he launched the campaign.

Listen to or download this episode.

Read More »

Oct 07 2013

Comments

Begin With the End in Mind

When people define processes, they usually start from the beginning. They ask "What do I have? What should I do with it?" If you're lucky, they also ask "Who needs it?" but that usually comes last.

The trouble is that when you string a bunch of processes like this together in a company, you find "gaps" between them. That's where one person delivers a spreadsheet that someone else has to manipulate more before they can use it. Or where one group delivers GUI mockups without dynamics to another group who is supposed to implement it. It leads to waste.

I often find processes with no consumers. Pure waste! Literally nobody uses the output, but the producer doesn't realize it.

When defining a process, I think you should start at the end. Define it from the perspective of the consumer.

I like to ask the questions in this order:

  1. Who is the consumer?
  2. What do they need?
  3. How do you deliver it to them?
  4. How do you know when they're ready for it?
  5. How do you produce it?
  6. What inputs do you need to produce it?

By doing it this way, you naturally create a process that includes signaling, delivers good (i.e., usable) outputs, and doesn't have any gaps.

Oct 01 2013

Comments

Where to Find Cognitects: October Edition

Want to meet a Cognitect in person? Here's where you can find us during the month of October:

Europe 10/4-10/18
Stu Halloway & Michael Nygard are taking over Europe! Find out more about their tour.

Washington, D.C. 10/4
NationJS
Organizer: Russ Olsen

New York, NY 10/7-10/9
Future of Web Design
Speaking: Michael Parenteau
Talk: The Myth of the Half-brained Designer: An Artist’s Journey Through Engineering

Durham, NC 10/15
West End Ruby Hack Night @ Relevance HQ
Attending: Yoko Harada

Minneapolis, MN 10/25
Intro to Datomic
Trainer: Michael Nygard

Oct 01 2013

Comments

Robert Stuttaford - Cognicast Episode 041

cover art

On this - our first post-merger episode! - we talk to Robert Stuttaford of Cognician about their use of Clojure, ClojureScript, Pedestal, and Datomic.

Listen to or download this episode.

Read More »

Sep 27 2013

Comments

October Barnstorming with Stu Halloway and Mike Nygard

Stu Halloway and Mike Nygard are taking over Europe. Here's where you can find them during their October adventures:

Helsinki, Finland 10/4
Reaktor Day
Speaking: Stu Halloway
Talk: Narcissistic Design, Core.async

Darmstadt, Germany 10/9
Darmstadt Java User Group
Speaking: Stu Halloway
Talk: Datomic, Clojure & ClojureScript

Budapest, Hungary 10/11-10/13
Rupy
Speaking: Stu Halloway
Talk: Keynote

Krakow, Poland 10/13
33rd Degree Conference
Speaking: Stu Halloway
Talk: Narcissistic Design

Amsterdam, Netherlands 10/14
GOTO Night
Speaking: Mike Nygard
Talk: Five years of devOps: Where are we now?

Berlin, Germany 10/14-10/16
EuroClojure
Speaking: Stuart Halloway
Talk: Narcissistic Design

Berlin, Germany 10/17-10/18
GOTO Berlin
Speaking: Mike Nygard
Talk: Maneuverable Web Architecture

Sep 16 2013

Comments

Relevance and Metadata Partners Join Forces to Become Cognitect

It is with great pleasure that I announce that Relevance, Inc. has joined forces with Metadata Partners (makers of Datomic) to become Cognitect, Inc. Cognitect maintains all of what made Relevance great -- the same team, the same focus on agile development, the same dedication to open source and sharp tools, but is also a vehicle for exploring those sharp tools and leveraging them to build truly modern information systems and solutions.

For all of our friends, customers, and partners who keep up with us here at the blog, know that this change will be purely additive from your point of view. Nothing changes about how we work with you; we now have better alignment around our products and services and will be even better partners.

It is a happy coincidence that this change comes on the heels of our 10-year anniversary. A decade seems like an excellent unit of measure -- we've had a fantastic decade with Relevance as a stand-alone entity. We're looking forward to doing even more as part of Cognitect.

Popular Tags