Thursday, May 15, 2008

Keep your Frameworks from Metastasising

Think Class Library, MacApp, PowerPlant. What do these frameworks have in common? They are all on my resume and they are all dead. Qt, Cocoa, AWT(?), Swing, MFC(?), .NET. What do these frameworks have in common? They are not dead, yet. The question mark indicates a framework in the zombie state of not being improved upon, but being used by too many people to be considered dead.
"It just so happens that your friend here is only MOSTLY dead. There's a big difference between mostly dead and all dead. Mostly dead is slightly alive." --Miracle Max in The Princess Bride



And, I am glad that frameworks die. I would rather not live in a world where 23 years later, MacApp was the best we could do. It was a pain to work with and I'm much happier with Cocoa or even Qt. People learned what was wrong with the old frameworks and made better ones. (If only this were true of MFC.) And, baring asteroid collision, people will come up with new frameworks in the future.


And that is the rub. Frameworks get you 2 ways. 1) they usually lock you into writing all your code in a particular language. If the next great application framework uses Python, and all your work is in C++, you're going to be awfully busy. 2) You drink the Kool-Aid, and use Framework classes everywhere. If you are a Qt user, half your methods take QStrings, and when the time comes when you want to switch from Qt to Cocoa, you will be re-factoring for weeks.


The language lockin is tough. I've known for years that C++ is not really a great application language; it may be a decent OS level language, but it is too fragile, too demanding, too static, and too complicated for making reliable desktop applications. But what else are you going to use for cross-platform apps? Maybe .NET will kill C++ as a cross-platform language. I don't know; it'll be a while. Hopefully, an appropriate cross-platform language will rise up to take its place. Which is part of my point, 10 years from now, we will not be using the same language on the same framework to do development. Something better will arise.


Getting back to the point of this entry, you want your code to last longer than any one framework. It's a matter of amortization. The longer your code lasts doing useful work, the higher the payoff for writing it. Over the 16 years I've been programming Macs, I've used 5 frameworks, and 3 of them are dead. I am not predicting the imminent death of Cocoa or Qt, far from it, but die they will, and I should have a backup plan. And here is the other rub, my backup plan 'til now has been to write cross-platform, pure C++ code using a lot of STL and boost, and try to keep the platform specific code from creeping into the general purpose code. But I just said, perhaps prematurely and wistfully, that C++ itself might fall out of favor with framework developers, which both makes cross-platform development more difficult without a Lingua Franca, and negates the hedge against your framework dying.


So I don't have a long term solution, but in the meantime do what has been good advice. Keep your use of frameworks limited to a thin GUI layer on top. Abstract the interfaces between your code and the framework. Abstract, abstract, abstract. To the extent practical, do not propagate framework classes into the meat of your codebase. If people had done this in the past, they could have skipped from MacApp to PowerPlant to Qt with a song in their heart instead of the crushing pain it was for most folks. Do not get locked in without a very good reason.


And know when it is time to scrap your live's work and move to a new language.
...watch the things you gave your life to, broken, And stoop and build 'em up with worn-out tools... --Kipling

Tuesday, May 13, 2008

Quartz to PDF, versus PS to PDF

I am ankle deep in Postscript code at my day job, so as a refresher I took an afternoon and hand encoded a business card for my wife, who is starting a side business arranging academic tours of China (for the Peking University Department of Philosophy and Religion). Obviously, most people would be better served creating a card in InDesign, or other vectored drawing editor, but this was a learning experience.


Here it is with the contact info scrubbed.



Postscript is not a friendly language, but it was simple enough creating a .ps file in my text editor—BBEdit—and just dragging and dropping the icon from the editor's title bar onto the OS X Preview application. Preview has the convenient feature of auto-magically converting Postscript files to PDF. Of course, compilation errors result in a cryptic failure dialog, but these were enough development tools for an afternoon's project. If I were to do this on a more regular basis, I'd compile a simple app which provided a message callback to the CGPSConverterCreate routine.


Consider how much easier it would be to create this file in Quartz, and how much better the output would look.

  • Font handling is hard in Postscript, even if you don't have to embed descriptions of your fonts. Thus my use of standard Postscript fonts Times and Helvetica.
  • Kerning is not automatic in Postscript. Yes, you can use kshow to manually set the spacing between pairs of characters. No, I'm not going to do that. Thus, the odd spacing between letters.
  • If this file had included characters from non-Roman languages, complications would arise as Postscript only allows 256 characters per font encoding, potentially requiring multiple font definitions per face. None of the free Unicode support in Core Text/Quartz.
  • I might have used a little transparency, but there's no such thing in Postscript.
  • Postscript is hard to read and maintain. The extra syntax needed to keep the parameter stack organized, distracts the eye away from the actual algorithm being described. Postscript is certainly more compact in the editor, by an order of magnitude, than a series of Quartz API calls but much of that compactness is wasted pushing, popping, dup'ing, and rolling the parameter stack. I mean, just look at it: [Update: changed ATSUI to Core Text]
    gsave
    basefont [9 0 0 9 0 0] makefont setfont
    (Nashua, NH 03061)
    dup
    stringwidth pop 2 div neg 0 rmoveto
    show
    grestore



The fact of the matter is that Apple has done a lot of heavy lifting for us either via proprietary extensions to PDF, or taking the extra effort of providing optimized support for font embedding. An afternoon spent trying to keep track of an unruly parameter stack was enough for me to appreciate how much power Quartz gives us, and how easy it is to call upon.