Today Chet and I spent a couple of hours working on the XML notepad GUI. We learned a lot, some of it useful.
When Chet came over today, we decided to begin our work on the first story for the XML Notepad. We had a running sample that fields events, and our plan was to implement the following story:
When the user types Enter, space down an extra line, create an empty P tag pair, and place the cursor in the middle of the tag, as shown here:
G03HR01
It seemed easy enough: our prototype already fields several control characters , which we used to display values from the TextBox control on the console, to get a better sense of what is happening in the XMLNotepad form code. (We could perhaps have used tests, as we did in Chapter 2, Testing with NUnit, but the TextBox was more of a spike to learn to make the GUI code work.) Here s the code we started with, inheriting from the Petzold notepad spike we showed you in the previous chapter:
using System;
using System.Drawing;
using System.Windows.Forms;
using Nunit.Framework;
using System.Collections;
namespace Notepad
{
class XMLNotepad : NotepadCloneNoMenu
{
[STAThread]
static void Main(string[] args)
{
Application.Run(new XMLNotepad());
}
public XMLNotepad() {
Text = "XML Notepad";
txtbox.KeyDown += new KeyEventHandler(XMLKeyDownHandler);
}
void XMLKeyDownHandler(object objSender, KeyEventArgs kea) {
if (kea.KeyCode == Keys.P && kea.Modifiers == Keys.Control) {
txtbox.Text += "controlP";
kea.Handled = true;
}
if (kea.KeyCode == Keys.L && kea.Modifiers == Keys.Control) {
String[] lines = txtbox.Lines;
foreach ( String s in lines) {
Console.WriteLine(s);
}
kea.Handled = true;
}
}
}
}
We talked about how to do it. I had been experimenting with a TextManipulator object that I thought could wrap a TextBox control and let us write methods against it. I d been thinking the TextManipulator would then become the model for the Notepad. As I tried to explain to Chet what I had done, it became clear that while I had probably learned some useful things, it wasn t time to commit to using that object, because the code didn t need it, nor did it point in just that direction. So our plan was to work directly in the Windows.Form, right inside the event handlers, until the code told us what it wanted to be like.
Lesson | If you re like me, you can t stop writing chunks of code that seem like they will be useful someday. And if you re like me, they often seem good enough to start using them, even if they don t exactly fit into the system, because we re sure they ll be useful later. I believe that the better thing to do is to keep the learning in our head, and maybe even in our file directories, but generally not in the system. The system should always have in it just the functionality that has been delivered to the customer and the simplest well-designed code needed to support that functionality. We should try not to put in generality before it s needed. We ve probably all said something like It will be cheaper if we put in this generality now; it will be harder to put in later. XP practices teach us that this isn t as true as we think. In this book, as we go forward, be watching for two things. First, watch to see if we get in trouble later because we didn t put in something more general than we needed at the moment. Second, watch to see what happens when we do put in more generality than is strictly needed. See whether we make mistakes and need to change it later. Then find your own balance. There s another advantage to you, the reader, taking the approach of putting things into the GUI at the beginning. This application is almost all GUI. It s nothing but a little text editor, with practically no interesting functionality, at least not yet. So what you ll get to see is how we write the code, test it, refactor it, and even write acceptance tests for our customer. We expect to wind up with a good design that separates GUI functionality from model ”text manipulation ”functionality. We expect that good design to emerge, gradually and naturally. We may be crazy, so watch carefully to see what happens. |