Showing posts with label frameworks. Show all posts
Showing posts with label frameworks. Show all posts

Monday, May 5, 2008

Developing a New Framework

This post is a bit of a change for me. I'm actually going to write about my work for PC-Doctor! I'm actually a bit embarrassed at how rare that's been.

I want to talk about how to design a brand new framework. It's not something that everyone has to do, and it's not something that anyone does frequently. However, there's very little information on the web about the differences between creating a library and a framework.
I've been working on a framework here at PC-Doctor, and I've worked on a few others in a previous job. I'll admit that I'm assuming that all similarities between these projects will be true for any new framework.

There are three things that I want to see from a new framework project. After I get those, it becomes more difficult to generalize across framework projects. The first framework I developed had all three of these aspects mostly by accident. My current framework has a tighter deadline than the previous one, but it still has all three of these to some extent. I'm a strong believer in all of them.

Goals


All of the frameworks that I've created try to do something new. This makes requirements gathering extremely difficult. If no one understands what the framework will accomplish, you almost have to decide on your own what it'll accomplish. You'd better be right, though!

Management will typically have a short term goal that they want accomplished with the framework. They might even be able to come up with a set of requirements. Don't get trapped by this. A framework must be much more than that. It enables programmers to use a common language to describe a class of application. Learning this language requires a significant time investment. If it only solves a short term goal, programmers won't be able to make that investment. Your framework has to solve a significant problem in order to be worth the investment required.

In another sense, however, requirements gathering for a framework is easy. You can get some details of the requirements wrong without damaging your users' ability to figure out what they want to do with it. After all, they typically write code using the framework. They can just write a bit more code than they should and get things working. Later iterations can use this experience to refine the design, but this won't happen until late in the design of the framework.

Instead of trying to find formal requirements, I prefer to find something that I call "goals". This is closer to a set of use cases than requirements, but they're reformed so that they look like requirements.

After developing a framework in my previous job, I saw how critical these goals were in the framework development. A good set of goals can let you make decisions quickly and accurately about design problems. If the goals are relatively small and simple, then they can be applied uniformly and accurately throughout the life of the project. That means that you're likely to fulfill the goals.

As an example, I'll give you a few of the goals for my current framework:

Goal: Relatively inexperienced developers should be able to use the framework to do somewhat sophisticated things.

This goal has driven a large fraction of my decisions on my current project. In my vision of the future, there will be hundreds of mini-applications using this framework. Having an enormous number of these applications would allow us to do some really amazing things, but that's simply not possible if I have to write them all. In fact, that's not possible if PC-Doctor engineers have to write them all.

This goal is designed to allow us to recruit developers who are more interested in the problems that the framework can solve than the techniques required to write code with it.

If this goal were a requirement, it would state something about the usability of the framework. Perhaps it would say how long a typical programmer would take to develop their first application with it. In its current form, it's almost completely useless to our QA department. That's not what it's for.

Goal: The appearance of the UI elements created with this framework should be directly modifiable by Chris Hill, our art department.

Again, this is me recruiting other people to do my work. :-) Stuff that Chris creates looks about a hundred times better than stuff that I create. Looking good is an important goal for us since we want our product to be fun to use rather than merely possible to use.

This is a better requirement than the previous one. This can be verified directly.

However, it turned out not to be that useful of a goal. While this goal verified some of the design decisions that were made for other reasons, it hasn't been all that useful to me directly. This might be a good thing, actually. If the goals work well together, they shouldn't have to conflict.

Goal: A future iteration of the framework should be portable to a variety of other platforms.

This goal is a good example of a goal that mostly gets ignored. The architecture does indeed support Linux, and a lot of the code should be easily ported to alternate platforms. However, it's hard to pay attention to a goal that isn't needed in the next release. PC-Doctor has some tight deadlines; we don't get to develop frameworks out of sight of our paying customers.

Not all goals have equal importance, and not all goals are actually useful. I don't consider this a failure, yet. Try to have as small a set of goals as possible. The more you have, the more difficult it will be to accomplish all of them simultaneously.

Okay, I've got a few other goals, too, but that gives you the idea. These are extremely high level goals. You could call them requirements, but that would be stretching things a bit. They really aren't that formal.

These goals are extremely important to the project. Choosing the wrong ones can kill the chance of success. Choosing the right ones will make design decisions extremely easy.

Usability


The next thing to worry about is the users of the framework and its usability for those users. I've talked about this before. The things I say in that post are even more valid for a framework than they are for a library. Go ahead and read that. I'll wait.

In my current project, I've got two types of users to think about. The first are mentioned in my goals. These are the developers who will write mini-applications with it. The second group are my coworkers who will help me maintain it.

Unfortunately, this framework has ended up putting the two groups in conflict. I frequently end up adding complexity to the framework in order to reduce the complexity of the API. In fact, I frequently go to great lengths to simplify the API slightly without worrying about adding half a dozen states to the framework's state machine.

It's still too early to tell if this will be a success. However, there are some preliminary indications:

1. Our first client to see the early results of the framework liked it and used it enough to have a lot of feedback for us.

2. Stephen, the product manager in charge of the first product, is currently busy writing a mini-application to test an optical drive. He doesn't complain much anymore. (I need to get him to complain more, actually. He's my only usability testing!)

3. Soumita, the only other programmer to actually dig into the framework so far, complains loudly. While I feel bad for her, making the internals simple wasn't one of my goals. I'm a bit worried now that it should have been, though.

To summarize, the UI of a framework isn't any different from the UI of an application. Use the same techniques to improve it. Above all, take the usability seriously. Frameworks are complicated and require significant investment to begin using them seriously. People will not do that if it's not easy to use.

Tools


You want to make your framework easy to use. You can do that by making a nice, clean API, or you can do it by making tools that allow users to ignore the ugly parts of your API. Both possibilities should be considered.

Boost and XAML are two frameworks that take this principle to opposite extremes. It's worth looking at both.

Boost has a wonderfully clean API. The tools that they've created suck. (Boost.Jam and BoostBook are horrific messes that make me cry.) The framework itself is a joy to use because you don't frequently touch their tools. This is a valid approach to framework design, but it's not the only approach.

Microsoft's XAML, for example, is the complete opposite. XAML is completely unreadable and extraordinarily difficult to use by itself. XAML data files are as readable as object files. However, Microsoft doesn't want you to use it by itself. They created a set of tools that let you completely bypass the XML obfuscation that XAML requires. The tools themselves are clean and easy to use. Again, this is a valid way to approach framework design.

I prefer something in between, though. Make sure there are some tools to help users deal with the worst parts of your framework. At the same time, make the framework itself clean. Solve all aspects of the usability problem using the most effective tool for the problem.

For my current project, I didn't have time to create any tools. However, I did manage to make a lot of the code that users create editable with CSS and XHTML tools. There are a lot of great tools for web development. All I had to do was enable my users to use these. The jury is still out on that decision, but I'm still optimistic.

This originally appeared on PC-Doctor's blog.

Friday, December 14, 2007

Interface Design: APIs as a User Interface

This article closely parallels Interface Design: World of Warcraft vs. Excel. In that article, I claim that UI designers can learn from game designers. Now I'm going to claim that library authors can learn from UI designers.

Library authors write code that is used by other programmers. Their interface is called their API, and, like a GUI, it is all the user has to see in order to use the product. An API doesn't look much like a GUI, of course. It is a highly specialized UI that can only be used by someone trained in their use.

Usability concerns are certainly important for APIs. If a programmer doesn't understand your API, then they will not be willing to use all of the features that you put into the library. They'll have bugs in the corners or the library that they thought they understood, too. Confusing APIs directly contribute to unreliable code and lower programmer productivity.

What can library authors learn from usability experts? This isn't as stupid a question as it sounds. Usability experts have figured out a lot about how human brains learn how to do things. Programmers have brains that work almost exactly like everyone else's brain. (I may get flamed for that sentence, but I'll warn you ahead of time that I can defend it.) There may be something worth learning.

Patterns


Patterns can help a lot. If I'm on a web page, my brain has been trained to try to click on underlined text. This is a valuable pattern that usability folks can use when they want users to click on some text. Likewise, programmers like patterns.

If I'm using a modern C++ library, and I want to get access to a collection of items, I'll try to grab an iterator range using functions called "begin" and "end". Once I get those iterators, I know exactly how to access the contents of the collection. My brain can then abbreviate a lot of different tasks as "this class acts like an STL collection". Suddenly, getting access to a collection in a library becomes easy.

Programmers have been trained to see and use a wide variety of patterns. Generally a framework will define the patterns that users will get trained on. Ruby on Rails, for example, trains users to get access to items referenced through foreign keys using the name of the table that you're trying to get to. You can write a rails library without doing this, but it's something extra that users of your library will have to learn. Instead of thinking "table A has a one to many relationship with table B", you're users will have to remember "table A has a one to many relationship with table B that can be accessed using another function name". It's more information that has to be remembered, and it's likely to be forgotten quickly.

Different users will understand different patterns. A usability engineer would tell you that you should understand your users. This means that you should understand what patterns your users can use easily and what you'll have to teach them. Your goal is to avoid teaching them.

Explorable Interfaces


Usability folks also like to create explorable interfaces. That is, they want to make it safe to try things out. My web browser does this by allowing me to hit the back button after I click on the wrong piece of underlined text. That's great for users since they get to explore the web without losing much time. Library authors can also try to do the same thing.

How can a library be safe to explore? There are a lot of different tricks that authors have used. A combination of multiple techniques is probably the best idea.

A good library for a compiled language will fail to compile when you try to use it incorrectly. It might even give you a clear error message when you do something wrong. An easy way to do this is to use type checking of function parameters. You can go a lot farther, though. For example, if one thing has to be done before another, then you could have the first thing return an object that has to be passed to the second thing. If the compiler helps a programmer figure out the library, they will be more willing to explore different parts of the library. To a usability engineer, the cost of trying something new is reduced.

Making it easy to write tests for your code can also make things easier to explore. Interpreted languages frequently use this as a substitute for the first technique, but it's useful for compiled languages as well.

Documentation is a great way to make a library easy to explore. If you can look up exactly what a function does, then it's a lot easier to use it correctly, and it becomes a lot easier to try new things out with the library.

Usability Testing?


I've never heard of anyone doing usability testing on their library, but it does happen accidentally. I frequently write libraries for use by programmers that I work with every day. If a library fulfills a real need, then those programmers will use it. They'll try to use it in ways that I didn't foresee, and I may have to modify my library to allow their new use. They might make some bugs that I didn't anticipate as well. In some cases, I can go back and change the API to make it more difficult to create those bugs.

This accidental usability testing is about as much as a typical library author might do. Could you do a real usability test? How might it work?

I can imagine telling a coworker to go through a simple use case for a new library. I could watch them try to figure out what's going on. Is it obvious that a mutex has to be held while you make a certain set of calls? Is the name of one of the functions unclear? Is the documentation incomplete somewhere? These are exactly the sorts of questions that usability testing should be able to uncover.

If a library had to be easy to use, this sounds like it would be the way to do it. I've never even heard of anyone trying it in an organized way. Is there a good reason for this, or are library designers just lazy?

This originally appeared on PC-Doctor's blog.

Monday, August 27, 2007

Google Web Toolkit: First Impressions

I've starting converting a complex web app from being purely JavaScript and browser plugin based to using the Google Web Toolkit for the JavaScript part of the project. See my previous blog post about this.

Unfortunately for me, this project is not high enough priority to play with it for long periods of time. However, I have managed to start work and get some basic functionality working. It was certainly interesting!

I'm going to comment on a few of my first impressions. I'll state a strong opinion now, but I reserve the right to change it completely as I get more experience with the library and tools.

Speaking of Tools...


Wow. This is really slick. You get to debug the Java code directly without looking at the JavaScript that it compiles to! Eclipse is a great editor for Java code, and GWT integrates nicely with it.

The debugger is nice, the compiled code looks good, and the warnings and errors that the development web server generates are extremely helpful. This is probably the strongest selling point for me with GWT.

Don't touch the DOM!


This was a shock to me. The web browser's DOM is an extremely efficient place to store information about the document you're displaying. A heck of a lot of effort has gone into making this efficient and safe. CSS is an extremely powerful tool that is closely coupled to the document's DOM.

GWT's designers don't want you to touch the DOM, though.

GWT gives programmers only limited abilities to write to the DOM, and they work extremely hard to make it difficult to read the DOM. For example, the DOM.setAttribute call can be used to assign a id attribute to an HTML tag. That sounds like a really useful call, doesn't it? I could use that to make it easy for our graphic artist to design some CSS to describe the appearance of the application. It's deprecated, though. You're not supposed to use it. :-(

GWT is not for documents.


I shouldn't be too harsh to GWT about the DOM, though. This might be obvious, but GWT is for complex, full featured applications that happen to reside in your web browser. It's not for displaying documents. There are some corners of the library that allow you to put HTML directly wherever you want to, and I suspect they work great. They should even work with an external CSS file.

An application is not a document, and I might be having trouble getting over that. I'll get back to you later when I form a stronger opinion.

Writing JavaScript directly?


If you want to do something that simply cannot be done through GWT, you're in luck. GWT has a JavaScript Native Interface that is analogous to Sun's JNI. It works great! I use it extensively to talk to my browser plugin, for example. It's easy to use, and it doesn't screw up the tools any more than they should be.

This, of course, allows you to create whatever back door you want to allow you to manipulate the DOM. However, until I get a better understanding of the GWT techniques, I'm going to try to do things the GWT way. I may have more to say on this subject later. ;-)
There are back doors to get there, but it's not a real GWT application if you rewrite their tools to do it your way. Instead, you do things the SWIG way.

GWT == SWIG


Yes, that's right. GWT has more in common with a SWIG application than a JavaScript/DOM/CSS application. Is that bad? It's certainly a great thing if you like SWIG. I don't have much experience with it, so I don't yet have a strong opinion.

However, I do think it's a great idea to emulate a well used framework instead of writing a completely new one. There are a lot of SWIG developers and ex-SWIG developers out there, and I'd guess that they'll feel pretty comfortable in this framework.

Documentation?


The documentation is fine, and I shouldn't complain about it. However, I could have really used this blog post before I'd started. If you start out as a native JavaScript/Prototype/Ruby on Rails developer like I did, then what I've said here is not completely obvious.

The Google group is great, though. I've gotten responses to my queries immediately.

This originally appeared on PC-Doctor's blog.