A few thoughts and questions related to the value of “loose-coupling” between code and data:
In Clojure, a customer
namespace that manipulates a map that represents customer
data is loosely coupled with customer data.
While in Java, Customer
class with a static methods that manipulate a Customer
record (or an immutable data class) is strongly coupled with Customer.
One benefit of Clojure approach is that the namespace doesn’t have to “import” the class definition for Customer
On the other hand, a Java developer might argue that the contract between code that manipulate Customer data and Customer data shape is not explicit
For instance, if you want to rename a field in Customer data, how would you discover all the pieced of code that need to be updated
Rich likes to say:
> We should program the insides of our sytems like we progam the outsides
A Java developer might object: > Does it worth it to have code and data loosely coupled when they both live in the same program?
Changing names == breaking things. (That’s how you end with misspelt http headers.) Coping with a new field is more interesting: new protocol version, or db schema update. What do you do of this new field your app doesn’t care about (say you are filtering/routing events: you need to lug the field around you don’t need to model it)
In classic java, does the code that implements filtering/routing events logic need to import class definitions for all types of events? I guess there are “design patterns” that make it possible to have different type of events with a common minimal set of fields to be processed by “generic” code.
It’s not about header vs payload
It’s about payload evolution
you dispatch purchase events based on amount
new version of the message comes in because of some new VAT regulation
you don’t care about the extra fields
but you need to pass them down
How do they manage it in classic Java? They add the new fields to the Event
class?
Either they go with a stratified approach (discrete typed getters + generic get — possibly generic gets, one for each type: getString
, getLong
etc.)
which allows to not break on payload extension (because backed by a map)
or they map each message piece as a class field and you get brittle code.
What are discrete typed getters?
Is it something like m.getAsString("price")
?
By discrete getters I mean getName getPrice and the like
GetAsString is a typed generic getter
Are the terms “discrete getter” and “typed generic getter” well known terms?
Nope