My Authors
Read all threads
Aight. I been away from programming for a couple of months, but there was a reason I started talking the other day about the kontentment project: I'm wanting mucho change in it.
For a talk I'm giving, I want the ability to draw human arcs, with the same ease with which I can draw human lines. So I set out today to get that in.
Human straight lines start with a line segment AB. Pick two random locations on that line, so we got 4 points. Now jiggle all four points a little -- that's official terminology -- and make them the four points of a cubic bezier: start. handle1, handle2, end.
I "invented" this algorithm by going to a live JS site that lets me play with cubics visually and, uhhh, goofing around with them. At that time, I didn't know how to interpolate cubics, but learning that was part of it, too.
The upshot: I can cause lines that look as if a human had drawn them with a marker to appear as if the drawing were happening live.
I further added optional arrowheads at either end, which was *also* something I had to learn how to do. (I am not a math/geometry head, I had to slog through a lot of articles I couldn't understand to find ones I could make sense of.)
Two geepaw-isms: GAK means "Geek At Keyboard", and GAK testing means testing your code by running the app over and over and seeing what it does. RORA means "Runs Once, Run Away", and refers to the practice of leaving bad code that passes GAK tests, moving on even tho it's awful.
So this code was GAK-tested RORA. I have all of the normal excuses for this, but the key one: damned if I could figure out how to test most of this app at that point. More correctly, how I could *profitably* test most of this app at that point.
There were/are various schemes one could use to create tests, but all of them would be basically automating the whole damned UI and comparing old and new snapshots looking for differences. That kind of test is a) slow, b) large, c) uninformative, and d) unlikely to find anything.
The JavaFx graphics engine is multi-threaded, double-based, auto-scaling, anti-aliasing, and has no cheap "headless" mode. Tests that can only run on my exact hardware are not our friends.
And besides, I had the thing running, I used it for dozens of presentations with hundreds of human lines, and it unquestionably worked. Not bloody likely I was gonna change all that, ya know?
Setting aside tests and testability, the code is a work of extraordinary crystalline genius, or, I mean, it *would* be, if I'd written it very well. But I didn't. And working so testlessly, refactoring to get it there seemed like an infinitely delayable goal. MORE FEATURES!!
Anyway, there I was, nekkid as a jaybird, and I'm wanting these arcs, and I'm wanting them to be "just like" the straight lines. There'll be minor differences, but not so much. Let's re-use the code! Let's *refactor* the code so we can re-use the code! Yay, team!!!
So I go study the code -- it's been well over two years since I RORA'd it. And my goodness, what do you think I found?

Uh-huh.

Exactly what you're guessing I found.
The factoring is awful, with the code in the wrong place both "objectfully" and "temporally". Though the two most heavily used component classes are well-done and thoroughly tested, the stuff the hoops they're jumped through are largely opaque. It's not good, kids, it's not good.
The algorithm I described above is correct and accurate. It is by no means expressed in the code as simply as I expressed it up there.
Now consider doing "just like" that algorithm, only with an arc. Take line segment AB and a height. Make a cubic that pulls the line up so that at its maximum distortion from AB it's height pixels away. I did that first thing this morning just to confirm the concept for myself.
I mean, take a look, if you want: dropbox.com/s/9lj1btsg7sin…
But it looks *exactly* like a computer drew it, and there are no arrowheads, and that's not "just like" the straight connectors.
Arrowheads first: the existing code computes them at a bizarre time, and is *deeply* committed to the original line segment's starting point for its orientation. But that won't work here: they should be roughly oriented back to the "height" value.
Then humanness. In the straight line code we "cubic-ize" a line segment then jiggle the control handles. This inhuman arc isn't a line segment, it's already a cubic.
Okay, fine. We'll pick two random points on this starting cubic and split it at those two points, yielding three total cubics. Then we'll jiggle the control handles on all three of them, and sit back and wait for the stock options to mature.
So that's the plan, but in the interim, I finally figured out what I needed to do to raise my tests and testability in all this crap, so I want to do all that, too.
Two straightforward resolutions to the testing issues, and both of them I've applied a thousand times in my TDD career, but what can I tell you, somehow they didn't feel doable back when I first RORA'd this. They're both easily doable.
1) JavaFx works, at least as well as any library that is built-in to one's language. Don't test it. Put the *geometry* and *logic* in non-JavaFx classes, and test it there.
2) Geometry works. Don't test it. Test that your implementation of geometry works in all the known readily calculable cases you can think of, up until the day your GAK work reveals you haven't thought of them all, then add some more.
These two notions, as I say, are just basic chapter 3 TDD, and I can't think why I didn't see them both before. Or, I spoze I can: solo work, too few advisors who insist on microtests, MORE FEATURES, stress of being both geek & product for myself, all the usual suspects, really.
So there ya go. I started. I wrote a tested ArrowHead class from scratch, essentially copy-paste-heavily-edit the stuff in the existing Connector. This time I made it *not* assume orientation-point. I tested it using the four 90 degree cases.
Next step, refactor the existing Connector code so that it can drop its own implementation and use the actually-tested single-responsibility constructor-only API *new* class instead of its old in situ hack.
Once I've done *that*, I can GAK test older scripts and make sure they still render arrowheads "correctly". (A founding premise of kontentment is that actual pixel-for-pixel accuracy is almost entirely irrelevant to my purposes in having it, so some variation isn't an issue.)
And that's the state of play. Once I'm happy with the extracted and testing ArrowHead, I will tackle the humanness issue. I have only a broad notion of how that will go.
I'm not here to offer morals to this story. I have some -- for myself -- but instead, I just wanted to share more of what "my actual coding" looks like.
Too much of our pedagogy is about how perfect humans write perfect code by making perfect decisions, and that's just not what actual making is like.
I've a rep as a "TDD expert". I don't want to spend that by spewing psuedo-algorithmic psuedo-axiomatic TDD bullet points.

I don't think that works. I don't know if these detailed stories will work better, but one of my mottos is "Try Different, Not Harder".

So I am.
All of my stuff is at geepawhill.org & this will go up there as blog & podcast soon enough. If you like this, 1) subscribe, and 2) consider joining the change-harvesting camerata, which supports this effort as part of a much larger effort to change the trade.

Thanks!
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!