Mon, 07 Feb 2005

As I explore my solution,
I see that subsequent calls to add a new quote actually append
the entire document to the previous document.
That's obviously not what I want.

Ah, solved the problem I found yesterday.
The hasText method in PersonPanel was
messed up. Just an annoying firstName.getText() != ""
vs. !"".equals(firstName.getText()) issue.
I didn't think I would need to write a test for something that trivial.
Stupid mistake.

Now for the second problem...
Before the XML output is generated from the Document,
I need to somehow empty the file.
Not sure how to do that off the top of my head with only an OutputStream.
Exploring...grrr, can't do it.
I really don't want XmlQuoteListener to have to use files becauses
that makes the testing harder.

I'll run the app and to see if that fixes my problem.
I have an uneasy feeling about creating a new OutputStream every time...
But hey, it worked like a charm!
Time for a check in.

So let's look back at the initial goals and see where we are...

I want to change the quotes page to be sorted by quoter author.
DONE.
There should be a list of all the quoters at the top.
NOT DONE.
Their names should link down to their quotes on the page below.
NOT DONE.

I want to use a simple Swing application to manage the quotes.
FIRST RELEASE: ADD QUOTE

The Swing app will store the quotes in XML.
DONE.
The app will have the ability to transform this XML into HTML via XSLT.
NOT DONE.

Cool, this is good.
If you don't mind, I'm going knock out the rest of this stuff
without writing it up. I need to be moving onto other commute-time activities ASAP.
Like reading and finding more quotes...and using my new software.

If anyone is interested, I'll post the final source code when I'm finished.

Wed, 02 Feb 2005

I am almost finished with the task of adding a quote to an XML file.
I have the GUI. I have the class that updates the XML Document.
Now what I need is a class that loads the file into a Document
and writes the updated Document back to the file.

But how does this class interact with XmlQuoteManager?
It should probably be listening for calls to XmlQuoteManager.newQuote
in order to know when to write to the file.
Maybe I'll just start with that...

This leads me to (allow IDEA to) create the QuoteListener interface and
add a new method to the (recently renamed) QuoteManager interface and
XmlQuoteManager. I run the test and jMock tells me that my
QuoteListener interface doesn't have an update method.
I'm feeling confident this morning so I'll take a big step and get to green right away...

I entered a quote and it updated the XML!
But there were a few issues...it added an extra (empty) author and an empty quoter.
Rather than fix it now, with the new code in the main method,
I'll extract it and test. Or more accurately, test then extract.

Starting with an empty test, I pause for a moment to consider what this listener
will need in order to do its work...
Oh, that's easy, just check for which variables had to be declared final
in the main method...the file name and the Document.
But I don't want to use a file name, I'd rather stick with streams.
So I'll do it like this...

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:

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.

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.

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).

Very straightforward. I'm feeling good about this right now.
I'm going to add more tests to handle some different variations of authors, quoters, and sources.
I won't bore you with those unless something interesting comes up.

Well, that didn't take long. Something interesting came up.
Here's the new test...

I expected this to fail because the code doesn't handle pages.
But it failed for a different reason.
The HTML in the quote got escaped and failed at the first assertTrue!
I'm going to comment out all the other asserts while I resolve this issue...

Thu, 27 Jan 2005

I'm trying to hook my new, more tested/able AddButtonActionListener into the
QuoteManagerPanel and having some difficulties.
Everything compiles but when I inject this anonymous Manager into
QuoteManagerPanel, I get nothing after filling out the quote form and
clicking 'Add'...

I get something when I print out quote.source.title,
but the text property is blank.
Hmmm...got it!
The problem is that when I create my AddButtonActionListener, I pass in
the value of the quote text then and there. Like this:

The test simply checks to make sure the document has gone from zero to one quote.
I'll start by letting IDEA create the XmlQuoteManager.
The test fails.
To get the test to pass I need to add an element of type "quote".
Shoot, I'm not sure how to do that.
In my spike I simply updated an attribute of an existing Node.
Here's where I'm stuck...

Wed, 26 Jan 2005

I could pass the test by changing the hard-coded values of the Quote
I'm passing into the Manager (and provide an equals method),
but I'd rather get to the point and inject the dependencies that
AddButtonActionListener needs to do its work.

My first instinct is to extract interfaces from PersonPanel and
SourcePanel in order to mock them more easily,
but they would just be a bunch of getters. Bletch.
But since I can't think of anything better right now, that's just what I'll do.

Ahh, back to green.
That was painful, and I'm doubting if all of the extra steps I just took were worth it.
I had IDEA generate equals (and hashCode) for all of my
model classes so that I could verify that the expected Quote matched
the Quote created by AddButtonActionListener.
I also had to create two interfaces: PersonComponent and SourceComponent.

Now that I've got a green bar, I think I'd like to do some refactoring to make this code a bit easier on the eyes.
Why not give the model objects additional constructors to take in their corresponding component objects?
I was reluctant to do this before because I didn't want to couple the model to GUI code,
but since they're just simple interfaces, I'm OK with it now...

I have reduced the number of objects the ActionListener depends on
by creating the AuthorPanel.
Looks like I could do something similar with the quoter fields.
Here we go again...how'd I start last time? Oh yeah, extract method...

This looks very familiar, which is good, because it means I can probably share code with
the AuthorPanel. But not yet...first the inner class...

QuoterPanel is almost an exact replica of the AuthorPanel.
Let's see if I can extract the duplication...
Yep, no problem. I created a concrete PersonPanel which was an exact copy
of AuthorPanel except that the constructor takes the entire String
for the label, rather than the authorNumber.
That way when I need a PersonPanel to represent a quoter, I just pass in "Quoter".
Pretty simple.

Now my anonymous ActionListener depends on six objects.
I can get that down to four if I group the source fields into their own panel.
I think I can do this quickly...I've gone through the steps twice already.
I'll take some bigger steps and not bore you with the details...

I have a SourcePanel.
There is a lot of GridBagLayout duplication between the three different
JPanel derivatives, but I'm not going to worry about that right now.
It's time to test...

This test doesn't even come close to compiling, so I'll let IDEA do the work for me
with a series of wonderous F2/ALT-ENTER steps.
This leaves me with an empty Manager interface and a stubbed out
AddButtonActionListener. I'll run the test.

Dave the customer is feeling a bit better now that I can enter the authors I need,
but Dave the developer is not happy...still no tests to speak of.
Let's take a quick look around and find some easy wins...
How about that anonymous ActionListener?
I'm going to try to test it...

I've brought up my test template in IDEA and I have a blank test method...

So how do I test this thing?
Currently it is coupled to all of the JTextComponents in QuoteManagerPanel.
The code that I'm most nervous about is the for loop with the if condition.
I'm going to need to promote this ActionListener to a concrete class,
but I don't want to pass in ten objects to the constructor...or call ten different setters.
How about I pull the related fields into their own JPanels?
The thought occurred to me when I had to create three separate author arrays.

I'm pulling into the station.
I'll check in and extract the fields into JPanels on the way home...

I'll start with the code that handles authors' JTextComponents.
Here's it is in its current glory (in bold):

Great, still looking good, but those three author arrays are bugging me.
Let's get rid of those...

I could show you all the things I did to remove those arrays, but this post is getting
way too long...and I'm sure it's very boring.
It only took a few minutes.
I simply replaced the three arrays with an AuthorPanel array.

Hopefully we're a bit closer to testing.
I'll have to wait until tomorrow, though.
My stop is coming up...here's what the AuthorPanel class looks like...

Fri, 21 Jan 2005

And I just did a bit of refactoring to remove most of the duplication.
Checking in...

This is a passive application for the moment.
I'd like to provide it with an object that it can store the quote data in
so that when I click the "Add" button, this object is populated with data.
Perhaps this will be called a Quote?
I'll just have it be an immutable value object for now...

This is kinda boring, which probably means I'm doing something wrong...or I am about to.
I wish I had a pair programmer to reassure (or warn) me.

So now that I have my immutable value objects, I see that I'm going to be creating these
objects rather than populating previously existing ones.
Not sure if that's bad or good. I'm really tired right now.

OK, I just realized one of the things I've overlooked.
I've only given the user the ability to enter one author per quote!
Yikes, I'll have to deal with that later. I want to keep making progress...

OK, I guess this is progress.
I've extracted the JButton and all of the JTextComponents into private final fields.
I extracted the layout code to a private method.
Finally, I added a anonymous ActionListener.
Here's what it looks like (sans layout code)...

I have created a Quote!
How sad that I don't know what to do with it.
And damn that's some tedious code, just mapping GUI components to structs.
As a developer, I'm not happy that there are no tests.
And as a customer, I'm not happy that I can only input one author per quote.
Before I figure out what to do with our freshly baked Quote,
I need to figure out an acceptable solution to the N authors problem.

Checking in...

To solve the N authors problem, I will peruse the quotes file,
find the quote with the greatest number of authors, and provide that many author fields.
Let's see...it appears that I quote at least two books that have three authors.
I quote the Gang of Four,
but refer to the authors in bulk, not individually.
I'll update the GUI code to handle up to three authors...

Tue, 18 Jan 2005

Looks like the code snippet I took from the Java XSL tutorial
uses DOM parsing (as opposed to SAX parsing).
This doesn't mean much to me, other than pointing me toward the correct documentation.
OK, the documentation sucks.
I'm going to experiment...

Made some progress.
Experimenting with a nice Java IDE like IDEA turned out to be more useful than
the documentation.
Here's what I have so far. This tells me that I have 6 quotes in my data file...

Still trying to unwind this XML.
I'm having flashbacks to using Perl's XML::Parser.
OK, looks like I've got a handle on it.
Here's what I have now...it prints out all of the child tags of each quote,
and accesses the isbn attribute of the source tag:

text:We in the software industry are working with a more or less invisible product,
yet this very invisibility only heightens our need for feedback.
quoter:GeraldWeinberg
source:isbn="0932633447":Project Retrospectives
author:NormKerth
-----------------
text:By building tests before you implement the code,
you get to try out the interface before you commit to it.
source:isbn="020161622X":The Pragmatic Programmer
author:DaveThomas
author:AndyHunt
-----------------
text:For everyone who exalts himself will be humbled,
and he who humbles himself will be exalted.
source:Luke 18:14b
-----------------
text:Programming is the Great Game.
It consumes you, body and soul.
When you're caught up in it, nothing else matters.
source:How Software Companies Die
author:Orson ScottCard
-----------------
text:It's never the size of the step that a person takes that counts,
but its direction.
source:isbn="0393700984":Narrative Means to Therapeutic Ends
author:MichaelWhite
author:DavidEpston
-----------------
text:Having a plan isn't everything, but planning is.
source:isbn="0201708426":Extreme Programming Installed
author:RonJeffries
author:AnnAnderson
author:ChetHendrickson
-----------------

I'm in the station now. Looks like updating XML files will wait until the ride home.

OK, let's see how to update an XML document.
I want to change Jerry's URL to http://ayeconference.com/...

But that doesn't change the actual file, just the in-memory XML structure.
How do I write the Document to a file?
Judging from the public methods I see in IDEA,
it doesn't look like a Document knows how to write itself,
or even provide an OutputStream.
Back to the tutorial...

Oh, it looks like I already had it.
Here's the code. It should look familiar:

This is just like the code I used to generate HTML,
except I don't specify an XSL file in my call to
TransformerFactory.newInstance().newTransformer().
This code updates the file lickety-split. Cool.

Time for a check in.

As the customer, I'd like to get an update on the progress of the project.
As the developer, I will give my appraisal of how far I've come:

I want to change the quotes page to be sorted by quoter author.
DONE.
There should be a list of all the quoters at the top.
NOT DONE.
Their names should link down to their quotes on the page below.
NOT DONE.

I want to use a simple Swing application to manage the quotes.
NOT DONE.

The Swing app will store the quotes in XML.
NOT DONE.
The app will have the ability to transform this XML into HTML via XSLT.
NOT DONE.

Dang, that's depressing.
As the customer, I'm disappointed.
As the developer looking at the plan, I am nervous about how little I actually got done.
But my confidence about how to accomplish these tasks is much, much higher.

So what is my next task?
It's time to view the quote data in a Swing app.
Finally! Some actual coding! No more spiking!

Sat, 15 Jan 2005

So now I know how to read XML data and, using Java 5.0, transform it into HTML.
I also have an XSL style sheet that duplicates the look and feel of my current quotes page.
Again I find myself wondering what to do next.
Again I will put on my customer hat and consider what I want.
Let's look at the original plan:

I want to change the quotes page to be sorted by quoter.
There should be a list of all the quoters at the top.
Their names should link down to their quotes on the page below.

I want to use a simple Swing application to manage the quotes.

The Swing app will store the quotes in XML.
The app will have the ability to transform this XML into HTML via XSLT.

I could add sorting to my style sheet.
Or I could do another spike that reads in XML data and writes updates.
Updating XML sounds more intersting, but as a customer, I'd like to see the sorting I've asked for.
So let's sort...

OK, sorting in XSL is easy.
I just had to add two lines beneath my <xsl:for-each>...

But that doesn't do what I want.
First of all, it sorts by first name.
Secondly, it puts all of the quoter-less quotes first, and then adds the quote by Weinberg last.
As my fellow ThoughtWorker Dave Wood would say: "Boooo."

Actually, this is good.
It looks like I'm going to need to change my XML data structure in order to allow for the sorting I need.
I'm glad I chose to do this task before the XML update spike, since the data format would have changed.
Pulling into the station...

OK, I've changed the XML data format to break quoter and author names down into first and last names like:

My next task is to spike reading and updating the XML file from Java.
I wonder if I could use some of my XSL transformation code?
It looks like the first half of my previous spike could come in handy...

Here is the data I'm using. It has most of the quote variations that I can remember:

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="sample.xsl"?>
<quotes>
<quote>
<text>
We in the software industry are working with a more or less invisible product,
yet this very invisibility only heightens our need for feedback.
</text>
<quoter url="http://www.geraldmweinberg.com/">Gerald Weinberg</quoter>
<source isbn="0932633447" page="xiii">Project Retrospectives</source>
<author url="http://www.retrospectives.com/">Norm Kerth</author>
</quote>
<quote>
<text>
By building tests <i>before</i> you implement the code,
you get to try out the interface before you commit to it.
</text>
<source isbn="020161622X" page="192">The Pragmatic Programmer</source>
<author url="http://www.pragmaticprogrammer.com/">Dave Thomas</author>
<author url="http://www.pragmaticprogrammer.com/">Andy Hunt</author>
</quote>
<quote>
<text>
For everyone who exalts himself will be humbled,
and he who humbles himself will be exalted.
</text>
<source>Luke 18:14b</source>
</quote>
<quote>
<text>
Programming is the Great Game.
It consumes you, body and soul.
When you're caught up in it, nothing else matters.
</text>
<source url="http://www.apocalypse.org/pub/u/kjc/cool/Card.on.Software.html">How Software Companies Die</source>
<author url="http://www.hatrack.com/osc/about.shtml">Orson Scott Card</author>
</quote>
<quote>
<text>
It's never the size of the step that a person takes that counts,
but its direction.
</text>
<source isbn="0393700984">Narrative Means to Therapeutic Ends</source>
<author>Michael White</author>
<author>David Epston</author>
</quote>
<quote>
<text>
Having a plan isn't everything, but planning is.
</text>
<source isbn="0201708426">Extreme Programming Installed</source>
<author url="http://www.xprogramming.com/">Ron Jeffries</author>
<author url="http://c2.com/cgi/wiki?AnnAnderson">Ann Anderson</author>
<author url="http://c2.com/cgi/wiki?ChetHendrickson">Chet Hendrickson</author>
</quote>
</quotes>

Time for a check in.
OK, so what's next? Let's take a look at the original plan...

I want to change the quotes page to be sorted by quoter.
There should be a list of all the quoters at the top.
Their names should link down to their quotes on the page below.

I want to use a simple Swing application to manage the quotes.

The Swing app will store the quotes in XML.
The app will have the ability to transform this XML into HTML via XSLT.

I could start setting up the Swing app, which would be a nice change of pace.
Or I could learn how to do XSL tranformations in Java.
Or I could add sorting and a quoter list to the style sheet.
Hmm, if I were a customer, which would I think was more important?
For now, I think I'm satisfied with seeing what I already have on the quotes page.
But I'm uncomfortable with having Firefox do the transformations.
I want to see the HTML generated by Java.
Looks like we're pulling into the station...

I love to read.
As I read, I am constantly underlining, writing in the margin and transcribing quotes onto scratch paper.
When I finish a book, I read through the quotes I've collected.
I choose my favorites and transcribe them into my quotes page.
I've been doing this since I started learning how to develop software.
Actually, I started the habit before I was a programmer, but the web page thing didn't start until after I learned HTML.

My quotes page has grown pretty hefty, and I would like to develop some software to help me manage it.

Ron's "adventures" were learning a new language (C#) while developing an XML editor.
I'm already learning a new language right now (C++), so I think I'll stick with one that I'm familiar with (Java).
But I will try out a technology (XSL) that's new to me, though it's not new to many.

Here's the plan:

I want to change the quotes page to be sorted by quoter.
There should be a list of all the quoters at the top.
Their names should link down to their quotes on the page below.

I want to use a simple Swing application to manage the quotes.

The Swing app will store the quotes in XML.
The app will have the ability to transform this XML into HTML via XSLT.

The only time I will work on this project is on the train, going to and from Chicago on my way to work.
It's about a 40 minute ride each way.

So where to start, where to start...
What aspect of the project do I know the least about?
XSL. I'll start there. I'll start with creating a sample XML file.
No, wait. Source control first.
I just imported what I've written so far into Subversion.
OK, now I'm ready to create my XML sample.

<quotes>
<quote>
<text>
We in the software industry are working with a more or less invisible product,
yet this very invisibility only heightens our need for feedback.
</text>
<quoter url="http://www.geraldmweinberg.com/">Gerald Weinberg</quoter>
<source isbn="0932633447" page="xiii">Project Retrospectives</source>
<author url="http://www.retrospectives.com/">Norm Kerth</author>
</quote>
</quotes>

OK, checked that in.

What's next? XSL-ify the XML into something resembling the way I want my quotes page to look.
I printed out an XSL tutorial from W3Schools,
which should be helpful.
Looks like the first thing I need to do is define an XSL style sheet...