Slow Start - Testaments and Books

Here is my answer to Keith's Bible App challenge. I know the deadline has already passed but I want to do it the TDD way, so here it is.

Again, the requirements.

  1. The user should be able to search for books based on a selected Testament (Old and New).
  2. The user should be able to see the contents of each Book
  3. The user should be able to search the contents of the Bible based on different search criterias like "Luke", "Genesis 1", "John 3:16", "love", "Abraham" and the application should be able to return the matching results.
  4. The user should be able to jump from one book to another.
  5. The user should be able to jump from one chapter to another.

So, five requirements, one rule: you have to use the database provided and you are not allowed to use any 3rd party libraries.

How do I approach this?

There's the direct form of attack. I can paint the screen, then generate the datasets and datatables from the database (with permissions from the wizards of vs.net, of course), and then use my lucky One Ring of Power to bind them all together. Nothing wrong with that really. A simple app like this can be written that way.

If this is how you would do it and you are not interested in another way, then press Ctrl-F4 or move on to the next item in your blog/feed/news reader. I wouldn't discuss that here.

What I'm presenting here is the alternative way of attacking this project - one where every piece of non-trivial code is driven and covered by tests - either unit test or integration tests. I'm sure someone would argue that for a simple application such as this, the technique that I'll be using is just plain overkill. I would agree with you. But that's not the point of this article. This is about demonstrating how to write tests for your code.

OK? Good. Let's start.

I've already decided on just copying the look of CryptoKnight's application - treeview on the left hand side, book contents on the right hand side and then a search box on top. I already know what the application does - allow the user to view and navigate through the bible, perform searches, etc. I can think of a couple of ways of implementing this.

  • Option 1 - on launch, the application loads all the data from the mdb file and into memory. This is not unlike how CryptoKnight did it - except that I won't be using datasets but actual objects. The advantage here is that I'll be working with objects for the majority of the application. I can represent the book concepts clearly and without translation - testaments have books, books have chapters and chapters have verses. I can just navigate through the graphs of objects to get from one place to another. Drawbacks: the app should load a little slower because it is loading the data from the database during launch. It should also have a higher memory footprint. I also need to write my own searching algorithm. That shouldn't be that hard though. I should be able to use the String methods to perform the searching and the I'll just wire up the objects themselves to perform the searching for me. It'll should also present a few interesting concepts. For example, I can ask each Book to search their own Chapters and all those can be done on their own separate threads! Not sure if that is needed here, but it's a possibility.

  • Option 2 - only load the root nodes (the testaments) on launch and then load the rest on demand. This should give me a faster launch time. After that, I have two choices - either I only retain the viewable contents in memory, or lazy load the contents as they are being requested. Either one is not a simple as working with the whole set of objects or data in memory though, so that's one of the disadvantages of this approach.

CryptoKnight's version is written using DataSets and all the data is loaded into during launch. So it has already been proven that whole bible can be loaded into memory. Searching is also done in memory - using the dataviews. That is essentially the same as the first option.

Cruizer took the second route.

I think for now I'll do the first scenario. During launch, I'll be loading all the tables and into an object graph rooted at the Testament level. The testaments, books and chapter are in the treeview. Contents will be on the contents pane on the right hand side. Searches are done in-memory.

Here are the initial list of tests based on the requirements.

  • a testament can hold many books
  • a book can hold many chapters
  • a chapter can hold many verses
  • a verse is searchable
  • a chapter is searchable
  • a book is searchable
  • a testament is searchable
  • load object graph from database

The last item is a 'technical requirement'. We can delay the implementation for that as long as we can and we will still have a running application. We can just create the testaments, books, chapters, verses in code. In fact, that is not even interesting - I have written a lot of DALs in my lifetime and that piece is just another DAL. I'd rather start with the real interesting parts of the application -- searching and displaying the book.

The first test - let's check if the tools are properly hooked up.

    using NUnit.Framework;
    
    namespace BibleApp.UnitTests
    {
        [TestFixture]
        public class CoreTests
        {
            [Test]
            public void TestShouldFail()
            {
                Assert.IsTrue(false);
            }
    
            [Test]
            public void TestShouldPass()
            {
                Assert.IsTrue(true);
            }
        }
    }

I run the test. The first test failed and the second test passed. That means the tools are configured properly. I can now write my first real test.

I'll start with the test "a testament can hold many books". I think this can be easily done in one shot but I'll go slow for now. I'll start with a fresh testament.

    using NUnit.Framework;
    
    namespace BibleApp.UnitTests
    {
        [TestFixture]
        public class CoreTests
        {
            [Test]
            public void NewTestamentHasNoBooks()
            {
                Testament t = new Testament("Old Testament");
                Assert.AreEqual(0, t.BookCount);
            }
        }
    }

It doesn't compile because Testament doesn't exist. I'll let Resharper generate the class and properties using a flurry of F12 (Goto next error) and Alt-Enter (QuickFix).

    internal class Testament
    {
        public Testament(string name)
        {
            throw new NotImplementedException();
        }

        public int BookCount
        {
            get { throw new NotImplementedException(); }
        }
    }

Now it compiles but it when I run the test - it fails. Not surprising since I'm throwing NotImplementedExceptions. I'll fix that

    internal class Testament
    {
        public Testament(string name)
        {
        }

        public int BookCount
        {
            get { return 0; }
        }
    }

Now the test passes. But it doesn't do anything - it just returns a fake value. Let's ignore that bit for now and add another test:

    [Test]
    public void TestamentCanHoldOneBook()
    {
        Testament t = new Testament("Old Testament");
        t.AddBook(new Book("Genesis"));
        Assert.AreEqual(1, t.BookCount);
    }

Then create the new class and method.

    internal class Book
    {
        public Book(string name)
        {
        }
    }

    internal class Testament
    {
        public Testament(string name)
        {
        }

        public int BookCount
        {
            get { return 0; }
        }

        public void AddBook(Book book)
        {
        }
    }

It compiles but the test fails. I can fake it again - or not. I will have to implement this properly sooner or later, so why not do it now. I'll use a generic list to hold the book and then simply return the list count as the book count.

    internal class Testament
    {
        private List<Book> _books;
        public Testament(string name)
        {
            _books = new List<Book>();
        }

        public int BookCount
        {
            get { return _books.Count; }
        }

        public void AddBook(Book book)
        {
            _books.Add(book);
        }
    }

There you have it - a unidirectional association of Testaments to Books. I ran both tests and the both pass. I think the test "a testament can hold many books" will now work. Let's see.

    [Test]
    public void TestamentCanHoldManyBooks()
    {
        Testament t = new Testament("Old Testament");
        t.AddBook(new Book("One"));
        t.AddBook(new Book("Two"));
        t.AddBook(new Book("Three"));
        Assert.AreEqual(3, t.BookCount);
    }

And it does - all three tests pass.

There you go - a Testament that can hold many books. Let's scratch off one test.

  • a testament can hold many books
  • a book can hold many chapters
  • a chapter can hold many verses
  • a verse is searchable
  • a chapter is searchable
  • a book is searchable
  • a testament is searchable
  • load object graph from database

You might have notice that the Book and Testament classes are both internal. That is because resharper did not generate separate files for them. I transferred them to their own files, made them public, re-ran the tests, they all pass, and I'm done for now.

Next up, I'm going to show testament objects into the UI and give you a taste on how to write unit tests against the user interface.

Posted by jop | 3 comment(s)
Filed under: ,

Markdown Viewer

I'm not really fond of browser based text editors - especially the one used in here in devpinoy. I still write my posts using my favorite editor - gvim, and then paste them over to the blog software.

That is sufficient if you are only writing plain text all the time. What if you wanted to have code in your post and you want it to have syntax highlighting?

The only browser-based editor that I can tolerate is the one in StackOverflow and it uses Markdown.

Markdown is a text-to-HTML conversion tool for web writers. Markdown allows you to write using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid XHTML (or HTML).

Markdown isn't really something new. If you open up a on old text document that you have, chances are, it's already using markdown. :-) What's cool with StackOverflow's editor is that has an markdown autopreview and you can mark a block as code and it will apply syntax highlighting magic using Google's prettify script.

So, what's should a programmer do? I can't just leave my favorite editor and then type all my posts in StackOverflow just so I could use the generated HTML? Nope - what I wanted is to still use gvim for editing (it even has a markdown mode) and then have another app that watches the file I'm editing and then transforms it into HTML everytime I save my changes.

That's what I have here. I'm typing the content using gvim...

Gvim Markdown

...and then I get to see the preview of what I am typing on my Markdown Preview application.

Markdown Preview

Then, all I need to do now is click on the Copy button and I paste the HTML over to the blog editor. The only missing piece is devpinoy - it does not yet support prettify! Keith!


This wouldn't be possible without Milan Negovan's Markdown.NET and Google's prettify. You can download a copy of the source code here if you find this useful.

Posted by jop | 3 comment(s)
Filed under:

Not a PC

John Hodgman: A brief digression on matters of lost time.

Posted by jop | with no comments

Google Tech Talks -- Unit Testing

 

A 32-min intro on unit testing. Watch it. Four stars.

Posted by jop | with no comments
Filed under: , ,

I told you so.

 I can't stop but smile at what I've written in this forum thread.

A decade ago, I am constantly having this similar debate with my managers, project leader, team leader, quality engineers, etc. about the merits of unit testing. As I was still inexperienced then, I am not really in favor of unit testing because (1) I'm the one doing the task, (2) I have to spend a lot of time doing it - that takes away from 'coding' time, and (3) I can't see the benefit of doing it because we already have a dedicated team of system testers that will catch the defects anyways. I get annoyed because the people on the other end of the debate aren't really doing any of the coding so they definitely don't understand what they are saying.

Now, a decade after, it feels like I'm channelling my managers/project/team leaders. I've gained enough knowledge to know the benefits of unit testing, had enough practice to know how to do it properly so I don't really spend a lot of additional time writing tests and I don't mind doing the task because it still is coding. I'm now on the other side of the debate - pro-unit-testing, pro-TDD even, and I'm still on the trenches, writing code.

Posted by jop | 6 comment(s)
Filed under: ,

How to use Patterns

Erich Gamma said:

Do not start immediately throwing patterns into a design, but use them as you go and understand more of the problem. Because of this I really like to use patterns after the fact, refactoring to patterns. One comment I saw in a news group just after patterns started to become more popular was someone claiming that in a particular program they tried to use all 23 GoF patterns. They said they had failed, because they were only able to use 20. They hoped the client would call them again to come back again so maybe they could squeeze in the other 3.


Trying to use all the patterns is a bad thing, because you will end up with synthetic designs—speculative designs that have flexibility that no one needs. These days software is too complex. We can't afford to speculate what else it should do. We need to really focus on what it needs. That's why I like refactoring to patterns. People should learn that when they have a particular kind of problem or code smell, as people call it these days, they can go to their patterns toolbox to find a solution.

Posted by jop | 2 comment(s)
Filed under: ,

Estimation

Today, I attended a seminar about Function Point Analysis.


To me, this seems to be a very magical way of estimating a piece of functionality. It is so different from that way I used to come up with my estimates that, though I haven't tried it yet, I can't help but think of reasons why it won't work.


Such type of thinking is not beneficial if you are trying to learn something. So, I'll give FPA some chance. In the end, I might end up not liking it after all, but at least I would know why.

Posted by jop | 7 comment(s)
Filed under:

Domain Experience

How come certifications are based on the technical skills of a programmer rather than business expertise?

If a manager of a company needs a C# programmer for their accounting system, isn't it more logical to look for a developer that has a good grasp of accounting which also happens to know how to program in the target language?

Unless your business is teaching technology, why would a company look for those certified in a certain brand of technology?

Posted by jop | 15 comment(s)
Filed under:

VS.NET: Reference EXE assemblies

Nice! Visual Studio 2005 now allows Class Library projects (DLL) to reference Applications (EXE).

On Visual Studio 2003, EXE projects are not listed on the Add Reference dialog. The .NET framework does not put any restrictions on what you can reference. I think the IDE programmers thought they're helping us (or me) by only showing the DLLs there.

It's a problem because I used to work on some applications that are not big enough to warrant separating the UI and the core logic. I would only have a single EXE assembly but I am forced to create a separate assembly for classes that needs to be tested because my test projects can not reference the EXE file.

I am currently working on a small utility application so I tried it just now and it worked! Very nice...

Posted by jop | 1 comment(s)
Filed under:

Now that's what I call a desktop!

Think of the possibilities:

  1. Magic the Gathering
  2. Internet mahjong; with realistic tile shuffling -- none of that randomizer stuff
  3. Solitaire, the way it should be played
  4. CRC cards!
  5. UML
  6. Billiards
  7. Table Hockey
  8. Piano
  9. Drums (pressure sensitive?)
  10. Massage tutorial !
  11. DJ mixing table
  12. Computer sculptures
  13. StarCraft II
  14. And finally, tables that turns blue all of a sudden...

http://www.microsoft.com/surface/ 


Posted by jop | 3 comment(s)
Filed under:

Hex

Open a file on Binary Editor using Visual Studio's Command Window

> File.OpenFile myfile.dat /editor:"Binary Editor"

 

Posted by jop | with no comments
Filed under:

Composed Method Pattern

Msg #129624 on the extremeprogramming Yahoo! Group

Some people swear that they would rather see all the code in line,
rather than separated out into small methods. I think that the
in-line people should be prevented from breeding.
-- Ron Jeffries regarding the Compose Method pattern.

Haha!

Posted by jop | 1 comment(s)
Filed under:

Muscle Memory

Eight years ago, a friend of mine introduced me to the world of Unix (you know who you are -- thank you). After mastering the finger ballet that is emacs, I then discovered the wonders of modal text editing in VI. Those are the first *real* programmer editors that I've used.

The power of Emacs lies in Lisp. It is a very programmable editor. It is so powerful, there actually came a time when Emacs is the application that I use for majority of my tasks. It has a mail reader, news reader, file manager, web browser, - it even has Tetris!

The power of VI lies on the conciseness of its commands and its integration with command line utilities. Unix provides lots of little utilities for slicing and dicing text. On a conceptual level, these utilities are very much like SQL for text files - you can query and join files (cat), filter lines (grep) and do all sorts of things with text.  In this conceptual level, VI is like Query Analyzer for text files.

These editors both have a steep learning curve. It took me a few hours just to get used to the environment and learning the basic commands.  That sounds silly - editors should be simple - open a file, type in text, save, and close. These editors are not like that. These editors are arrogant. If you make a mistake, they will just pout and let you figure it out. However, once you've learned the commands/shortcuts, muscle memory kicks-in and you'll not even notice that you're using a different editor at all. Then you'll have withdrawal symptoms every time you use another editor. :w

As a programmer, you owe it to yourself to learn at least one of these very powerful utilities. Even in this PostIntelliJ era, these editors are still very relevant. Of course I'll still use built-in editors of VS.NET/Eclipse on my day to day work (I guess once you're addicted to Intellisense, you can never go back), but there will always be instances where the built-in editor just doesn't cut it. CSV, XML, HTML, CSS files, SQL scripts are all those files that doesn't have the same level of tooling present on mainstream programming languages. Whenever the need arise, you can pull out your VI and start slicing!

:wq

Posted by jop | with no comments
Filed under:

Logged

Notepad has this cool feature that I never seen anyone ever use. When you create a file and place the text .LOG on the first line, Notepad will take that as log file. Everytime you open that file in Notepad, a new line will be appended containing the timestamp and the cursor will be placed under that new line.

I've been using this feature for years now. This is my sole reason for still using notepad. I maintain a LOG.TXT on my home directory, and whenever I think of anything that needs to be remembered, I just [Win-R] LOG [ENTER], type in the idea [Ctrl-S] and [Alt-F4] - my idea is now safely tucked with a free timestamp.

I still have the log files from way back 1998. Most of my entries would actually make good blog articles. Maybe I can post some of them here.

Btw, I first saw this feature on Windows 98. When I tried it out on Windows XP and 2003, it is still there. I wonder if this still works in Vista?

Posted by jop | 3 comment(s)
Filed under: ,

Tears, Flying and Nightmares

I almost got teary eyed after watching the official StarCraft 2 cinematics and gameplay videos. The game brought back a lot of memories - flying command centres, shouts of frustration, and people getting nightmares because my zerglings have reached their bases... again.

Now, if I can only find out where I placed my build order cheat sheet...

Posted by jop | 5 comment(s)
Filed under:
More Posts Next page »