Red Squirrel Reflections
Dave Hoover explores the psychology of software development

Dave Hoover
dave.hoover@gmail.com

Categories
All [Atom]
Craftsmanship [Atom]
Dynamic [Atom]
Intersection [Atom]
Learning [Atom]
Links [Atom]
Polyglot [Atom]
Projects [Atom]
XP [Atom]
Old Blog

Obtivian Blogs

Andy Maleh
Colin Harris
Fred Polgardy
Jim Breen
Kevin Taylor
Todd Webb
Turner King
Tyler Jennings

Archives

March 2009 (1)
January 2009 (1)
December 2008 (1)
October 2008 (3)
September 2008 (1)
June 2008 (4)
April 2008 (3)
March 2008 (1)
February 2008 (1)
August 2007 (1)
July 2007 (1)
June 2007 (1)
May 2007 (4)
April 2007 (3)
March 2007 (5)
February 2007 (6)
January 2007 (6)
December 2006 (10)
November 2006 (5)
October 2006 (8)
September 2006 (8)
August 2006 (5)
July 2006 (12)
June 2006 (7)
May 2006 (5)
April 2006 (5)
March 2006 (4)
February 2006 (2)
January 2006 (5)
December 2005 (5)
November 2005 (3)
October 2005 (3)
September 2005 (6)
August 2005 (4)
July 2005 (7)
June 2005 (14)
May 2005 (6)
April 2005 (8)
March 2005 (9)
February 2005 (11)
January 2005 (16)
Old Archives

 

Sat, 29 Jan 2005

Quotes Manager Project -- Day 11

An ongoing pet project blog...

I'm back to green. I needed a CDataSection rather than an ordinary Element. I broke the tests because a CDataSection wraps the text with <![CDATA[]]>. Here's the code:

    public void newQuote(Quote quote) {
        Node root = document.getDocumentElement();
        Node quoteNode = document.createElement("quote");

        Node textNode = document.createElement("text");
        Node textSection = document.createCDATASection(quote.text);
        textNode.appendChild(textSection);
        quoteNode.appendChild(textNode);

        Node sourceNode = document.createElement("source");
        Attr sourceIsbn = document.createAttribute("isbn");
        sourceIsbn.setValue(quote.source.isbn);
        sourceNode.getAttributes().setNamedItem(sourceIsbn);
        sourceNode.setTextContent(quote.source.title);
        quoteNode.appendChild(sourceNode);

        for (Person author : quote.authors) {
            Attr authorUrl = document.createAttribute("url");
            authorUrl.setValue(author.url);
            Node authorNode = document.createElement("author");
            authorNode.getAttributes().setNamedItem(authorUrl);

            Node authorFirst = document.createElement("first");
            authorFirst.setTextContent(author.firstName);
            authorNode.appendChild(authorFirst);

            Node authorLast = document.createElement("last");
            authorLast.setTextContent(author.lastName);
            authorNode.appendChild(authorLast);

            quoteNode.appendChild(authorNode);
        }

        root.appendChild(quoteNode);
    }

And here's the latest test...
    public void testShouldWriteXmlWhenGivenNewQuoteWithPageNumber() throws Exception {
        String text = "The major problems of our work are not so much <i>technological</i> as <i>sociological</i> in nature.";
        String isbn = "0932633439";
        String title = "Peopleware: Productive Projects and Teams";
        String page = "4";
        String firstName1 = "Tom";
        String lastName1 = "DeMarco";
        String url1 = "http://www.systemsguild.com/GuildSite/TDM/Tom_DeMarco.html";
        String firstName2 = "Timothy";
        String lastName2 = "Lister";
        String url2 = "http://www.cutter.com/consultants/tlbio.html";
        Collection<Person> authors = new ArrayList<Person>(2);
        authors.add(new Person(firstName1, lastName1, url1));
        authors.add(new Person(firstName2, lastName2, url2));
        Quote quote = new Quote(text, new Source(title, page, isbn), authors, null);

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse("stub.xml");

        assertEquals(0, document.getElementsByTagName("quote").getLength());

        Manager manager = new XmlQuoteManager(document);
        manager.newQuote(quote);

        assertEquals(1, document.getElementsByTagName("quote").getLength());

        String textContent = documentToText(document);
        assertTrue(-1 != textContent.indexOf("<text><![CDATA[" + text + "]]></text>"));
//        assertTrue(-1 != textContent.indexOf("<source isbn=\""+ isbn + "\" page=\"" + page + "\">" + title + "</source>"));
//        assertTrue(-1 != textContent.indexOf("<author url=\""+ url1 + "\"><first>" + firstName1 + "</first><last>" + lastName1 + "</last></author>"));
//        assertTrue(-1 != textContent.indexOf("<author url=\""+ url2 + "\"><first>" + firstName2 + "</first><last>" + lastName2 + "</last></author>"));
    }

I'll uncomment those tests and see where I am. Arg, they're failing on the next line. Something to do with the source, it's missing a page. Oh, there's a good reason for that, I never coded it. This is why I write tests first.

So I added the page attribute, but then my other test broke because it doesn't have a page. Time for a handy-dandy if statement. Ahhh, back to green. Here's the if block:

        if (quote.source.page != null && !quote.source.page.trim().equals("")) {
            Attr sourcePage = document.createAttribute("page");
            sourcePage.setValue(quote.source.page);
            sourceNode.getAttributes().setNamedItem(sourcePage);
        }
I need a test with a quoter.
    public void testShouldWriteXmlWhenGivenNewQuoteWithQuoter() throws Exception {
        String text = "To be able to understand when the rules don't apply, you need to completely understand when they do.";
        String isbn = "0201760436";
        String title = "Agile Software Development Ecosystems";
        String page = "31";
        String quoterFirstName = "Bob";
        String quoterLastName = "Charette";
        String quoterUrl = "http://www.cutter.com/consultants/charetter.html";
        Person quoter = new Person(quoterFirstName, quoterLastName, quoterUrl);
        String firstName = "Jim";
        String lastName = "Highsmith";
        String url = "http://www.adaptivesd.com/";
        Collection<Person> authors = new ArrayList<Person>(1);
        authors.add(new Person(firstName, lastName, url));
        Quote quote = new Quote(text, new Source(title, page, isbn), authors, quoter);

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse("stub.xml");

        assertEquals(0, document.getElementsByTagName("quote").getLength());

        Manager manager = new XmlQuoteManager(document);
        manager.newQuote(quote);

        assertEquals(1, document.getElementsByTagName("quote").getLength());

        String textContent = documentToText(document);
        assertTrue(-1 != textContent.indexOf("<text><![CDATA[" + text + "]]></text>"));
        assertTrue(-1 != textContent.indexOf("<source isbn=\""+ isbn + "\" page=\"" + page + "\">" + title + "</source>"));
        assertTrue(-1 != textContent.indexOf("<author url=\""+ url + "\"><first>" + firstName + "</first><last>" + lastName + "</last></author>"));
        assertTrue(-1 != textContent.indexOf("<quoter url=\""+ quoterUrl + "\"><first>" + quoterFirstName + "</first><last>" + quoterLastName + "</last></quoter>"));
    }

This fails where I expected, on the last assert. I'll put in the quoter code on the way home. We just pulled into Chicago...

Back to green. I basically just copied and pasted the body of the author loop and after a couple SHIFT-F6's the variables had the appropriate names.

    public void newQuote(Quote quote) {
        Node root = document.getDocumentElement();
        Node quoteNode = document.createElement("quote");

        Node textNode = document.createElement("text");
        Node textSection = document.createCDATASection(quote.text);
        textNode.appendChild(textSection);
        quoteNode.appendChild(textNode);

        Node sourceNode = document.createElement("source");
        Attr sourceIsbn = document.createAttribute("isbn");
        sourceIsbn.setValue(quote.source.isbn);
        sourceNode.getAttributes().setNamedItem(sourceIsbn);

        if (quote.source.page != null && !quote.source.page.trim().equals("")) {
            Attr sourcePage = document.createAttribute("page");
            sourcePage.setValue(quote.source.page);
            sourceNode.getAttributes().setNamedItem(sourcePage);
        }
        sourceNode.setTextContent(quote.source.title);
        quoteNode.appendChild(sourceNode);

        for (Person author : quote.authors) {
            Attr authorUrl = document.createAttribute("url");
            authorUrl.setValue(author.url);
            Node authorNode = document.createElement("author");
            authorNode.getAttributes().setNamedItem(authorUrl);

            Node authorFirst = document.createElement("first");
            authorFirst.setTextContent(author.firstName);
            authorNode.appendChild(authorFirst);

            Node authorLast = document.createElement("last");
            authorLast.setTextContent(author.lastName);
            authorNode.appendChild(authorLast);

            quoteNode.appendChild(authorNode);
        }

        if (quote.quoter != null) {
            Attr quoterUrl = document.createAttribute("url");
            quoterUrl.setValue(quote.quoter.url);
            Node quoterNode = document.createElement("quoter");
            quoterNode.getAttributes().setNamedItem(quoterUrl);

            Node quoterFirst = document.createElement("first");
            quoterFirst.setTextContent(quote.quoter.firstName);
            quoterNode.appendChild(quoterFirst);

            Node quoterLast = document.createElement("last");
            quoterLast.setTextContent(quote.quoter.lastName);
            quoterNode.appendChild(quoterLast);

            quoteNode.appendChild(quoterNode);
        }

        root.appendChild(quoteNode);
    }
There's nothing that drives me crazier than developers who copy and paste code without refactoring it out. So it's time to refactor this monsterous method. After a series of CTRL-ALT-M's and CTRL-ALT-N's, otherwise known as extract method and inline variable, the method looks a lot nicer.
    public void newQuote(Quote quote) {
        Node quoteNode = document.createElement("quote");

        quoteNode.appendChild( createTextNode(quote) );
        quoteNode.appendChild( createSourceNode(quote) );

        for (Person author : quote.authors)
            quoteNode.appendChild( createAuthorNode(author) );

        if (quote.quoter != null)
            quoteNode.appendChild( createQuoterNode(quote) );

        document.getDocumentElement().appendChild( quoteNode );
    }
The tests are still green. There is duplication between the createQuoterNode and createAuthorNode. Let's get rid of that ASAP. I'll start by seeing what happens if I use the createAuthorNode rather than the createQuoterNode.
    public void newQuote(Quote quote) {
        Node quoteNode = document.createElement("quote");

        quoteNode.appendChild( createTextNode(quote) );
        quoteNode.appendChild( createSourceNode(quote) );

        for (Person author : quote.authors)
            quoteNode.appendChild( createAuthorNode(author) );

        if (quote.quoter != null)
            quoteNode.appendChild( createAuthorNode(quote.quoter) );

        document.getDocumentElement().appendChild( quoteNode );
    }
That breaks the quoter test because now the quoter is showing up as an author. I introduce parameter (CTRL-ALT-P) on tag name, make sure the quoter code is passing in "quoter" and rename method (SHIFT-F6). Voila! Back to green, and IDEA tells me I have dead code (createQuoterNode) I can delete. So I do (I really love that feeling).

Here's the current state of the method:

    public void newQuote(Quote quote) {
        Node quoteNode = document.createElement("quote");

        quoteNode.appendChild( createTextNode(quote) );
        quoteNode.appendChild( createSourceNode(quote) );

        for (Person author : quote.authors)
            quoteNode.appendChild( createPersonNode(author, "author") );

        if (quote.quoter != null)
            quoteNode.appendChild( createPersonNode(quote.quoter, "quoter") );

        document.getDocumentElement().appendChild( quoteNode );
    }
I should find some other permutations to test before moving on. Like authors without URLs or sources without ISBNs. But I won't bore you with them now.

[/projects/quotes] permanent link


powered by blosxom