First8 staat voor vakmanschap. Al onze collega’s zijn een groot aanhanger van Open Source en in het bijzonder het Java-platform. Wij zijn gespecialiseerd in het pragmatisch ontwikkelen van bedrijfskritische Java toepassingen waarbij integratie van systemen, hoge eisen aan beveiliging en veel transacties een belangrijke rol spelen. Op deze pagina vind je onze blogs.

1 m² of source code and a single Java interface to tame it

You know that most of the task planners or calendar apps have features when you create a todo, task or meeting they try to be “smart” in filling in as much details as possible?

You enter the title of a new e.g. meeting and based on some heuristics it tries to conveniently set some additional properties.

This is what Alice considers the biggest unique selling-points of her company’s new Calendar app. Development started just this morning and its kick $ss features will blow the competition out of the water!

Consider the very first version of the main Calendar application which tries to detect the start date of the meeting, based on some known keywords such as “today”:

The Calendar gets the text of the new entry from the user, sets the entire text into the title and because it detects a known keyword “today” in it, and sets the start date of the meeting to today’s date. We’ll worry about internationalization for another time 🙂

The following test case demonstrates this behaviour:

Changes

Now developer Bob thinks this is a very neat little Calendar system which could benefit from some additional contribution: automatically adding attendees based on a recognized name from the phone book.

Bob exercises some proper TDD thinking and changes the test to reflect the desired behaviour.

To make the test pass, he updates the Calendar to find contacts in the phone book (mentioned by name) and automatically add them as an attendee to the meeting.

Changes

Now co-worker Chris picks up a new user story which reads:

Given a possible location in the title / When you can detect a correct address / Set the meeting’s location to the found address

He knows a pretty decent online API for (fuzzy) searching for addresses and makes the necessary changes to the main body of the Calendar class.

As soon as he commits his work to version control, he encounters some merge conflicts: seems Alice has updated the Calendar already in the meantime with some changes to the start-date-detection-algorithm.

Chris gets Alice’s new updates, merges them with his own code locally and re-submits again to version control. Seems Bob beat him to it! There was a bug in the attendee-finding-logic, but Bob squashed it already – that’s how he rolls. Anyway, whether Chris could back away a little from that general Calendar area at all the rest of the day, if he didn’t mind? Senior-architect Dave just came back from holiday and fancies some development work himself. Not too impactful, some variable renaming or something.

Changes

That does it!, co-worker Eddy thinks when he sees his colleague Chris crying. He says: “Why don’t you isolate these changes from each other in the application? Every part which contributes something to a meeting can work in isolation, developed in isolation and tested in isolation. There’s no need for everything to happen inside the Calendar itself, because as you’ve noticed: integrating your changes with other people’s changes continuously on the same 1 m² of source code is a friggin’ goat rodeo!”.

Then Eddy did it:

He created an interface.

Chris was baffled! And thinking: “The beauty of it! The Calendar itself doesn’t care about the start-date-contribution-algorithm, the attendee-finding-logic and probably also not about Chris’ own work-in-progress of detecting a location.”

“No, it doesn’t” says Chris, as if he could have overheard Chris thinking. “Each and every individual behaviour can all be abstracted away into their own hidden implementations of that interface. All the Calendar knows there are parts of the software which it needs to collaborate with. Everybody can contribute something, it just needs to give everyone a chance.”

That’s some deep stuff!

It’s good to have a test in place, so together they reckon it’s pretty safe to apply some refactorings.

Changes

Alice moves her start-date-contribution-algorithm to a separate class:

Bob follows and moves his attendee-finding-logic to a separate class too:

Finally, Chris can actually also find a spot for his work-in-progress code of trying to detect a location, and creates a separate class too:

Chris knows his feature is far from perfect, but that’s OK. He also knows he can make improvements without having to touch anybody else’s code!

Without all the features removed, the Calendar is in a sorry state, according to the tests.

Luckily Eddy quickly manages to make the necessary adjustments and really trims the main Calendar logic down to just calling the contributors:

at the same time he makes the test actually use the contributors:

Test changes

Chris, eager to bring also his location contributor also under test, adds it to test in the initialization too…

…before Eddy steps in: “Not on my watch, Chris!”

Chris: “What do you mean?”

Eddy: “Look at the Calendar, man. It hardly does anything at all, except call one or more contributors. That’s the only thing actually worth checking in the Calendar test. You think it cares for your location feature, Chris?”. To Alice and Bob (which quietly had Chris take the heat when they knew very well were this was heading) “Well, let me tell you, it’ll no longer carry your feature’s water!”

It took a while for the team to realize that for their own isolated code they also should have their own tests now. Not only would the team conflict again on another patch of 1 m² of test source code, but having the Calendar tests fail based on the correctness of their ever evolving contributors would definitely come up at the company BBQ. Shivers!

Alice moves creates a start-date-contribution-algorithm test in a separate class:

Bob follows and creates an attendee-finding-logic test in a separate class too:

Eddy changes the original test to verify if the Calendar actually calls whatever contributor is passed in.

Chris thinks such a test which asserts two things should actually be two separate tests, and he’s read somewhere it’s better to use test doubles instead of mocks, but he reckons that’s not the kind of decisions Eddy wanted to showcase here. What a great guy!

In the weeks after

Alice has made here start-date-contribution-algorithm i18n-aware and support 34 languages, including Klingon. She never touched the Calendar class, or test for that matter, ever again.

Bob started making the Calendar itself more versatile by introducing concepts which all could benefit from the same contributing logic, such as Appointments, Tasks, Todo’s, Diaries, Bullet Journals by introducing a general Thing abstraction.

Chris built the entire contribution mechanism out to a full-fledged plugin-mechanism leveraged by an online Marketplace boasting more than 500+ plugins which all perform a better job a location-detection than Chris’ own version ever did.

This has been cross-post of my personal blog.