2021-12-20 08:29

REPL vs test driven development

Sara Wänerskär
Ville Svärd

How are Funnelers encouraged to code?

Developers at Funnel have a great degree of freedom. They get to prioritize their work and what problems to focus on and are encouraged to experiment with new technologies. Collaboration is encouraged. One of the advantages of this joint ownership approach is that code bases will be less person dependent. This enables developers to change teams without having to change employers.

At the same time, Funnelers are encouraged to write code that has specific qualities. Funnel developers like readable, simple code with high test coverage. Test-driven development (TDD) is close to many developers' hearts. High test coverage is a way of documenting the code and should make it easier for all developers to read unfamiliar codebases.

What is test-driven development?

Software engineer Kent Beck made the term Test Driven Development in his book Test-Driven Development: By Example. The book is only just over 200 pages long and is considered a classic in the TDD community and describes the test-driven approach.

Failing unit test in editor

According to Beck, the key to test-driven development is that the tests are made to drive out the behavior. The workflow looks like this:

  1. Write a small test for new functionality. This test will fail.
  2. Implement new code that will make the test pass.
  3. Refactor as necessary.
  4. Repeat

The entire unit test suite will run continuously so that the developer can see if they break any existing functionality. TDD brings several benefits, but some key aspects are that tests will be written, and developers will be encouraged to write code that will be easy to test. Code that is easy to test will be easy to understand and reason about. A key feature of TDD is the constant re-running of tests - failing as well as successful runs. This provides quick feedback and can - with a good test-runnerIDE or language - almost feel interactive in that a developer can quickly try out new ideas, see if they break previous assumptions or work out.

What is the REPL?

Most developers at Funnel use Python and Javascript. However, there are several functional programming enthusiasts in the company. One team uses Clojure as their primary programming language. Functional programming, as explained by Eric Normand in his book Grokking Simplicity, divides code into three parts - data, calculations and actions. Calculations are also often referred to as pure functions. A pure function is only dependent on input parameters and will return the same result every time it is called with the same values. Thus a pure function or calculation does not depend on a volatile or shared state and results in no actions (aka side-effects).

The REPL, or Read-Eval-Print Loop, is a much-loved feature of Lisp dialects such as Clojure. It is a running environment (or program, if you will). A programmer can send input (code or data) to (Read), evaluate it (Eval) and have the result printed (Print) by the REPL. REPL-driven development encourages the programmer to work in small steps, try out, and interact with the environment by continuously evaluating their code. Working with a REPL, you are also encouraged to write code with few side effects. Setting up a state and evaluating side effects are hard work compared to writing pure functions. The fewer and more isolated the side effects, the quicker and more reliable it will be to type the code.

What is the goal?

As Eric Normand points out, the programs we write should have side effects. An application that does not write to a database, prints something in a UI, sends a message or reacts to the outside world rarely has any business use.

However, we want to make the code we write predictable. We want to trust the code. One way of building this trust is by having small functions that always return the same value given the same input parameters. These are pure functions. Writing unit tests for pure functions is easy. They will require few input parameters, and you will not have to worry about mocking, setting up or tearing down state etc. Similar to working with the REPL, the developer will get quick feedback on their work. If tests start failing, you know something is wrong.

An editor with the REPL running

If you are working with a REPL, you will be encouraged to write small pure functions for the same reasons. Sending code to the REPL is easy when dealing with small functions and simple test data. Feedback is instant. If you write code to the REPL that will test some functionality and decide that this will invariably be true, you can copy what you evaluated and save it as a unit test. Knowing that working in small steps and keeping things simple is efficient builds trust. In the long run, this can affect your trust in your colleagues, as you can assume that your colleagues have written the code using small steps and continuous feedback too.

In both TDD and REPL-driven development, a disciplined approach is encouraged to separate functions with side effects from pure functions. If you are a lazy programmer who likes to write robust code quickly, this is the way to go. Writing code that is easy to understand is doing yourself and your colleagues a favor.

© Funnel 2020 - 2022 | Privacy statement