WebCalc iteration 5 - more complex calculations

Welcome everyone to the fifth iteration of WebCalc. Previously I only managed to fix a few issues with the code and upgrade Java, Spring Boot and Gradle. This time I’ll get back to adding new functionalities and add a possibility to do more complex calculations like 1+2+3. To IDE then!

But first, let’s deal with some technical issues. One is upgrading Gradle to stable version 5.0. Having installed it locally on my machine, I can just call gradle wrapper --gradle-version=5.0 --distribution-type=all and that’s it, see commit 14c17dc3.

The second thing is this possible bug in Spring Boot Gradle plugin I was complaining about previously. I did some investigation and, although there might be something not exactly right with this plugin, the problem is actually how I’m using both that and dependency-management plugins. I should have done RFTM long time ago. Knowing how to do it properly I can now just import spring-boot-dependencies BOM and have all versions in all modules in sync, see commit 2de6a84c. I must admit though that I’m still not sure 100% if that’s the correct way, especially given that two ways of applying plugins in Gradle do not merely differ in syntax.

Short mental detour. Outside of this project, I’m recently trying to find a balance between two aspects of developing software: delivering business value and good engineering. On one hand, I have a feeling, that we’re too focused on technical details, like using the newest and the most hype technology there is, but providing very little actual value to our stakeholders. On the other hand, we can be so focused on the business value that we are ignoring good engineering practices like keeping cohesion high and coupling low. Not many conclusions yet, but I believe, that we should keep our tools reasonably up-to-date. In order to not spend too much time on that, we need to know how to use them properly and not to couple them too tightly to everything else. That’s why I allowed myself to go for all those improvements and fixes lately. Happy to discuss if someone feels like.

Having technical issues out of the way, I can again focus on the code. First, I noticed, that some tests use helper methods I created, some are not. That’s easy to fix:

Finally, I can make some progress in terms of functionality. My goal is to have a possibility of calculating expressions like 1+2+3. This time, however, I’ll start not by writing a test. To make it pass I’d need to spend quite some time, but I don’t want to be “in the red” for too long. I’m using reverse Polish notation and there’s a known algorithm how to do calculations using it. I’ll go for obvious implementation. I’ll also do it “first make the change easy, then make the easy change” way. The first step would be to start using Stack in Calculator and keep all current tests green, like so:

I just used for the first time var keyword. It feels like I’m giving up on type safety, but I’m also removing a few characters from the code, so the rest should theoretically be more “meaningful”. I’ll see where that goes, maybe it’s not a bad idea after all.

OK, I now have a partially implemented algorithm for doing calculations in reverse Polish notation. It only supports one operator, but it’s sufficient to keep my tests green. Can I go towards the full algorithm already? I don’t think so, it’s too early, now I need a new test.

I created two tests, one on REST API level and one unit test. They verify exactly the same behaviour, but on different levels. REST is what I’m actually after, but unit tests let me work much faster and get the feedback earlier.

As expected, the tests fail. I need to introduce a loop in the Calculator, like so:

I’m relying in here on exceptions to differentiate between numbers and functions, which I’m not entirely fond of, but it’s enough to make my tests green. In a real world that would probably be not enough and I’d need to revisit this place later on.

That should honestly be about it when it comes to the algorithm itself. To verify this I’ll add a few more test cases:

Looks good, I cannot find a use case, where my implementation would fail. I’m sure you can figure something out, like trying to use all memory.

That would be all for this time. I think I have enough of my “business logic” and can go to more tricky parts like users, security and billing. That’s the part where I’ll be going into the unknown myself. See you there!