How does TDD look like in real world development of microservices or web interfaces? That's what this series is all about. | |||
---|---|---|---|
1. Introduction | 2. The requirements | 3. Test case analysis I | 4. Test case analysis II |
Test case analysis III | 6. Test case analysis IV | 7. Setting up a project with Spring Boot | 8. Which tests to write? |
9. API design |
We’ve come up with a few alternatives for the APIs (their draft version, anyway). I’m going to weigh them here, and remind ourselves – this is the internal API forma, but also has a REST counterpart.
Let’s talk about each of the options, but this time, not just about how they look, but also about their design implication.
String pressKey(String key);
One API to rule them all. There’s an issue with its design though. If the UI doesn’t tell the server: “I’m ready”, or if it was refreshed in the middle of an operation, there could be a disconnect between what the UI displays and the server’s state. And where there’s disconnect, there will be bugs.
String pressKey(null);
Still a single API, but this time, we’re talking with the server. In order to reset, we’re using an API called “pressKey“, when no one has actually pressed any key. Exposing a special meaning with “null” to the outside world is not something I like to do. The last guy who did it called it “the billion dollar mistake”. Not only is anything being pressed, no nulls have been pressed in the making of this post. We’d like the interfaces to speak the language of the domain as much as possible, and this one kind of breaks it.
So how about that reset-as-a-startup?:
String pressKey(“C”)”
It’s a more attractive option, since the initialized system should behave as if it was reset with the “C” key. There is still the issue that nobody actually pressed anything. And although I don’t like planning and designing for future requirements, there may be a future where resetting results has a different behavior than the one on startup. In that future, we might want a different functionality when pressing “C”.
void pressKey(String key); String getDisplay();
If we separate the get/set operations, (and follow the command-query separation principle) we can get a nice, clean interface. At the start, we’ll call the “getDisplay” API to show what the calculator’s state is at the moment. Which may not be zero. It can be the last held result).
This is an interesting feature, although this kind of behavior was not requested. We need to show “0” in the beginning.
We can assume that “getDisplay” will result in 0, but that gives a separate meaning to “getDisplay” – if used at the start it shows zero, regardless of what the server holds. Additionally, this APIs require two calls to the server every time, which may be costly and slow.
void initializeCalculator();
Which leads us to a separate API for initialization. We probably need it – to tell the server the UI is ready. However, where does the zero come from? We still don’t want to press anything. So maybe the initializing method can return what to display:
String initializeCalculator();
While this is promising, there is some inside knowledge about what the return value that we’ll need to document, so people from now on will know. Tests will help, but maybe a better name can help:
String initializeAndGetDisplay();
It’s better, but still does two things. For now it will do. Next time I’ll tell you my pick and write some tests.
But before we go, you’re probably thinking – what we did here is a bit of cheating. We should have the API discussion while we write the tests. This is where we should actually do that thinking, not before writing even “@Test“. In fact, before the glorious TDD days, we’d write a design up front (in a 500 page document), and invent that API (hopefully thinking also about alternatives). Did we just jump back in time?
As opposed to a series of posts, our (and my) thinking is not linear. Neither of the “proper” TDD, or “proper” design is how we think. TDD, and development in general, is an iterative process. In this series, so far I’ve been writing and deleting stuff, just because I’ve learned things on the way and even (gasp), changed my mind a couple of times. It’s ok for thinking up front, (I’m a huge fan of thinking!), and it’s ok to let things change on the way. That’s how we think, learn and work and we should embrace it.
4 Comments
Ted · June 28, 2018 at 10:30 am
Nice article, Gil!
Regards, Ted
Gil Zilberfeld · July 3, 2018 at 6:36 pm
Thanks! More coming soon, after the break.
Brad · December 10, 2020 at 10:39 pm
Hi! I noticed that the article series table of contents seems to be missing some articles—like this one and the few before and after it. Just thought I’d let you know.
Gil Zilberfeld · December 11, 2020 at 12:34 pm
Thanks! When I get around to both updating the site and the series. I really want to, but work gets in the way.