Press "Enter" to skip to content

Week #2 – TDD and first refactorings

It’s one week into a competition and I already have a delay 🙁 I have planned to have the parsing of timetables done by now, but unfortunately I didn’t manage to get as much free time for this as I would like. Also, I had to make some refactorings, as my initial design had flaws.

TDD

Till now I have managed to create parsers for most of the sections that timetables consist of. But unfortunately, this means that I have done only about a half of what is needed in terms of parsing. But of course that’s because I was writing tests, that took time, right? And it has nothing to do with a fact that I was a bit lazy and didn’t have much time for development 😉 Well, that’s not true. As a matter of fact, writing tests first allowed me to find bugs much sooner and save some time in the long run.

Everything that I have done was done in TDD manner, that is Test Driven Development, which is a pretty fun and a really useful approach. If you don’t know what is TDD, here are some basics. There are only three rules in this approach. Here’s they are, as defined by Uncle Bob Martin:

  1. You are not allowed to write any production code unless it is to make a failing unit test pass.
  2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
  3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.

What this means, is that first, you have to write one test for the functionality that you want to implement, this test will, of course, fail, as there is no implementation – methods and classes do not exist, they have wrong algorithms etc. In the next step, you have to make the test pass. This means writing a correct implementation. But remember, you have to write the minimal requirements for it to pass. Nothing more. After this, when you have your test bar green, you can refactor your code to make it a bit better designed, more readable etc. All the time checking if all tests pass. Next, you repeat the whole process, create a new failing test, fix or create implementation and refactor. If you are interested in TDD and you would like to learn more about it check out Test-Driven Development by Kent Beck, it describes this concept really well.

When I started writing tests, I was using standard JUnit assertions like:

They are ok, they do their job just fine. But later, I started using AssertJ library, that makes these assertions much more readable, it makes them feel like real sentences. For example:

As you see, it’s a bit better.

On top of that, it comes with many more useful assertions which make tests even more concise and show the intent of a test much better. Here are few examples:

Or even something as awesome as these, that I have taken from AssertJ examples website:

As you see, it really is more powerful than standard JUnit assertions. And all you have to do to use them is add one jar to your project, for example, for maven:

Going back to the progress topic. All that’s left to do in my parser is parsing of one section. Unfortunately, it is the most complicated section. It has all bus lines with their routes and timetables – this is the most important section and as a matter of fact, it’s made of at least 5 nested section. It will require a lot of boring work, but should not be hard.

Refactorings

As I was implementing parsing of sections I encountered two small problems in my initial design. Some section had objects that consisted of more than a single line. For example, it had one line as a header of a bus stop and few more lines, indented a bit more, as a list of lines that were available at this stop. My initial approach was made on the basis, that each line of section is a separate, independent object. And that was wrong.

But there was an easy fix. First of all, I made my section line parsing method return an object that represented this line but return it only when this object was somehow important, like a bus stop. If it was not important I made it return null. Now, after parsing each line I would check if it returned an object, and if it did, I would remember last returned object in my parses object field. That way, when parsing the next line I could get a hold of last line result and add some data to it. This fixed my first problem.

The second one was a bad detection of nested sections. The timetables data is a list of sections, but some of those sections have some more sections inside them and those sections can have even more sections. So it is like a tree. First, I had to start parsing a new section if I found a section opening tag, this was working as intended from the beginning. I had onSectionStart method that took care of it. But finding a closing tag was not implemented correctly. I had to add this detection inside my AbstractSectionReader class inside its readSection method, that in the case of encountering such an ending tag, it should break the line reading loop and finish the parsing of this section. That way, the stream of lines could be returned back to parent section reader.

Here’s how the modified AbstractSectionReader looks like now:

As you see it is a bit more complicated, but thanks to this, writing parsers of sections is really simple, as all of the complex logic is encapsulated here.

And that’s all for this week. For the next week, I plan to have the whole parser ready and maybe even some database stuff have done already. We will see, so stay tuned for more.


Also published on Medium.