| || ||
| || |
| Controls in your XML ||2/14/2007 |
I have just added a new feature to ACCELA’s AAutoToolbar class. You can now specify popup buttons, segmented controls, and combo icon buttons directly in the XML file instead of having them in a nib. The nib approach seems like overkill since it has to instantiate an entire window just to extract one control. If only Carbon nibs could have views in them like Cocoa nibs can.
I also finally added some unit tests to the toolbar test project. In the process, I rediscovered a bug that I first ran into about a year and a half ago. I always feel a bit silly when I search the mailing list archives for messages about a particular problem, and find I was the one who asked the question the first time too.
This particular thread was interesting because it sparked a debate over what bug fixes should be included in a 10.4.x release versus in 10.5. The argument for delaying the fix (even though this fix is trivial) is that any change is dangerous, so priority is given by need rather than ease.
The bug is that if you try to find what toolbar a toolbar item is in, and it hasn’t been added to a toolbar yet, you may get a crash. For me the situation only comes up in unit tests, so having to work around it isn’t that big a deal.
The competing Nano library (much more like ACCELA than Nitrogen is) seems to be having good success. It does have a better web site than I have for ACCELA. The author, Dair Grant, agreed with me that it would have been good for us to collaborate rather than compete, but he didn’t discover ACCELA until Nano was already well underway.
So my conclusion is I need to make some fancier web pages to show off what ACCELA can do. With some screen shots, even.
| || |
| || || || |
| || |
| Separation ||11/12/2006 |
I’ve decided to make it a goal to remove the use of ACCELA in Volley. It’s weird in a way to say I don’t want one of my open source projects to be used in my other open source project, but I think overall it’s better this way for a couple of reasons.
First, there are some things that ACCELA is being used for which needs to be replaced with something cross-platform-friendly - specifically, string handling and XML parsing. Both of these can be replaced with libxml, which is not only a good cross-platform XML library, but it’s also built in to Mac OS X. (It’s kind of an outdated version, but I haven’t had any problems so far.) Since the client is being rewritten in Cocoa, most of the remaining Carbon-based code is related to handling files and folders, and that can be redone with Cocoa calls too. The plugin loading code won’t change though, because Cocoa’s NSBundle doesn’t have an equivalent for CFBundleGetFunctionPointerForName.
Second, I think it helps if I avoid dependencies. Ideally you should be able to download the source code of an open source project and just build it. Requiring additional steps, like grabbing another library, complicates the process, making it easier to mess up and making it harder to attract more developers to the project. Having an “it just works” quality is a very attractive feature, I think.
This is a bit ironic since I’ve just added a dependency on boost, but that’s a popular library so I think that’s more acceptable.
This is also why I didn’t use ACCELA in XVG, although I could have - the Core Graphics wrappers would have been useful. But I think it actually wouldn’t have made a big difference, and limitations in Objective-C++ might have gotten in the way (especially in regards to having a C++ class as a data member of an Objective-C object). Plus in a way it’s nice to stick with the raw C functions, so I can remember how they work.
| || |
| || || || |
| || |
| ACCELA October 2006 release ||10/7/2006 |
The most sweeping change since the last release is the refactoring of the XWrapper and XRefCountObject templates. The constructors were split into two versions, instead of taking an inDoRetain/inOwner parameter. The new version is cleaner, especially when passing the result of a function to the constructor.
The new Bindings group of classes provide support for basic Cocoa bindings in Carbon controls: value, text, enabled, minimum, and maximum. Data browser support is a work in progress.
The AEventParameter family of classes have been reworked slightly to use template specialization to associate event parameters, types, and type codes. It’s just the kind of tedious work that ought to be done by the compiler.
Many other changes and improvements have been made, including more examples and a few basic unit tests. I have also written up an overview of the major classes.
| || |
| || || || |
| || |
| Just when you think you’re done ||10/6/2006 |
Releasing software is harder than it looks. I’ve been learning that lesson pretty thoroughly both at work and at home as I prepare the next release of ACCELA.
The basic feeling is just when you think you’re done, there’s this whole other load of work to go through. For ACCELA the list looks something like this:
- Make sure all the example projects build and work properly. I’ve made some good improvements in this area lately. Or rather, I’m not as lazy as before. I could use more unit tests, but there are some, especially on the documents & scripting code. That’s where it’s most needed, since there’s real stuff going on there, not just wrappers.
- Compare the current files to the last release and compile the release notes. I don’t get enough feedback to know if this is actually needed, but I do this step as a matter of principle anyway, just to keep everything neat and tidy.
- Generate new HeaderDoc files, fixing any errors that come up, and upload them to the web site. Every time I have to remind myself how to update a SourceForge project web site.
- Create and upload the archive. This means exporting a clean copy from the archive so there are no .svn directories, and then reminding myself how the SourceForge file releases system works.
- Announce the release. This means posting an article on the SourceForge project page, posting a news item on my blog, and sending a message to Apple’s Carbon Development mailing list.
And then I finally go back to life as usual. For people outside the software industry, I bet it’s easy to assume that we just write some stuff, call it good, throw it in a box, and ship it. But there’s a lot more going on behind the scenes.
That kind of thing always reminds me of when I went to Disneyland several years ago and they were running tests on the Rocket Racers ride, which was supposed to replace the PeopleMover. They had the cars running along the tracks with big plastic jugs of water to simulate passengers. The plastic jugs even had grooves for seatbelts, so you could tell this wasn’t just thrown together. And it turned out to be a good thing they ran those tests, because the ride turned out to be a bad idea. The PeopleMover tracks just weren’t designed for fast-moving cars.
I suppose I could add some crack about other bad ideas that Disney should have abandoned, but I’ll leave it at that.
| || |
| || || || |
| || |
| Apple’s RecentItems ||6/30/2006 |
As I was browsing the contents of the latest ADC documentation update, I found a new sample code package called RecentItems, which implements a “recent items” menu for Carbon applications. Interestingly, the sample app sorts files, folders, and applications into separate submenus.
Of course, I’ve already implemented a Carbon “recent items” menu in ACCELA’s ARecentItemsMenu, so I had to check this out to see how it compares. My goal was to imitate the Cocoa version as closely as possible, but apparently not so with this sample. There are no file icons in the menu, and if you have two files with the same name (but in different locations), the old item is deleted. I followed Cocoa’s behavior of showing the parent folder’s name and icon to differentiate the two.
It would have been interesting if this sample code had tried to do what I did… but at least now I don’t have to catch up with the competition
| || |
| || || || |
| || |
| Major ACCELA changes ||6/14/2006 |
I’ve been making some major ACCELA changes in the past few days.
The first was something that’s been bothering me for a while: that extra flag in the XRefCounter and XWrapper class templates. Flags are often a sign of sub-optimal design. They can be hard to read because “true” and “false” don’t have enough inherent meaning. A better approach is usually to add more meaning to whatever the flag accompanies, so that’s what I did in this case.
I created new simple wrapper types that contain a reference type - like a WindowRef - with the additional meaning that “this reference has just been retained” or “you should delete this object when you’re done”. XRefCounter and XWrapper now have two constructors: one that takes the plain reference type (the WindowRef), and another that takes the “retained” or “owned” wrapper type.
This actually has two advantages. First, it replaces those flags with something that’s easier to read. Second, any function that returns a newly retained or created reference can return the new retained/owned wrapper instead so that you don’t have to remember that detail when you use the function. That information is already built-in.
This kind of thing is what I love about C++.
Since this was such a wide-reaching change, I also started writing some basic unit tests. So far I had only done that for the document classes. To begin with I just have some tests for ACFString, but that tests the new wrapper class system well enough too.
That new unit test project (BasicTests) includes every file in the library, to make sure everything complies. It also has a file that includes every header file that doesn’t have a corresponding source file, to make sure the compiler looks at everything. This uncovered quite a few problems. There were several files that I had written speculatively but never used. In some cases I had written the same class in different places, and the compiler complained about reusing the name. Right now I have everything compiling except for the duplicate printing classes.
Now I’m working on a new approach to Carbon Event parameters, associating them with their type codes and data types. Instead of manually adding new entries in AEventParameter.h, I developed some regular expressions for extracting the definitions from the Carbon header files and turning them into macros that declare template specializations. Most parameter names are followed by a comment with their type code, and most type codes have a comment with their data type. I still had to do some hand-editing for the exceptions, and for those which didn’t have one specific data type, but it’s still more efficient than the old way.
This is another thing that makes C++ fun for me.
On the other hand, there are many of you who might not see how any of the above could be called “fun”. To each his own. I’m going to go home and watch cartoons.
| || |
| || || || |
| || |
| Open Source and Diligence ||4/23/2006 |
XVG was my first new open source project in a few years, and I’ve taken a somewhat different approach with it than I did with the others (at least at first). I’m going by two basic rules: work on one thing at a time, and keep the repository in a state where someone can build the application and run it at any time. Unit tests definitely help with that second one. I’m also trying to be responsible about maintaining XVG as an open source project. I try to keep in mind that it is basically on display to the whole world (even if, in practice, not many people are looking at it right now), so I should think of it as a front lawn instead of as a closet.
ACCELA wasn’t as easy to work on under those rules, since for the most part it’s a collection of mostly independent parts. There may still be a few things that are not well tested; I never wrote a test/demo app to test everything. I mainly left that for features that were more my own code than just simple wrappers: the auto toolbar and the document classes.
Volley, on the other hand, definitely would benefit from those practices, but when I started it I didn’t quite have the habits of focused development that I’m trying to adhere to now. For example, a while back I made a fairly major change - switching over to the boost classes for threads - but I have yet to check that in because I started working on other things at the same time, and I never quite got everything fully working. I didn’t really get into the concept of unit tests until Xcode 2 made it convenient. One of these days I need to get back and finalize these changes; perhaps I should plan to do that after the first release of XVG.
There is always the temptation to decide I’m bored of working on a feature, and skip over to something else instead. But then I end up with a mess of half-completed features. I caught myself going down that road just recently with XVG. I had started to implement drawing and editing tools, and I had a chain of logic that led me to start implementing the Bring to Front/Send to Back commands.
You see, to be able to switch tools, I needed to have the tool palette item in the toolbar (since I plan to do that instead of a floating tool palette). But I wanted the window to look good, so there should be some other toolbar items too. The item ordering commands seemed like good candidates, so I started working on those. But once I had the code written for them, I remembered that I still hadn’t tackled the issue of Undo, which I would need not only for these new commands, but also for the recently-started editing tools, not to mention the inspector palette that’s been there for a while. So really Undo needed to be the next task; putting it off would only mean more work when the time came to adding it in to already-written commands.
That’s why, if you were to look at the XVGView.m source file right now, you’d see all the written-but-untested item ordering commands commented out. For the sake of keeping things clean, I don’t want to leave anything in that hasn’t been reasonably tested, and it simply wasn’t the time to test those commands.
These principles of unit tests and focused development appeal to me a lot, and I often think there are some good life lessons that can be extracted from them. These practices do not happen in isolation; when you develop good habits in one area of your life, it’s going to help you in others too. And of course, the same goes for bad habits.
Focus is a good thing. It helps fight laziness, and it gives you a way to express that you care about what you’re doing. If your work on a project consists of randomly poking at various individual tasks, then you won’t get much satisfaction or progress. If you don’t actively demonstrate that you care about the project, you will come to care about it less. It will mean less to you because you haven’t given it meaning.
Unit tests are a way of defining the goals and standards for a program. They give you a way to tell the computer what you expect out of the program, so that the computer can tell you if it lives up to those expectations. I only wish there were such a quick and easy way to run unit tests on my life, giving me a report of any ways in which I am not meeting my own goals and standards. Instead, I have to do it the old-fashioned way, through introspection and developing the good habits that defend me against the bad ones.
| || |
| || || || |