Sprint 1: How TDD and careful approach design promotes a smoother & bugless development

Jonathanjojo
6 min readOct 16, 2020

--

Thinking inside-out and outside-in at the same time.

source: https://medium.com/dtran-design/who-am-i-45a4ee8606

This article is made as an assessment for Software QA course: CS UI 2020

Background

Long-story-short, We were given a project repository (an online library service) that has a lot of room for improvements. I was instructed to submit 1–2 issues and create a merge/pull request regarding those issues.

And, I have to do the task using TDD.

A recall of Test-Driven-Development (TDD)

TDD is a practice where you write failing tests targetted for a certain implementation, then write the minimum implementation such that the written tests can be passed, then refactor the code to give it some cleanliness.

Red (failing test). Green (implementation + passing test). Refactor. REPEAT.

With TDD, you are thinking inside-out: we start with the function in mind, determine the correct output, and slowly growing the application.

What else? Design before you code.

I always have a pattern: determine first the behavior of the final app. Before a single line of code is written, you need to begin by understanding the problem you are trying to solve, how the problem was created, and what value you project the solution to have. Before you code, you should have a clear vision of what you are going to build.

Therefore, you are thinking outside-in, determine the behavior of your application, then implement the functionality to fulfill the behavior. You will better know what to code.

The 2 tasks at hand

The first task was to create a statistic API accepting start and end date parameter. This API was to return an aggregated daily count of views, downloads, likes, and comments. To be honest, this is quite simple and fast for me since I had done a similar thing for another project.

The second task was to display comments on uploaded materials. There was supposed to be a page containing a list of materials, each material has a list of comments that are associated with it.

How I finished the tasks

Task 1: Traffic Statistics API

So, I began to think of how I want the service to behave and what the service to be.

Fast forward, I wanted it to be called from a certain URL: /statistics/api/ with a start and end date parameter, I wanted it to have a daily count aggregator, I wanted it to have a dictionary generator to provide the container for the return data (as well as the shape of the data), and I wanted it to have a view to actually return it into the users.

Then, I looked into the current code, explored the environments, and took mental notes about the models I would use.

With that in mind, I can look into the future: which parts of the code will I have to modify and which parts I will create. With all of those being set up, I was ready to code fast and code right.

I started by creating a new dedicated application for it. And here comes TDD. In my opinion, TDD made me focus on the task and (almost) all the cases that could manifest.

  • I began to create a test to direct the mentioned URL to a controller/view. I proceeded to write the view class name with no implementation. Done.
  • I remembered that I was going to accept the start and end date parameters. I wrote the tests to accept those. And while I was writing the test, I realized that I need to validate those parameters (thank TDD again). I created some cases, failed the tests, implemented the validators. Done.
  • It came to the real deal, the counter. I made some test values to mimic the traffic, counted them, created the tests, easy. Now, back to the things I have designed earlier, I made an aggregator, a dictionary generator, and finish the view to return them. After some not so long time, it was done.
  • But, when I ran the test, I realized that the feature I had coded could be confused if the date parameters are in the future. Back to TDD, I needed to test these as well. So I did, then I added the implementations, done.

After some small refactoring, it was done with 100% coverage thanks to TDD, and it was the right approach thanks to the careful design. During this development, I realized that designing the code first helped me to create a service that is returning the correct value as needed, and TDD helped me to avoid having a crashed app due to unhandled errors.

Task 2: Post-Comment Grouping

FYI, I started doing this task not long after I finished the previous one. The same technique applied.

First I looked at the current page, see what changes are needed. It only displayed the comments and a link to the material it was attached to. Of course, it would be better if it were to display the comments per material. Next, I looked at the code behind it and quickly determined that I would have to change the return value — as well as how to get the value I was looking for.

So, my decision was to have a new page with a new title and URL, the new page would need the comments of all the materials instead of just the comments. In other words, it had to display all the materials and all comments that were associated with each material. Therefore, I would need to have a view that could return this grouped data.

After some looking around, I decided that it was okay to have a new view, a new template, a new URL, etc. After all of those were done, I had to remove all references to the old ones.

The designs and detailed approach had got me so far, here comes TDD:

  • I decided to have a new view altogether. So I started by having a test to assure that my URL is directed to my new view. I had a minimum view set up. Tested, failed, created the URL mapping, done.
  • Then, I decided to have a new HTML template as well. So I tested the rendered template, failed, returned my new template, passed, and done.
  • I tested and implemented the permission as well (from the old one).
  • Here comes the real deal. I already decided from the start that it would have to return a grouped data. I created a test value for this, and a dictionary I expected from the view as the returned value (context). TDD helped me a lot in visualizing what I needed.
  • Then, I failed the test, implemented the grouping (it was just a simple query on all the current user’s materials and the comments). Then I returned it just like the dictionary I used for testing. And when I passed the test, I was done with the value.
  • But then, the grouped value did not finish the task. The task was to group it visually. So, I needed to test the elements in the rendered HTML. I couldn’t use selenium because it would be too costly to install and run. Therefore, I decided to test the HTML code, I set up a regex match to indicate that within the div of a post, there are div-s of its comments.
  • That being done, coding the HTML was not hard since I only displayed my already so structured dictionary passed as context. By the time the template was done, the test passed as well.

Just like my plan at the beginning, I cleared all references to the old one, and the app was integrated with my new template and view. Again, designing helped me to visualize and plan the tasks I’m doing way more clearly. My development pace was very much more structured and organized. TDD came in so my code can be validated and ensured to work correctly as planned.

Conclusion

On this sprint, I may not learn a lot from the tasks, but I personally learned how to carefully design the approaches first.

By designing the approach first, it helped me to visualize the tasks I’m doing, helped me to direct my development course, and provide a big picture view of the service I am working on. In other words, designing an approach analysis ensured that I made the right decisions on the development.

Then, during the development, TDD helped me to produce a

Design your service, then test it along as the code grows into the service you have foreseen.

--

--

No responses yet