Home
Developers' Journal Below are the 20 most recent journal entries recorded in the "Reliable Software" journal:

[<< Previous 20 entries]

October 31st, 2006
08:55 am
[bartosz]

[Link]

Bugs in VS 2005
I find the quality of Visual Studio 2005 appalling. There are bugs that really stand out, and Microsoft must have known of them before releasing the product.

For instance: Every time you cancel a build, you have to pray. Not only does VC++ produce corrupt files in that case, but afterwards gives you nonsensical error: "Build failed: File xxx.obj is corrupted". Darn it! If you know that the file you produced is corrupted, just delete it!

If you are really unlucky you get a bunch of corrupted obj's. In that case, VS will inform you about them one at a time! So you have to start the build, see the error, delete the file by hand, start the build again, see another error, and so on...

Another annoying thing is that their code browser is brain-dead. It only understands a subset of C++. So, for instance, if you are using namespaces, you won't be able to search for definitions. You click on MyNamespace::Foo and you get a list of all Foo's in all namespaces. Maybe this is because my implementation files use the notation:
void MyNamespace::Foo ()
{
   do { the.foo.dance () } while (!it.rains ());
}

rather than:
namespace MyNamespace
{
    void Foo ()
    {
       do { the.foo.dance () } while (!it.rains ());   
    }
}

But that's correct C++ (it compiles fine), and one would think it's pretty easy to parse.

The browser is also pretty useless with virtual functions. With virtual functions, you would want to view a list of all implementations, not the declaration in the abstract class.

It's been almost a year, and Microsoft, to my knowledge, hasn't released a bug-fixed version.

(2 comments | Leave a comment)

October 26th, 2006
12:45 am
[bartosz]

[Link]

Wiki parser
I've been adding features to Code Co-op's wiki parser at the average pace of one a day. Most of the work now concentrates on built-in SQL queries, in particular the WHERE clause of the SELECT statement. I knew that once the wiki subsystem was released in the beta of Code Co-op 5.0, users would ask for more and more features. And indeed they did.

I started with simple clauses: equal and not-equal. Then I had to implement four comparison operators, >, <, >=, <=. Then CONTAINS, which is actually non-standard SQL, but it was introduced by Microsoft's content index (in fact I took part in defining it when I worked there). And now IN and LIKE. Not to mention the pseudo-property FILENAME. And sorting...

So now you can embed queries like this in your wiki page:

? SELECT Summary, Status, Resolution FROM Bug WHERE Summary LIKE %visual%studio% AND Status IN (pending, deferred) ORDER BY FILENAME DESC

This will produce a table with the Summary, Status, and Resolution columns for entries in the Bug database whose property Summary contains words "visual" and "studio" in that order, and Status one of "pending" or "deferred". They will be sorted in descending order of filenames (each entry is stored in a wiki file).

I also wrote articles about peer-to-peer wiki and wiki databases in Wikipedia. Both are our own invention. The idea of P2P wiki came from a friend of mine, Brian Dickens.

(Leave a comment)

October 14th, 2006
11:52 am
[bartosz]

[Link]

afxres.h
You can use Visual Studio 2005 C++ to create windows applications without MFC, right? Wrong!

It turns out that as soon as you create a resource file, VS puts this statement in it: #include <afxres.h>. This include file is absent from your installation if you chose not to install MFC support with Visual Studio. If you remove the include statement, the compiler will tell you that IDC_STATIC is not defined.

(10 comments | Leave a comment)

August 7th, 2006
04:39 pm
[bartosz]

[Link]

Rewrite
I gave up and started rewriting the differ. This code has been neglected for too long. I'm still trying to minimize the scope of the rewrite, but it doesn't look good.

I wonder if things could have been anticipated. If the design could have been better, so that the need for rewriting could have been minimized.

Probably.

Unfortunately, one can never anticipate all possible forces that will be stressing the design in the future. Often, when the designer tries to anticipate too much, the design becomes unnecessarily complicated. That's what agile programming tries to avoid (in my opinion, too aggressively).

There was one major mistake that was made in the design of the differ, and I must confess it was mine. It was a failed experiment in following the Windows architecture way beyond its limits. The idea was to design an editor that would work like a Window control. Sort of like an edit control on steroids. Every command to the editor was turned into a user-defined Windows message. Similarly, all notifications from the editor were sent to the main window as messages. This turned out to be a disaster.

One obvious drawback of message passing in Windows is its lack of typing, but that's a minor annoyance. What really hurts is that Windows message passing introduces a type of polymorphism that is totally incompatible with C++. Were I programming in Smalltalk, I might have had an easier time. But in C++ I ended up with a lot of code that looked like Smalltalk runtime written in C. Finally, only now I realize how hard it is to modify this code.

Lesson: Don't try to use the message-passing Windows architecture in C++ beyond what's absolutely unavoidable!

(5 comments | Leave a comment)

August 3rd, 2006
12:33 pm
[bartosz]

[Link]

More refactoring
If you realize that you need to make a change or add functionality in a lot of similar places in your code, consider refactoring first.

This is the case in my current task. I want to change the way documents are loaded into their windows. I want to create a separate window, with its own controller, to deal with each version of the document. Looking through code, I noticed that documents are loaded into windows in many places, and it always happens in a similar way. There is always some kind of a source: a file parsed into lines, a diff, or a merge. This source is dumped into an edit buffer. The buffer is sent to an edit window using a window message. Of course, in every case there as some subtle differences. The trick is to parametrize these differences.

Defining a common interface for the source objects helped a lot. I called this interface (abstract class) LineDumper. It has only one pure virtual method Dump. It dumps its contents into an edit buffer, which is a collection of tagged lines.

I was then able to centralize the loading of documents into two methods of the Commander: InitVersionDocument and InitDiffDocument. It's the InitVersionDocument method that's of major interest to me. It initializes the document to be displayed in the left pane. That's the place where I can start implementing my scheme of using a vector of editors, one for each version of the document.

(Leave a comment)

August 2nd, 2006
02:20 pm
[bartosz]

[Link]

Change of approach
There is one display pane and multiple documents that can potentially be displayed in it. This display pane is represented in code in more than one way:
- A window handle to an editor window--a window with a scroll bar (or two) and a pane.
- The editor controller
- The pane window handle
- The pane controller
Right now, the document buffer is attached to the pane.

My first impulse was to attach a new document buffer to the same pane--this can be easily done (and in fact, it worked when I tried it), but leads to a lot of problems at higher levels.

So my second idea is to go to the top leve,l and create a separate editor window for each document. Of course, only one document can be displayed at a time, so I would have to juggle windows. Only one window would be active at a time and that window would be shown and it would receive user input. When the user clicks on a tab to show another version of the document, the current window would hide, and the new one would take its place.

Of course, all this could be lazily evaluated--the windows, and even the controllers, could be created on demand.

So I need a cache of windows. When switching tabs, I would first check the cache for a given document version (before, after, current, etc.) and create it, if it's not there.

This calls for an auto_vector of objects that combine:
- window handle,
- edit controller, and
- a tag (e.g., "before", "after", etc...)
- a file path

I'll call this object DocEditor. I'll create one DocEditor at the start; and later add more, in response to tab notifications. The top controller will store a window handle corresponding to the current DocEditor and use it to communicate with it (that's what it does now, except that the handle never changes).

(Leave a comment)

August 1st, 2006
05:14 pm
[bartosz]

[Link]

The Snag
It happens every time! You are deep into the implementation of a new feature when you realize that you have a major unexpected problem that seems to require the re-architecting of the whole system.

Here's the problem: The differ was designed to have a one-to-one correspondence between an editor window and a file that's being edited in it. With the addition of tabs, this is no longer true. When the user clicks on a tab, a new document has to be loaded into the same editing pane. This poses several questions:

1. What to do with the contents of the previous document. Discard it? Not if it's been edited! Save it? Too disturbing to the work flow. We obviously have to keep the buffer, at least if it's been edited.
2. What about the undo stack? It belongs with the document buffer, not the editor.
3. How to set the scroll position of the new document? The user will expect to view "the same" part of the "before" and "after" file.
4. We have to make sure that the correct file is saved under correct name. There was an assumption that the currently edited file has to be saved, but the user might be viewing the "previous" file, having edited the "current" file, which is now hidden.

We could get away with just one undo stack, if we allowed only one version (current) to be edited. It seems like a reasonable assumption. But what about the "Save As" menu item? Shouldn't the user be able to save a previous version of the file under a different name?

Back to the drawing board!

(Leave a comment)

July 30th, 2006
01:14 pm
[bartosz]

[Link]

Another check-in
That was quick! Clicking on tabs now displays a message box with the appropriate path.

Why is it so important? Because now I know that I have an environment for implementing the main functionality--switching files in the differ window. I have to fill in the implementation of the top controller's ChangeFileView method. In all likeliness I won't have to touch any part of the UI or top level objects. I'll be working on a lower level of abstraction.

(Leave a comment)

12:48 pm
[bartosz]

[Link]

Check-in
At last a moment of free time! I re-read my last two posts to figure out what to do and I quickly implemented, tested, and checked in the following change: Initialize tabs based on FileNames.

Next step: Create the environment for tab selection handling. Define the class FileViewSelector, as described here. For now, I'll implement its method ChangeFileView, at the top controller level, to display a message box with the appropriate file path--I can can get the path from the FileNames object.

(Leave a comment)

July 25th, 2006
12:26 pm
[bartosz]

[Link]

Access to tabs
There is one central place in the Commander where the command line is parsed and re-parsed (e.g., after the Open and Compare menu commands). This is where I inserted the InitTabs call. This a new private method of the Commander. Since this method requires access to the tab control, which is owned by TopController, I added a method AddTabView to the commander--it takes a pointer to the tab view (which is this handle we are not supposed to be copying from one of the previous posts) and stores is as a Commander data member. It is called inside TopController::OnCreate method, right after the tab controller is created.

Remember, first provide access to objects, then implement their usage.

Commander::InitTabs is now stubbed to just add the Before and After tabs and select the After tab.

That was a small task, resulting in a small check-in. Now to a more general implementation of InitTabs that uses FileNames.

It is very important to be able to talk about code at a high enough level. Note that I provide very few code samples--I mostly talk about interactions between components. I sometimes use actual class names and sometimes generic names, and there is barely a difference between them--e.g., FileTabController vs. tab controller (there's only one in the differ).

This is how we communicate at Reliable Software. A programmer who cannot explain in plain sentences what's going on in his/her code is sent back to the drawing board. I'm not kidding!

(Leave a comment)

10:53 am
[bartosz]

[Link]

Top-level continued
So far I have covered the following sites where the top level interacts with the tabs:
- Construction of tab controller in TopController::OnCreate and its ownership by TopController
- Positioning of tabs during OnSize
- Identification of the site where the tab control notifies the client that a selection has been made--the OnSelChange method of tab controller

There is one more interaction to be analyzed--the creation of tabs depending on what the differ is supposed to display. For instance, if the differ is called with a single file name, there should only be one tab--Current. When showing the diff, the Before and Current; or Before, After, and Current tabs should be shown. In a merge situation, the Reference tab should also be shown. And so on.

The decision about what is to be displayed is taken during the parsing of the command line. There is an object called FileNames that stores the results of the parsing--it could be also used to provide the info about what tabs should be displayed.

Unfortunately, the format and the parsing of the command line are not very logical--they are a result of hacking without looking back. So this is a good time to redesign this part. I will have to rationalize the command line format and simplify its parsing. The command line is created in Code Co-op before executing the differ. There are a few well-defined spots where this is done. The parsing of the command line is done in the differ's commander and results in the initialization of FileNames.

There are two other places where tabs require reinitialization--these are the menu commands, Open and Compare With.

So where should I start? As I said, the top-down approach requires me to first create an environment for my new component--the tab control. So the number one thing is to find the attachment points and do the soldering. This is done not only before the component is implemented, but even before the callers are fully functional. So I will put the rationalizing of the command line on the back burner for now, and concentrate on the interaction between FileNames and the tabs. I'll have to figure out what questions to ask FileNames in order to create appropriate tabs. I will create stub member functions in FileNames to answer these questions.

Remember, figuring out the interfaces always comes first.

(Leave a comment)

July 23rd, 2006
10:21 am
[bartosz]

[Link]

Simplifying Code
I can't stress enough how important it is to immediately follow any extension of functionality with a refactoring and simplifying step. We've learned it at Reliable Software the hard way.

What happens if you skip those steps? The complexity of your code keeps increasing until you lose control over it. We came very close to this point when developing version 4.6. We had to establish strict rules to keep complexity in check. Accompanying every development step with a small rewrite became a rule. Creating new abstractions, refactoring, or plain simplifying the code are ways of reducing complexity.

Each new abstraction frees the brain of a developer from having to remember details. In cognitive psychology they call these things "chunks". If the code is nicely split into chunks, we can easily reason about it. If it's not, we have to put a lot of effort to create these chunks on the fly. We study the code over and over until some structure dawns on us (or not!). Then we promptly forget the ad-hoc chunking, and the next time around we have to go through the same process again. What a waste of time!

So I have abstracted some functionality of the tab control. Now I'm looking at the tab controller classes, which are virtually duplicated in code co-op and the differ. They are both derived from Notify::TabHandler. They contain a View, which is the above mentioned tab control abstraction (the EnumeratedTabs template, or a class derived from it). Most of the functionality of the tab controller is simply delegated to its View--Get/Set Selection, Add/Remove Tab, etc. I could have abstracted this delegation, but a simpler solution is to expose the View to the client of the tab controller. The method GetView returns a reference to the proper instantiation of EnumeratedTab. For convenience, I have typedef'd this instantiation, so, for instance, in the differ, FileTabController::View is the same as EnumeratedTabs<FileSelection>. In practice, I don't ever use this type outside, I just make direct calls, like this:
_tabCtrl->GetView ().SetSelection (FileAfter);

This modification required some changes in the client code, but they were self-limiting. This shows the resiliency of our code in the face of local modifications. It's not always like this. Sometimes a small change in the interface of a lower-level object results in an avalanche of changes in the client code. That would be a sign of weak design.

(Leave a comment)

July 24th, 2006
06:01 pm
[bartosz]

[Link]

Resolution
What d'you know! That was exactly the problem. I added the following three lines to ControlWithFont:
private:
    ControlWithFont (ControlWithFont const &);
    ControlWithFont & operator= (ControlWithFont const &);
and the compiler caught the problem immediately. Tab::Handle was being passed by value to TabSequencer. I have no idea why this code worked before--it shouldn't have!

(Leave a comment)

05:26 pm
[bartosz]

[Link]

Snag
So far the implementation has been a breeze, 15 min here, 20 min there... And suddenly I'm in deep trouble. Hours are passing and I'm making zero progress.

What happened? All this refactoring was not supposed to change the functionality, right? So why are the tabs in Code Co-op displayed using the ugly default Windows font? At first, I thought it was something trivial, so I reviewed my changes--to no avail. The font in the tab control is set using the SetFont method of ControlWithFont. It's always been like this, and it worked. I started the debugger to make sure I'm not passing the wrong arguments, or passing object by value instead of reference (I'm not very consistent with blocking value semantics by declaring empty copy constructors and copy assignments). No such thing. I noticed though that the font is originally displayed correctly, it changes back to ugly after the first call to SetSelection. My running hypothesis is that this is something related to object ownership. Somehow the font created in ControlWithFont gets deallocated. I'm going to test some more.

(Leave a comment)

July 22nd, 2006
04:37 pm
[bartosz]

[Link]

Refactoring
I did a lot of copy and paste when implementing a tab handler for the differ. Sure, I had to change a few things here and there, but essentially a lot of code is now replicated between code co-op and differ. So now that I have two variations of the same thing, I can refactor the commonalities and parametrize the differences.

Let's start with the "view" part of the tab controller. It is built around the library object, Tab::Handle (it derives from it). There are two things it adds to the handle--it names the pages using an enumeration and, in the case of Code Co-op's implementation, it adds an image list that contains the red and green dots that can be displayed in the tabs.

I propose to refactor the enumeration part. I will create a template class, EnumeratedTabs, that takes an enumeration as a template parameter. I will use a different enumeration for differ tabs, and for co-op tabs. The first enumerates "before", "after", "current", and "reference" versions of a file. The second enumerates the "file area", "check-in area", etc., of code co-op.

For the time being, since there is only one client for the image list associated with tabs, I won't refactor this part. I'll just derive co-op tabs from my template and add the image list functionality to it.


With such a detailed plan, I was able to implement this task and test the result in about 15 min. The result is a template class EnumeratedTabs in the library (it will soon appear in RSWL). It's used directly in differ tabs, and as a base class for co-op tabs. If anybody tells you that they have no time for refactoring, don't believe them.

(Leave a comment)

July 21st, 2006
07:30 pm
[bartosz]

[Link]

Why UI first?
You might be wondering why I started with the UI. I already explained the advantages of top-down implementation--you want to define your lower-level objects through the environment in which they will work. The environment in this case is provided by the UI. In particular, I know now that the switch between viewing different versions of the file will happen inside of the notification handler for the tab control.

It follows that I will have to give the handler access to some high-level object, maybe even the top-level controller, which controls what files are displayed in differ windows. However, it would be a bad idea to just give the handler access to the whole controller. It would cause a very bad dependency inversion. Think of it this way, if the handler had access to the top controller, the handler source file would have to #include the top controller header. But the top controller already depends on the handler--the handler object is embedded inside the controller! We get circular dependency, and this is a sure sign of bad design.

So how does one avoid circular dependencies? First of all, notice that the handler doesn't need access to all the methods of the top controller. It will probably call just one--maybe something called ChangeFileView. So the handler could be perfectly happy using a narrower interface with just this one virtual method (maybe also GetCurrentFileView, or some such). This interface could be called FileViewSelector.

The trick is to derive the top-level controller from FileViewSelector (as well as from Win::Controller--multiple inheritance!). The top level controller will implement the ChangeFileView virtual method--it has access to all the objects involved. The constructor of the tab notification handler will get a pointer to FileViewSelector, so that it will be able to call its ChangeFileView method when necessary. The fact that the pointer really points to the top controller will be established dynamically, when the program is running. This way the handler code has no dependency on the top controller, but at runtime it will call the implementation of ChangeFileView that belongs to the top controller. We have a cake and eat it too.

I don't know what this trick is called, but it's something that every programmer should know and use all the time to solve dependency inversion problems.

Other advantages of starting from UI--you get immediate visual feedback. You can see the tabs and you can click on them. You know that things work as they should when you hit the breakpoint in the handler.

Another thing worth noticing is how little time the implementation took and how it worked as soon as it compiled. The task was very well defined and researched. And that's another great advantage. While researching the UI, I refreshed my memory about the relevant parts of the system. Now it will be much easier to proceed, because I know which files to look at, and where the action is. You can't overestimate this!

(Leave a comment)

July 19th, 2006
06:15 pm
[bartosz]

[Link]

UI implemented
I finally found some time to get to the implementation. It took maybe half an hour altogether, although it wasn't continuous time.

Status: A tab control with two tabs (Before and After) is displayed-- just for testing. When I click on the tab, the OnSelChange method of the tab controller is called. It doesn't do anything yet.

(Leave a comment)

July 16th, 2006
04:20 pm
[bartosz]

[Link]

Adding tab controls
(Continued from previous post.)

As a rule, we always develop and modify our code top-down. When UI is involved, it means starting with the UI part. In this case, I'll start with the tabs.

Not to reinvent the wheel, I look at the existing code that uses tabs. Code Co-op's main window uses tabs, so that's where I look first.

Code Co-op's code is much more mature than the Differ code--it already went through a lot of rewrites and restructuring. For instance, the whole UI part of co-op is separated into the UiManager object. This object contains a TabController object. TabController inherits the library interface Notify::TabHandler.

Whenever the user clicks on a tab, the window procedure is called with WM_NOTIFY. Our library implementation of the window procedure calls the window controller (implemented by the client) to obtain a notification handler and let it process the notification.

Code Co-op overrides the GetNotifyHandler method of the controller. It selects the appropriate handler based on the ID of the control. The tab control must have a unique ID. When the notification comes to this ID, co-op controller returns the TabController object from UiManager.

These steps have to be repeated in the Differ. A TabController must be implemented and GetNotifyHandler must be overridden.

This is the passive role of the TabController--it responds to windows messages. Code Co-op itself also interacts with TabController--it sizes and positions it in its main window. This is done in the OnSize method of UiManager (the controller delegates OnSize to UiManager).

Having learned all this by analyzing existing code, it's time for me to sketch a plan for the first modification. I will create a dummy TabController object in the Differ project, embed it in the Differ controller (Differ doesn't have a separate UiManager) and implement the infrastructure around it--starting with GetNotifyHandler.

Next I will implement OnSize. For that I'll have to actually create a tab control. This is done using a Tab::Maker library class.

This will all be dummy implementation--the titles of the tabs will be assigned arbitrarily, and there will be no action associated with clicking on a tab. I will test it and check it in.

(Leave a comment)

July 15th, 2006
03:43 pm
[bartosz]

[Link]

Development Record
I decided to record an example of development process at Reliable Software. The company has always been a testing ground for new development methodologies, and over the years we have come up with our own ways of doing things. Considering how much high quality code we've been able to produce with very limited resources (three developers), our experiences might be worth sharing.

Producing quantities of code is no big deal. What is significant though is the ability to modify this code with relative ease. Every time you add new functionality, the complexity of your code increases. If you're not careful, you end up with a mess. We have developed very strict guidelines to control complexity. Every time we add more code, we also have to restructure its surroundings to add clarity and structure. Some amount of rewriting must always accompany the addition of new functionality.

Here's the task I have to accomplish: Modify the differ so that it can display not only the diff and the resulting file, but also the file before the change and, if it makes sense, the current state of the file. In a (three-point) merge situation, the differ should be able to display the reference file as well.

The plan is to add a tab control to the differ, to let the user switch between all these views. The diff pane will be always visible, but the other pane will be switchable.

The dispatcher code hasn't been substantially modified for at least five years, so I'll be re-learning it as I go.

Watch this space for the next installment.

(Leave a comment)

July 14th, 2006
09:29 am
[bartosz]

[Link]

Top-down and test-driven development
I've been always advocating top-down approach to software development. This was based on my experience. Bottom-up leads to impedance mismatch problems; top-down creates clean architecture. I know I'm right, but how do I convince others?

And whenever I do a code review I have to be convincing. Just saying, "Trust me, I've done it a million times" doesn't always work.

What got me thinking about it is the test-driven methodology. It's a gimmick, which is useful in some specific situation, and is touted by some extreme programmers as panacea for all programming ills. The main point of test-driven development is that you first design a set of tests and then develop a component that passes them. At every step you use minimalist approach--you don't design for generality, you just want your component to pass the next test. The advantage of this approach is that you end up with a component that is built exactly to the spec--the spec being defined in terms of your tests--no more no less.

Of course, the problem is now shifted to designing appropriate tests--not an easy task! These tests create an environment for your component. The component evolves to fit this environment. Conceptually speaking, to design a plane, you first build a wind tunnel. If the plane passes all tests, it will be able to fly in your wind tunnel--which, incidentally, is not the same as flying in the airspace.

So the main question is, how well does your test suit simulate the actual environment where your component will live?

Now, going back to top-down approach--when you build your software top-down, you are, at each step, creating the actual environment in which your component will live. This reasoning clearly shows both the advantages and the shortcomings of top-down.

The main advantage is that the component is built to the exact specifications of its environment--you'll know what data, and in what form, will feed your component. You'll know what output is expected from your component. You'll know its lifetime--creation and destruction time.

On the other hand, it might be difficult to re-create all testing scenarios in a live project. Testing special cases and boundary conditions might be hard.

But the main problem is when your component must serve in multiple environments. Here, from the very start, you have to abstract the environment for your component. This abstraction might be easier to describe by a test suite than by anything else.

Which brings me to the conclusion that test-driven development is best when you are designing for reuse.

Which is actually rare.

(Leave a comment)

[<< Previous 20 entries]

Reliable Software Powered by LiveJournal.com

Advertisement