Skip to content

Instantly share code, notes, and snippets.

@gferreira
Last active September 18, 2017 23:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gferreira/18b9af056a9d4319d207d5a6c7ee7b2c to your computer and use it in GitHub Desktop.
Save gferreira/18b9af056a9d4319d207d5a6c7ee7b2c to your computer and use it in GitHub Desktop.
partial transcription of presentation at Robothon 2012

Tal Leming: Building Apps

partial transcription of Robothon 2012 presentation

© Tal Leming

Defcon

Robofab was built as a scripting library. It was not built to be fast, it was built to be comfortable.

Defcon is built to be fast, it’s not built to be comfortable. It’s built to be the backbone of an application. There are several things that are built into it that you really have to know how to use to make it work right. It gives you a nice foundation to build an application on. It’s also extremely light-weight, so it doesn’t take much memory.

It has the standard objects that you’re used to in Robofab (Font, Info, Kerning, Groups etc). It has a couple of different ones. The objects that are part of it are really stripped-down; they are really basic. They don’t do much more than loading and saving, basic iteration, and things like observation. Rather than having all of these things burdened with all of my Metrics Machine behavior, Prepolator behavior, it’s just the basic behaviors built-in. The main idea was, I want to able to build my own special behavior for my applications on top of these things so that I wouldn’t have to deal with loading data and handling writing it back out into the UFO, so the base objects do that for me. In Metrics Machine I added kerning and groups – so I have Kerning and Group objects that do special things (all the behind-the-scenes stuff in the Group Editor is handled by the Groups object).

The way defcon works is: you subclass your base objects and you implement your own behavior, and you actually pass those to defcon and they get inserted into the font when the font is loaded. So you don’t have to manage the objects yourself. I used to manage separate kerning and group objects in earlier versions of Metrics Machine and it was trouble. This is a much cleaner system and it makes it pretty easy.

Observer Pattern

Those of you who know Computer Science, I am about to get this very wrong – I’m sorry. I’m gonna try to explain it the best I can. I’m a designer.

Defcon implements what is known as the Observer Pattern. The Observer Pattern is a distributed event-handling system in Computer Science. Basically, it makes communication between objects very clean and clear.

Metrics Machine is version 4, which means there were 3 versions that you never saw. And each one of those was a complete rewrite, which is a big no-no in Computer Science, but I did it anyway, four times. The way the earlier versions worked was like this:

[img]

In an application you have your interface. And you have your objects: a font, or kerning, or something like that. So the interface is showing the user what’s inside of the object. The way that I used to do things was, I had the interface talking directly to the object and the object talking directly to the interface. That makes sense when you have just two little arrows on screen, but when you start building a complex piece of software like Metrics Machine, you end up with something like this [img] and it quickly becomes very very difficult to change your interface or change your object, because each one knows about the internals of each other. And that’s very bad. You’re gonna hear me talk a lot about abstraction – I really like making things abstract between the objects and the interface, so that I can change the interface pretty quickly.

Defcon does something different. The Observer Pattern – Just taught me something about this, and it’s one of my favorite things ever in programming – you still have your base objects here: you have your interface, and you have your font, or your kerning, or whatever you want to represent. Another object gets added, and Just called it a Dispatcher when he explained it to me, so I still think of it as a dispatcher. What this does is, it allows the object to have a thing that talks to the outside world. so when the objects changes, it will talk to the dispatcher. Rather than the object talking to the interface directly, it tells this dispatcher.

The cool thing about this system is: the object doesn’t need to know about the outside world. It can do it’s own thing, you can have the code very clear and concise, and you don’t have to jump it off with calls to the interface. When the object changes, the dispatcher notifies the interface. The interface has already told the dispatcher “Hey, I want to know when the font changes” – then when the font does change, the dispatcher abstractly handles talking to the interface. The cool thing about this is, it can be a one-to-many relationship, so the dispatcher can inform different parts of the interface. So I have several windows, I have lots of views that you saw (line view, individual cells, things like that) – all of those subscribe to the dispatcher. And the cool thing is, when the font changes, those things automatically know and update themselves. And my object doesn’t need to know that there’s a window open, or the contents of the typing preview in MM, or anything like that.

Even better thing for me as a developer is, I can take away parts of the interface and nothing breaks. The people who beta-tested Metrics Machine can tell you that I frequently change the interface pretty dramatically. There were several things that were in the interface that I took out, because no one thought they were all that useful. And I was able to do it without having major trouble. In the past, if I tried to do that, it was a big problem and things would blow up, so I ended up with an interface which was pretty stuck and couldn’t be changed.

(I hope I got most of that right. It’s heavy stuff.)

Representations

This is something I came up with. I’m sure there’s a computer science term for it, I couldn’t find a particular pattern that it follows.

A representation is a way to describe a particular thing. In the case of defcon, that’s a glyph. A representation can be an image of a glyph, or it can be XML data that describes the glyph, or it can be anything you want. In Prepolator I use representations as a list of boolean values that represent the directions of contours. So it can be anything you want.

For the sake of simplicity, let’s think about it as an image. If you show images in an application – you don’t want to draw the glyph over and over and over again, each time the screen redraws, or each time something has moved in the interface, you don’t want to redraw – you want to cache it. In the old days I would build a cache like this [img], that held all of my images. When you have a cache system like this, what you have to do when the user changes a glyph – let’s say, our user has rotated the O – I have to take that image out of my cache, because it’s now out-of-date; I need to make a new version of the image; and I need to stick it back into the cache. That seems pretty simple, but when you’re dealing with a huge font and little images (the little cell views that you saw), big images (the typing preview images) – you’re dealing with lots of caches and it can become a lot of spaghetti code to keep those things in sync. And when things go out of sync, bad things happen, users get confused, and they get upset – rightfully so.

Defcon does representations differently. Rather than storing a cache yourself, the glyph object keeps its own cache, so the A has a cache, the O has a cache, everything has its own cache. You never actually talk to the cache directly, rather it’s inside of the glyph so you have to ask the glyph for something from the cache. The cache is not like before, where a cache would represent just images, and you would have another one to repsent just XML, and another one to represent whatever. The cache inside of the glyph saves whatever you want to save into it.

The way the system works is, you have to ask the glyph for a representation. So, say you want to ask it for the image: you ask it, and it sends it back. You may be wondering where the actual image comes from, and that’s a good question. It uses what is called a Factory: a factory is an abstract way to create a representation. You don’t need to give the factory to anything except to defcon. When you register with defcon, you give it your image factory, and say “this is how I want to make images” – that becomes available to all glyphs, so now you can ask all glyphs in all fonts “give me your image” and they automatically know how to make their own image. So the glyph goes into the factory and out comes the image at the end.

Now, the thing that is really nice about this system is, when I talked about keeping things in sync: Since the glyph manages its own cache, the glyph knows when it’s been changed; so, when it’s been changed, the representations are out of date, so it can go ahead and destroy all those representations automatically. So now the cache is empty. Rather than automatically refill the cache with the image, the XML and the list, it’s going to wait for you to ask for them again. And then give them back to you. Well, it will make the representation when you ask for it.

So, this actually makes it a really fast light-weight system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment