App 2: To-Do List (TDL)

In most of the remaining lessons of this book we’re going to build a To-Do List (TDL) application that you can run at your operating system command line. The purpose of this is to show more of the nitty-gritty details involved in writing a Scala/EOP application, including how to compile and run it using a tool named Scala-CLI.

How the app works

TDL is a command-line application that you run with scala-cli. To run it, clone this book’s Github repository, move into the ToDoList directory, and issue this command:

$ scala-cli run .

Or, if you prefer, use this shorter command:

$ scala-cli .

Both of those mean, “Compile the code in this directory, find a main method, and run it.”

When there are multiple main methods you have to add an additional option there, but with one main method, this command works.

When the app starts running, you can type the letter h to see help. That help output shows that the app accepts these single-letter commands:

COMMAND           DESCRIPTION
-------           -----------
a [task]          add a to-do item
d [task number]   delete a task by its number
v                 view the list of tasks
q                 quit
h                 show this help text

Given that background, this is what a small interaction with TDL looks like, where I add two tasks with the a command and then delete the first one with the d command:

(Commands: a "task", d 1, v, q, h)
Yo: a wake up
1. wake up

(Commands: a "task", d 1, v, q, h)
Yo: a brush teeth
1. wake up
2. brush teeth

(Commands: a "task", d 1, v, q, h)
Yo: a make coffee
1. wake up
2. brush teeth

(Commands: a "task", d 1, v, q, h)
Yo: d 1
1. brush teeth

So that’s how the app works.

Rules for writing the app

To write the TDL app, I’ll use the same rules I followed so far in this book. It will use:

  • Immutable variables
  • Immutable data structures
  • Pure functions
  • Expression-oriented programming
  • Functional error-handling

I’ll also add this rule:

  • Any function that interacts with the outside world must return a Try value

I used this technique when reading the document from the file in the Word Count example, but now this is a hard rule.

A flat-file database

I initially started to create this app using a SQL database and a Scala database library. However, once I dug into Scala database libraries, I saw that they almost all jump right into FP concepts. And because we’re still building our way up to those concepts, I decided not to use that approach.

Instead, this application will use a “flat-file database.” This isn’t a real database, it’s just a file. For the TDL app it will contain a list of “To Do” items on separate lines, like this:

Wake up
Make the coffee
Brush my teeth
Take a shower

However, if you’re ever interested in more advanced uses of a flat-file database, a common approach is to separate fields in the file with a field delimiter, such as a | symbol. When you do that, your rows will look like this:

|Alvin|Alexander|Talkeetna
|Fred|Flintstone|Bedrock
|Mary|Bailey|Bedford Falls

So we’ll write this database code in the following chapters, and the benefit of this is that you’ll see how you use Try at the boundaries of an application to communicate with the outside world, and how that works with the rest of your code.