This page looks the same as it did last week, but it’s being generated using Java. Whee. (And I hope it will look a little different by the end of the weekend.)
I didn’t spend too much time programming: my time was mostly spent managing and understanding infrastructure. There’s now an acceptance test which runs all the unit tests, a program to run all acceptance tests. I had a little bit of confusion with the multiple programs named ‘java’ and ‘javac’ on my system, but now the right one is being called.
My most pressing current infrastructure issue is that I really don’t understand how javac works with dependencies. If Foo.java uses a class Bar and if Bar.java uses a class Baz, then it looks like, if I modify Bar.java and tell javac to recompile Foo.java, it will also recompile Bar.java, but if I modify Baz.java, then compiling Foo.java doesn’t cause Baz.java to be recompiled. Or maybe I need to go one level deeper, or maybe I’m misunderstanding things completely. (Hmm: maybe javac knows that touching Baz can’t change Bar’s interface, so, just from the point of view of compiling Foo correctly (as opposed to having it and all the code it calls run correctly), it isn’t necessary to recompile Baz in that situation.)
For now, I’m using a plain old Makefile. Which isn’t right, either, because dependency info isn’t expressed in the Makefiles, but I’m hoping that make plus whatever understanding javac has of dependencies will be good enough. (As long as I don’t do parallel builds; this machine only has one core, though, so that’s acceptable.) Clearly I should learn about ant; I’ll make sure to do that as part of my next iteration.
Most of the reason why I had to write so little code is that, for better or for worse, I saved the non-GUI code from my last attempt at this. Which was a very small amount of code, but I think saving it was a good move: as it was, the changes required for this iteration took more than my two-hour goal. I still had to learn a little bit of Java: I’d never written a unit test in Java for code doing output to a file before. (Or if I had, I didn’t remember.) Working from C++, the theory is pretty obvious – there must by some abstract “output stream” class – but I didn’t know how the details worked.
So I looked at the documentation (I really like javadoc), and, sure enough, we’ve got java.io.OutputStream. Except that it talks about byte streams, and Java (quite sensibly, but unlike C++) makes a distinction between characters and bytes. Nothing leapt out at me from the javadoc, so I pulled out a book and found that Writer was the interface that I wanted. It’s interface was a little sparse; digging around, PrintWriter is more useful.
My first reaction is that I’m not sure that separation is a great idea – why not put all the functionality on Writer? But the answer is presumably that doing so would make Writer a non-interface (since you would want default implementations of the extra methods), which would limit its flexibility given the way Java does multiple inheritance. It also raises the question of whether the function I’m writing should accept a Writer or a PrintWriter; I decided on the former, since it makes the function a bit more generic. Which I think is good design, even if it apparently isn’t always the Java way.
So that’s the function: what about the test? I seem to recall reading that Java has a class called StringBuilder that you’re supposed to use to construct Strings piecemeal, but it dosen’t have a relation to any of these classes. Digging around, though, there’s something called StringWriter which is a sort of Writer encapsulation of StringBuilder. Why doesn’t StringBuilder just implement the Writer interface directly, though? Beats me, not that I’ve thought about it much.
And then, after all of that, the unit test failed in a very mysterious way. At first I assumed that I was misusing the classes in question, but it turns out that the problem was in my understanding of Java’s compilation model, as mentioned above. Once that was all fixed, the acceptance test passed the first time; yay!
I’ll probably end up deleting some more of the code that I wrote in December, but it’s served its role as a crutch. And the new code is wonderfully pregnant with possibilities: I look at it and I can see how I’ll want to move this method to this class, and I’ll probably want to extract a class out of these functions, though I can’t quite see the details of the latter. But right now, the code is quite clean enough for the current desired functionality; I’ll do those refactorings as appropriate for future iterations. (I’ll certainly move some methods in the next iteration: that’s the right time, while right now is too early.)
I’m also starting to completely rethink the priorities of some of my early iterations. I had planned to, in the next few weeks, be able to save the data in XML and read it from XML. The truth is, though, that doing so won’t actually make life any easier for me as a Customer: it’s very easy to write Java code to add more books to the database. Right now, the relevant code looks like this:
Collection collection = new Collection();
collection.createBook("Walter Benjamin", "The Arcades Project");
return collection;
and I can just add a more createBook lines as necessary.
And XML was always intended as a crutch: eventually, I’ll want to generate web pages on the fly, and it’s a bit silly to do that by reading in the entire book collection in XML format. Instead, it’s better to look up whatever book the user requests from a database. So why not skip the XML step, and go straight to using a database?
I haven’t made up my mind completely; I would like an excuse to get my hands dirty with XML, after all. But the truth is that I don’t need it here, and that, in places where I might need it (controlling my iPod, generating an RSS feed), having used XML here won’t help me directly. Also, XML is pretty simple conceptually, so I don’t get the feeling that I really need to get my hands dirty with it to have a basic understanding of what’s going on.
Unfortunately, I don’t know anything about the databases, so I’ll have some reading to do before I can implement those stories involving a database. So for now I’ll stay away from the relevant stories, and concentrate on stories that improve the web pages that I generate (more fields, more kinds of data, whatever) while I read up on the subject.
Post Revisions:
There are no revisions for this post.
My most pressing current infrastructure issue is that I really don’t understand how javac works with dependencies. If Foo.java uses a class Bar and if Bar.java uses a class Baz, then it looks like, if I modify Bar.java and tell javac to recompile Foo.java, it will also recompile Bar.java, but if I modify Baz.java, then compiling Foo.java doesn’t cause Baz.java to be recompiled…
javac tries to be smart, which usually works, but sometimes does not. Unlike C++, a change in a class Baz cannot change the interface for a class Bar that uses it (even if it has the type Baz exposed in the interface) because objects are always passed by reference (and there are no type aliases so the actual type of any argument or return value is always clear.) So, a recompilation of Baz requires a recompilation of Bar (which might use something that’s been changed) but not of next-level clients (Foo).
But, by default javac works the other way and only does one level of “search”. If Bar.class is up-to-date wrt to Bar.java, but Baz.class is not, compilation of Foo.java->Foo.class will not update Baz. This can lead to an application failing in unexpected ways. But, I believe if Bar.class is also out of data, then Baz gets updated as well— although I’m not 100% certain. This is what I recall happening when I was doing more Java programming.
There is a -depend or -Xdepend which tries to get the whole dependency tree rebuilt.
9/4/2005 @ 10:38 pm