Posts tagged with: todoapp

TodoApp – part 4: Welcome softcore!

The application as getting a bit more well designed when it comes to DRY KISS, SR. But before we continue, we have a small problem in the last iteration.

We didn’t find a good way to get typed data back instead of a data reader. We didn’t want to fill a List<> and return it, because it would take a lot of memory if we have millions of todo items. Instead we developed two classes turning a datareader into a typed IEnumrable.

The resulting code in the ItemRepository looks like this:

        /// <summary>
        ///   List all items.
        /// </summary>
        /// <returns>A collection of items, or a empty collection if no items was found.</returns>
        public IEnumerable<TodoItem> List()
        {
            var cmd = _db.CreateCommand("SELECT * FROM todo_items");
            return new ForwardOnlyCollection<TodoItem>(cmd.ExecuteReader(), OnFillItem);
        }

        /// <summary>
        ///   Callback from ForwardOnlyCollection
        /// </summary>
        /// <param name = "reader"></param>
        /// <param name = "item"></param>
        private static void OnFillItem(IDataReader reader, TodoItem item)
        {
            item.Id = (long) reader["id"];
            item.Title = (string) reader["title"];
            item.Description = (string) reader["description"];
        }

And the method in MainWindow was turned into:

        /// <summary>
        /// Loads items from the database and inserts them into the list box.
        /// </summary>
        private void PopulateListbox()
        {
            lbTodos.Items.Clear();
            foreach (var item in _repository.List())
                lbTodos.Items.Add(item);
        }

The MainWindow class is now totally unaware of the data source. Neat, huh?

The next day

After sleeping very nicely the developer (humm, the one making the Todo application) woke up with four letters circling around in his head: S K I S. He didn’t make any sense of them and went to work. After looking at the code he remembered what he did yesterday.

“We didn’t want to fill a List<> and return it, because it would take a lot of memory if we have millions of todo items”

omg! The letters was in the wrong order, they should be “KISS”. Keep it simple (and) stupid. How often do we have millions of todo items? That would be quite sad, wouldn’t it?

He refactored into a regular list instead:

        /// <summary>
        ///   List all items.
        /// </summary>
        /// <returns>A collection of items, or a empty collection if no items was found.</returns>
        public List<TodoItem> List()
        {
            var cmd = _db.CreateCommand("SELECT * FROM todo_items");
            var items = new List<TodoItem>();
            var reader = cmd.ExecuteReader();
            while (reader.Read())
            {
                var item = new TodoItem();
                FillItem(reader, item);
                items.Add(item);
            }
            return items;
        }

A code duplication was also found. A TodoItem was filled with data from a IDataReader in both Get and OnFillData. OnFillData was renamed to Filldata and used in both places.

All code can be viewed at codeplex.


TodoApp – Part 3: Fix that data source.

Let’s continue with the refactoring. What are the main window really doing?? Well.

  1. Displaying todo list
  2. Loading and saving stuff to the database

That’s one thing too much. We’ll implement a Repository. imho, Fowler is wrong in his explanation. The most important goal with the Repository pattern is the following line: “Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers”. That’s what the pattern is all about, period. We do not want our domain to have any knowledge about the data source.

In later versions, the data source will be a REST web service publishing stuff as JSON. By implementing a Repository now, we get the bonus that we do not have to do that many modifications in later versions. All we need to do is to switch implementation class from one to another (since we are using an interface and not a class in our code).

The new class is called ItemRepository. The application is a bit more readable now than the first version, right?


TodoApp – Part 2: Single responsibility is what we need.

In our journey towards hardcore we need to refactor the shitcore into a bit more softcore =) I’m not going to show all source code in this blog entry. You can look at the code here.

It will take some iterations before the code is quite usable. In this iteration we will focus giving each method a single responsibility, which means that each method should only contain the logic for one thing. The constructor is a kick ass example of that. Lets look at it.

First of all, it’s responsible of connecting to the database.

public MainWindow()
{
    InitializeComponent();
    _db = new SQLiteConnection("Data Source=todomachine.db;Version=3;DateTimeFormat=Ticks;");
    _db.Open();

then, it’s also verifying that the table exists in the database.

    //create table if it do not exist.
    if (!DoesTableExist(_db, "todo_items"))
    {
        SQLiteCommand command = new SQLiteCommand(_db);
        command.CommandText =
            @"CREATE TABLE todo_items(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title VARCHAR(40) NOT NULL,
description text NOT NULL
);";
        command.ExecuteNonQuery();
    }

and finally it’s loading stuff into the list box.


    // load all todo items.
    SQLiteCommand mycmd = new SQLiteCommand(_db);
    mycmd.CommandText = "SELECT * FROM todo_items";
    var reader = mycmd.ExecuteReader();
    while (reader.Read())
    {
        lbTodos.Items.Add(new Item { Id = (long)reader["id"], Title = (string)reader["title"] });
    }
}

Let’s fix that and write a little bit of documentation for each method.

btnNew_Click

Next we have btnNew_Click which is used to save a new item:

private void btnNew_Click(object sender, EventArgs e)
        {
            var frm = new TodoItemForm();
            frm.ShowDialog(this);

            var cmd =
                new SQLiteCommand("INSERT INTO todo_items (title, description) values(@title, @description)", _db);
            cmd.Parameters.Add(new SQLiteParameter("title", frm.tbTitle.Text));
            cmd.Parameters.Add(new SQLiteParameter("description", frm.tbDescription.Text));
            cmd.ExecuteNonQuery();

            lbTodos.Items.Clear();
            // load all todo items.
            SQLiteCommand mycmd = new SQLiteCommand(_db);
            mycmd.CommandText = "SELECT * FROM todo_items";
            var reader = mycmd.ExecuteReader();
            while (reader.Read())
            {
                lbTodos.Items.Add(new Item { Id = (long)reader["id"], Title = (string)reader["title"] });
            }
        }

It has two responsibilities: Saving an item into the database and refreshing the listbox.
Fortunately, we have already created a method for the listbox in the constructor refactoring. Let’s just add that the listbox should be emptied before adding all items.

lbTodos_MouseDoubleClick

lbTodos_MouseDoubleClick is used to edit an item.

        private void lbTodos_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Item item = (Item)lbTodos.SelectedItem;

            SQLiteCommand mycmd = new SQLiteCommand(_db);
            mycmd.CommandText = "SELECT * FROM todo_items WHERE id=" + item.Id;
            var reader = mycmd.ExecuteReader();
            reader.Read();

            var frm = new TodoItemForm();
            frm.tbDescription.Text = (string)reader["description"];
            frm.tbTitle.Text = (string) reader["title"];
            frm.ShowDialog(this);

            var cmd =
                new SQLiteCommand("UPDATE todo_items set title=@name, description=@description WHERE id = @id", _db);
            cmd.Parameters.Add(new SQLiteParameter("name", frm.tbTitle.Text));
            cmd.Parameters.Add(new SQLiteParameter("description", frm.tbDescription.Text));
            cmd.Parameters.Add(new SQLiteParameter("id", item.Id));
            cmd.ExecuteNonQuery();

            lbTodos.Items.Clear();
            // load all todo items.
            SQLiteCommand cmd3 = new SQLiteCommand(_db);
            cmd3.CommandText = "SELECT * FROM todo_items";
            reader = cmd3.ExecuteReader();
            while (reader.Read())
            {
                lbTodos.Items.Add(new Item { Id = (long)reader["id"], Title = (string)reader["title"] });
            }

        }

Responsibilities:

  1. Load item from database
  2. Populate item form
  3. Save stuff from the item form into the database
  4. Populate list box

Here we’ll refactor the item form to use the Item class, and we’ll therefore make the item class standalone (instead of being a private class inside MainWindow). That should take care of #2.

#4 have already been fixed thanks to the previous method refactorings.

We’ll move the item loading into a separate method.

Done

The first refactoring is now done. The goal of this post was to help you understand what Single responsibility really means, although we are not quite done with the guideline yet. The MainWindow form still have many different responsibilities. But first let’s explore exception handling in the next post.


TodoApp – part 1: From shitcore to hardcore

The easiest way to learn how to improve ones coding is by examples. I’ve therefore created an example application which is really crappy written application. It’s a todo app where you can enter your todos (but not delete them ;)). The idea is to take this basic winform application and turn it into a client/server app utilizing different open source libraries for logging, IoC and web services.

The sourcecode is available at codeplex, each check in will represent a blog post. (Check each diff to see what I’ve refactored each time).

Read the source code and check the next blog entry for the first refactor iteration.