, 24 tweets, 4 min read
TSD #3: Starting The Builder Architecture

At this point, we have a cute simple interface that writes arbitrary tree-shaped data. But there's no tree, there's just a list of leaf nodes. We need to process that list to enable the implicit tree they represent to be operated on.
Such an operation will want to deal with individual nodes in that implicit tree. The operation doesn't have to *really* build trees, that's between it and its spiritual advisor. But it has to have enough info to build them.
the interface on the writer looks like:

fun build(builder:TsdBuilder)

what it will do is call that builder in a way such builders need to process the TSD as if it were a tree.
The TsdBuilder interface has three functions:

open(path:String, node:String)
leaf(path:String, node:String,value:String)
close(path:String, node:String)
The arguments are the full period-delimited path, the node, which is actually just the rightmost element of the full path, and if the node is a leaf, the value of that leaf.
So. I'mo go make those interfaces, get myself a TestingTsdBuilder, and get a concrete TsdWriter to do it right.
Heh, a classic over-coding happened. Over-coding is when you write more code than you have test. This is a common occurance, especially when you start with the answer already in your head. In this case I forced the output to be sorted before I had a test that required that.
Over-coding is not a sin, but under-testing is. What I mean is, I don't beat myself up for thinking ahead. It happens to every TDD-er. But I *do* stop as soon as I notice it and go make sure the tests are caught up before I keep going.
Sometimes, I'm doing it in this case, I just comment out the extra for a second, write the test(s) that will call for it, and make sure they're red before I uncomment it.
(All better on the overcode.) The build algo can now handle simple one-child tree's:

parent
child
grandchild

I'm about to break that though, because I want it to handle:

parent
child1
child2
There's something very close to the heart of TDD in this. My code solves every problem I've given it so far, not every problem I have. I purposefully give it a problem I think will break it. I purposefully predict out loud that it will. Then I change the code til it doesn't.
By the way, I explicitly decided here to test the build algorithm using a fake of the kind that Meszaros calls a "spy". All it does is add a string to a list for every call that's made to it. The assertions are then made against that list.
It's worth noticing that decision, which isn't a super-common one for me to make, and wonder about why I did it that way.
Here are two alternate ways I could have done it. I could have actually built one of the useful TsdBuilder's I know I'll want. I could have used an automocker like mockito.
I chose not to use the automocker because automocker's are heavyweight and very powerful tools that come with a high price in complexity and a high risk of enabling terrible design. I've written that up somewhere, and don't want to go into it again now.
I chose not to build and use a *real* builder because I didn't want to be simultaneously testing the build algorithm and my new builder. I just wanted to test the build algorithm itself. I'm trying to minimize my mental bandwidth.
I chose the simple string-array collector trick because I want the tests to be super-duper graspable by me, and I want them to be rigorous and complete. The build algorithm is at the core of the value I want to get from TSD, so it's super-important that I understand it perfectly.
I remarked that I don't write a lot of behavior-centric tests like this. That's because I'm not normally writing code where the desiderata is a particular algorithm, a particular set of operations. Far more commonly, the desiderata is a chunk of data.
Very well then. I wrote the test, it broke as expected, and I then changed the code until it's all green again.

But.

Now I hit two problems.
The first problem is that the code is -- I'm going to use a technical term here -- icky. I don't fully understand it. It's not obvious what it's doing or why. I have a couple of if's there that seem like they should be handled in a better way.
The second problem is combinatoric uncertainty. I *think* this code handles all the cases. But I don't *know* what all the possible cases are, and I can't enumerate all the actual cases I'll one day see in the wild.
So, I'm gonna approach those in reverse order. First, I'm going to throw some more cases at it, more tests, and see if/when it goes south. At that point, my confidence will be higher, and I'll spend some time seeing if I can make the code felicitous.
Oh, FFS, once again I forgot to *start* this muse by sharing the repo. These muses are live-action, and you can follow along in the code by checking out

github.com/GeePawHill/tsd

It's Kotlin, and I'm using IntelliJ. The prior articles are on the blog, and all start w/"TSD".
I'm gonna take a shower and play my game for a little while, so the next round of changes might be a bit.

Meanwhile, have a great Sunday!
Missing some Tweet in this thread? You can try to force a refresh.

Enjoying this thread?

Keep Current with 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!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Follow Us on Twitter!

Did Thread Reader help you today?

Support us! We are indie developers!


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

Become a Premium Member ($3.00/month or $30.00/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!