Next time you have to learn a programming language, or a set of libraries from an ecosystem, put your learning under unit tests. It has 7 amazing advantages.

My story

Learning programming things by unit testing them is something I've done three times.

The first time and the original inspiration for this idea is the Kotlin Koans, a much believed way for Java developers to start learning Kotlin by running failing tests and fixing them one by one.

Later, I realized that while I had mastered the language, there was behind it a huge ecosystem of Java and Kotlin libraries, and I had no structured way of learning them. I was messing up inside my employer's main projects - and its 3 minutes compilation times - with my messed-up first attempts at understanding the library, and that does not count as a structured approach !

I remembered the experience of learning from the Kotlin Koans and wanted to have something similar. The kotlin-libraries-playgound project came out of this simple idea, and grew and grew. Today it contains samples for [Apollo, CliKt, Kodein DI, Kodein DB, Exposed, Fuel, Hoplite, Klaxon, Konad, Konf, Kotlin Collections, Kotlin Faker, Kotlin IO, Kotlinpoet, Kotlin Statistics, Kotlinx Serialization, Ktor Client, Mordant, Moshi, OkHttp, OkIO, Picnic, Retrofit, Skrapeit, SqlDelight, Statemachine, ]https://github.com/LouisCAD/kotlin-libraries-playground/tree/main/kotlin-jvm/src/main/kotlin/playground), KoTest, Mockk, Spek, Strikt, Mockito, Junit-Jupiter, etc.

But it was my third attempt that really cemented this practice in my mind.

This time, I needed to learn a new programming language and its huge ecosystem: Typescript and Node. Again I chose to learn by writing unit tests. You can find my project here:

Again I was delighted by the experience and I will try to explain why.

It starts with a simple mental switch.

Don't log, verify

When you follow the documentation of a programming language or library, you will typically read a piece of code that takes some input and transform it, before printing it to the console.

If you are like me, reading is not enough. The tutorial may explain things well, but only you can do the job of understanding it, and that usually requires getting your fingers dirty playing with the code.

Now the issue of just using console.log() is that the results are gone as soon as you have logged them, you are on to the next thing. Whereas if you make a unit test out of it, you have a self-validating piece of code that you can execute over and over.

So don't stay here:

console.log(formatted)
// May 21st 2021, 3:20:04 pm

Do this instead:

it('format dates', function () {
    const moment = moment('2021-05-21 15:20:04')
    const formatted = moment.format('MMMM Do YYYY, h:mm:ss a')
    expect(formatted).to.equal("May 21st 2021, 3:20:04 pm")
});

Get started with a pair-programming session

I started my node-playground repository by doing a pair-programming session with a friend.

I highly recommend this since it got many questions out of the way:

  • Can you walk me through this package.json? What do I need to know?
  • How do I add a library and its types?
  • How do I add and configure typescript?
  • I don't understand how imports work, can you explain?
  • How do I setup a test runner? (mocha)
  • Can you setup the tests in watch mode? (Yes)
  • Which library do you recommend for the assertions? (chai)
  • Can we write together a simple unit test for a library? (Moment.js)

Configuration gets in the way when you are getting started, so ask a human for help!

Get practical experience of writing the code in the IDE

Some learning websites have their own embedded text editors.

While this has its advantages (zero config), at the end of the day you must develop the skill of writing code in the IDE of your choice - Visual Studio Code, or Webstorm in my case -. Using this approach will get you plenty of practice.

Quick feedback

A big advantage of this approach is that you have a fast feedback loop.

The quick feedback loop inherent to this practice helps you get in the zone, as defined by Mihaly Csikszentmihalyi:

In positive psychology, a flow state, also known colloquially as being in the zone, is the mental state in which a person performing some activity is fully immersed in a feeling of energized focus, full involvement, and enjoyment in the process of the activity. In essence, flow is characterized by the complete absorption in what one does, and a resulting transformation in one's sense of time.

https://en.wikipedia.org/wiki/Flow_(psychology)

You advance steadily, test by step, stone by stone, in reversible steps.

Practice testing from day 1

A credibility issue that junior programmers have - and sadly even non-junior programmers - is that they have little experience with testing. "Getting" testing is an important hallmark on the way to professionalism.

But is testing hard?

I think the distinction from Rich Hickey: Simple is not Easy is important. Testing is a simple practice once you get it, but it's not easy in the sense that junior programmers don't have lots of experience with it, if at all.

But if you practice testing from day 1, it sure won't feel that hard the day you are hired!

A mentor can easily review your work

Another advantage of having your learning contained in a GitHub repository is that it makes it easy for a mentor to review your work. Add them as collaborators to your project and ask them what they would change in your codebase. Then look at the diff together, it's a great way to start a conversation about what you need to learn next.

Keep your knowledge up-to-date

This one especially applies to unit tests for libraries like in the kotlin-libraries-playground project. Since the code is self-validating, you can update the dependencies and see what has changed and what was broken. Yes, it's work, but it's useful work. It keeps your validated knowledge fresh.

Use the repository for bug reports

The Kotlin libraries playground has also been very effective for me to report bugs. When I was facing an issue with an external dependency, I created a new branch and added the minimum amount of code that reproduced the problem. Having reproducing steps helps the maintainer to provide you a fix more quickly.

Proof of knowledge for job interviews

This one is big. You know the traditional dilemma: you want to have your first programming job with $LANGUAGE, but you are getting rejected because you don't have experience in it yet.

The way out of this non-sense is to show that you have acquired enough knowledge with it. Sure enough, having a public repository that demonstrates your knowledge is a great way to do that.

Conclusion

Writing unit tests on what you are currently learning provides for a great developer experience, similar to what professional developers do. With time it becomes a public repository of your validated knowledge, which can stay up-to-date, and is useful for getting feedback, reporting bugs or demonstrating your skills in the context of a job interview.

It goes hand in hand with the good tip of writing and publishing real projects. Putting out a new project is like assembling a new puzzle. Writing unit tests is all about understanding better what each piece of the puzzle does.

If you want to contact me, read my standing invitation at https://jmfayard.dev/contact/

This post is also available on DEV.