In a data-rich environment, we can use the Builder concept to make DSL's for our Making application. This often makes testing the hard business core of our code both faster and easier.
Folks, I love sharing my geekery with you. For me, it brings much comfort. I hope, tho, you'll join me in working for change that isn't just about code, but about the larger world.

Black Lives Matter.
We've spoken in the past about using our codebase to do more than one thing. We always use it to create our shipping app. But we can and do use it for an app that improves our *making* process. We call that the making app.
When you're running your microtests, it doesn't necessarily look or feel like you're running an app, but you are. And that app uses much of the same source-code that what you ship does. It just uses it in a very different way.
Some applications manipulate a whole lot of intricately connected data. In the world of healthcare, for instance, an app might have literally dozens of classes, all rooted to and connected with a Patient. And the business logic is quite thick, with many cases and variants.
Suppose we wanted to test a key part of our logic, around getting permissions for medical procedures involving minors. To do that, we care about just a few things: the patient's birthdate, the medical system they're part of, the current date, and the procedure's minority rules.
The naive approach to testing the variants here looks like constructing all these objects, hooking them together, and calling some code. There are about a half-dozen cases, so we'll do this all a half-dozen times.
And there you see a cost begin to emerge: those objects are complicated, with many fields, most of which are entirely irrelevant. They must be connected, with ID's or keys that match each other.
There's a lot of *noise* there, and the signal is in small differences in large blocks of data. The making creeps its way into being unpleasant. And when that happens, when tests are painful, you know what we humans do: avoid them.
The low signal-to-noise is *especially* true if you're using automockers to simulate data sources or you're actually literally writing to a database. Please start by killing those two practices off. But if you've done that, you'll have made it better, but not enough better.
Ultimately, objects have to be made,with their fields, and connected. There aren't two ways around that. So if you see tests as arrange-act-assert, what you'll see is that your "arrange" is comparatively huge, tho your act and asserrt are 1-liners.
Now, the quick thinkers will have already jumped to a key potential solution. "We need some way to make a default patient, then we just change the fields we want changed." That's an excellent idea, and a strong starting point, but it's just a start.
See, a real Patient doesn't have fields you can just arbitrarily change. There are methods in the API that can do this, but they're themselves messy and complicated, and often require even *more* data to be poured into our "arrange".
Further, even if we solve that problem for Patient, we still have to solve it for the other objects, and we have to get them all linked together, too.
Enter the ScenarioBuilder (SB). This class is a specialist in turning descriptions of scenarios into concrete objects that represent that scenario. The key: it gathers all the descriptions up front, and only does the construction at the very end.
You create an SB, then you say things to it like: "today is 2021-03-21". "gimme a patient". "put her in Alaska Medical System", "make her 12 years old", "gimme a scrip for morphine". The SB doesn't do those things -- not yet -- it just collects the description.
Eventually, you say "go", and it makes all the objects needed to fulfill that description. It uses default values for anything you didn't override. It connects the patient to the medical system. It grabs a physician for a scrip, and so on.
Now, to flesh this out a little more, let's talk pros and cons. There's a lot to this, and it will definitely take you some effort, so we need a sense of what's good or bad about it before we dive in.
1) Pro: It's part of the Making app, not the Shipping app, so we have complete control over its API. We can replace forty lines of boilerplate to give somebody a procedure with a single API call: enema(). There's *zero* shipping use for this, but its invaluable in making.
2) Pro: We can provide API's that completely hide all ID/key manipulation. If you make a patient, and you make a doctor, and you make a scrip, the ScenarioBuilder will just assume you wanted them connected.
3) Pro: If your language is capable of it and you're good at it, SB calls will be easily legible to others, including others who aren't programmers. (Kotlin's extension methods and end-lambda syntax are wonderful for this.)
4) Pro: A change in the structure of a Patient might break the ScenarioBuilder, but it won't break the scenarios. Change how SB makes its stuff, and your scenarios are still valid.
5) Con: It's a fair amount of work. You can start small, but in truly data-rich environments it will grow pretty rapidly. You may wind up having to write tests against the SB itself, for instance.
6) Con: You must rigorously define your "nominal" values, the defaults the SB will use unless you tell it not to. You'll have to share those with your team, and you'll almost certainly want some pretty-printing capability, too.
7) Con: Because it's not part of the shipping app, you need it to be valued. That is, doing a half-assed job isn't really an option. It has to be much easier than the old way, quick to explain to noobs, and quick to flex under change.
8) Pro/Con both: It's a custom jig for a custom domain. That's a pro because you can fit it really tightly. It's a con because it won't move easily to other domains, even if they're conceptually nearby.
This has gone on a while, so let me just shoot a couple of quick pro-tips and let you go.
Think about the ordering of your descriptive statements, which is best left somewhat loose, but *can* benefit a great deal from "what's already said": if you said it's 2021-03-21, do you want that to only apply to the object you're describing, or from that point on?
You may have to create simple data classes to hold elements of a description. That's because you're not *implementing* the description until the very end.
You can sometimes benefit by extracting a long very-detailed description into a method and giving it a handy name for other tests, akin to using setup helpers. "guyWithBrokenLeg()" or some such.
That's it for now. But just for now. Let me foreshadow a little: You see, I wanted to write about this so we can talk about edging our way into a very hard problem: modern microservice apps distribute their business logic all over hell's half-acre.
There are ways to approach this, but they first require you to think in terms of two apps in one source base, then in terms of scenario builders, and then, well, we'll see.
If you like my content, put a ri--subscription on it. It's free, spam-free, you get full-text/audio, and it helps me.

geepawhill.org/subscribe

And please keep working for change in the world, any & every way you can.

Black Lives Matter.

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with GeePaw Hill

GeePaw Hill Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @GeePawHill

19 Mar
Honestly, y'all should read WCW more seriously before you gimme the parody.

Not hating. Just saying.

This dude rang the bell a dozen times in his career.

Imagine that.
My favorite WCW, my top-five poem of forever, is this one.

poetryfoundation.org/poems/46483/da…
So. Love you, do love you, for real. But your fridge plum thing is old and tired and disrespectful of a poet who shakes the world.
Read 5 tweets
19 Mar
Here my Stevie, rescuing me as he does surprisingly often. "Heaven Is 10 Zillion Light Years Away".

My heroes show up, randomly, just in time.
This was the song that helped me grasp the difference between anger and hate.
Read 5 tweets
19 Mar
Aight, double-play. Here's Melanie twice.

First, "Brand New Key".

At some point a person reaches an age. And at that age, it's not in years, it's in living. And at that some point, one understands what a lovely song this is.
Then, caught up by her charm and her voice, one encounters "Lay Down".

Read 5 tweets
7 Mar
Approaches in software development -- or anything else -- that don't take ordinray human failings as their starting point are prone to dramatic failure. "The Impossible Human" is, well, noticeably uncommon. Let's dig in on that.
More geek joy comfort food from me today, but please think & work outside the monitor by enabling and encouraging change in our wider world.

Black Lives Matter.
Some years back, I made content for a CMS that had a whole lot of overlapping parts, each with its own special language. I found it very difficult to express myself quickly & cleanly, and, it being me, I complained about it a lot.
Read 29 tweets
28 Feb
"It puts the database on its browser skin, or else it gets the hose again." This task occupies the daily life of a great many programmers. Today, I want to throw out some random sparks of advice for people working in that setting.
Folks, my ideas about changing code are deeply intertwined with my ideas about changing the world, which is a far more important activity than any kind of geekery. Let's geek out, for sure.

But please keep working for change, and supporting those who do.

Black Lives Matter.
In enterprise IT, it is commonplace for backend folks to work on problems shaped like this: there's a web endpoint controller on the top, a database on the bottom, and some simple or complicated business logic in the middle.
Read 32 tweets
27 Feb
ONI: c51, and a couple of building tips. That space next to the musher is going to be infinite food storage. I need it vacuumed out and filled with chlorine.
The stairs down & up on the west are actually a working liquid lock. We usually make permanent ones, but I won't need access to this room, so I really only need the lock for a short time. Two dribbles of water is all it takes. It won't last long, but I don't need it to.
The fastest & easiest way to a vacuum is to fill all the gas tiles with a solid, then use diagonal deconstruct. Whatever was in them is gone when the tile is built, and you get vacuum when it's destroyed. Wouldn't work in this case, but it's the best way.
Read 15 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!

Follow Us on Twitter!