On December 31, 1995, Calvin and Hobbes boarded their sled and took off into the blank canvas that to them was the stark white, freshly snow-covered scenery.
That’s not what this post is about. At least in part, it is, however, about endings. Just as that last comic strip Bill Watterson ever published.
In the fall of 1999, I discovered this fantastic little tool called Macromedia Flash 4. To cut a long and boring story short, the result was that instead of going to university, I immediately kicked off my career as a professional web developer in the advertising industry. While in hindsight, that claim of professionalism was bordering on the ridiculous in its utter optimism and naïveté, the good news is: it somehow worked and while I did start university a year later, it had to take a back seat to my main occupation.
Now, twelve years on, it seems like not that much has changed. Granted: I spent the last five years not only developing but also managing teams and doing conceptual work. Still, at the core of things, I am what I was all those years ago - a web developer.
As you might have guessed, though, the real changes are a bit more subtle. As time went on, I became more and more aware of two important facts: first, neither my talents nor my interests really lie in the frontend; second, twelve years of doing advertising is enough for a lifetime.
Don’t get me wrong: I don’t have any deeply-rooted problem with advertising in and of itself. I do, however, think that there’s a fundamental problem with projects in the advertising industry: they lack real stakeholders. Now I might be completely off the mark here, but that was my overarching impression in almost all the projects I was ever involved in and it makes a lot of sense to me, too: the companies you work for in advertising have their stakes in their products, not really in marketing them.
Whether I’m right about this doesn’t really matter, though: real or imagined, this gap I experience is enough of a problem for me that I want to change what I’m working on.
The other part of the equation is that I enjoy building systems, applications and frameworks, not microsites. The projects I enjoy the most are along the lines of Robotlegs, Swiftsuspenders and Reprise - an MVC framework, an IoC container and a CSS-based layout and components framework. Building a CMS abstraction layer to be used by the hundreds of agencies building modules and microsites for the NIVEA website was pretty neat, too.
For these reasons, I have decided to close my current business as the tech lead of a small team of sub-contractors to advertising agencies at year’s end.
As of January 2012, I will do some exploring of a blank canvas of my own and be available for bookings as a freelancing developer specialized in building systems, renderers and complex applications. I’m perfectly capable of doing and will do the occasional frontend programming if an otherwise perfect job requires it, but as said above, I strongly believe that my real talents lie a bit deeper down the stack. If that sounds like something your company could use and you’re either located in Germany or could include me working remotely then please do get in touch!
With the advent of Flash CS5, Adobe switched the format of .fla
files from the quirky binary format it was in previous editions to what every
self-respecting developer of document-creation tools uses nowadays: A
compressed archive consisting of an XML file (the actual document) and lots of
additional files.
This in itself would be pretty nice, what with enabling third-party tooling
and all. What I want to get at, though, is that they were nice enough to also
enable working with those same documents saved as an uncompressed folder:
Choosing Flash CS5 Uncompressed Document (*.XFL) as the file format
when saving a project causes a folder with the project’s name to be created.
Inside this folder is everything that would normally be contained in the
.fla:
The file DOMDocument.xml, which is the equivalent of the .fla file without any embedded assets or settings
The file PublishSettings.xml, which contains exactly what you think it does
The file MobileSettings.xml, which also contains exactly what you think it does
The file META-INF/metadata.xml, containing the documents’s creation and change history
The folder LIBRARY, which contains the documents library, neatly structured in the same way as your library itself, but with additional folders for binary assets, such as BMPs
The folder bin, which contains cached versions of the binary assets, pre-converted to their output representations as compiled into the published SWF
The beauty of this setup is that you can work with all these different files
just as you would with any other text or binary files: You can edit the XML
files in your editor of choice, replace images with newer versions you get
from your designer or use your diff and merge tools on them.
This last part is the most important to me: By replacing your .fla
files with XFL folders, you allow them to be version controlled in
a sane way. Instead of forcing your VCS to deal with incomprehensible blobs of
binary data, hoping that it will make the best of it, you allow it to live up
to all the hype about its efficiency and speed that caused you to use it in
the first place.
One last tip on that: Use whatever means your VCS provides to exclude the
*.dat files in the bin folder from versioning. They’re
really simple caches that get re-created if missing.
tl;dr:
Don’t use the Mario Mushroom Operator if you don’t want your setter to be
invoked more than once.
Update: I totally forgot to mention that I found out about this problem with @darscan while working on Swiftsuspenders and Robotlegs code.
The Details
I think it was @robpenner who coined the term
“Mario Mushroom Operator”.
In case you’re wondering, the Mario Mushroom Operator is this: ||=.
A good translation for how the MMO™ works seems to be this:
1
if(!field){field=value;}
In case you’re still wondering, here’s how you’d use it:
12
function useRuntimeDefault(input:Object):void{input||=getDefaultValue();}
I.e., the most important use-case for the MMO™ is to apply runtime-determined
default values for method arguments.
Now, that’s really useful and you might be wondering what could possibly go
wrong with that.
Consider this snipped of code:
123456
privatevar_setOnce:Boolean;privatevar_value:Object;publicfunctionsetvalue(value:Object):void{if(_setOnce){thrownewError('Value can only be set once');}_setOnce=true;_value=value;}publicfunctiongetvalue():Object{return_value;}
Used in a class, this code encapsulates a value that can be set exactly once,
after which it can only be read.
With me still? Splendid.
In fact, you’re probably already guessing what comes now: Using the MMO™ to
assign this once-settable value iff it hasn’t already been set:
1
value||={};
And here, finally, things go awry. As it turns out, the MMO™’s translation
given earlier isn’t quite correct. Instead, the compiler (or the VM, I haven’t
checked the bytecode) seems to translate our usage of the MMO™ to something
along the following lines:
1
field=field?field:{};
In summary, instead of guarding the assignment to a field as an if statement
would do, the MMO™ only chooses between two values to use in the assignment
like the ternary operator does.
In case you’re now thinking that that doesn’t affect you because you, just as
every sane person you know, don’t ever have use-cases for one-time assignable
fields, ask yourself whether you can be certain that all your setters are
side-effect free if you re-assign the same value and that you never, ever,
care about the overhead associated with double-setting values needlessly.
“Yes” and “yes”? Cool. “Mmh” and “not sure”: Weep with me.
I just released version 1.6 of my not-so-small-anymore IoC container
SwiftSuspenders. This
release marks the end of the line for 1.x-releases, all future development
work will go towards the all-new, shiny 2.0 release. Bug fixing will continue
as per usual, of course.
Small Changes?
Yes - in 1.6:
An easy but nevertheless significant performance optimizations for child injectors: Through a slight refactoring of the InjectionPoint class, I was able to make it fully independent from the injector that creates them, enabling them to be shared among all injectors in the VM instance. This allows them to be cached once, removing the significant performance overhead associated in inspecting classes to find injection points for all but the first injector.
Some usability improvements such as better error, warning and info messages on trying to instantiate interfaces, re-mapping previously mapped types and construction of dummy instances to work around Flash Player bugs.
Right, but Big Plans?
Indeed - for 2.0!
For the next major release, I plan to change things up quite a bit. The main
features on the roadmap are:
a much nicer API
factory mappings
field mappings
live injections
optional injections
weak mappings in child injectors
full live-cycle management with [PreDestroy] annotations
a new format for external, runtime-loadable definition of both injection points and type mappings
optionally shortening [Inject(name='name')] to [Inject('name')]
That sounds just swell, but I’d really like some details, please!
Of course you do!
The shiny new API
SwiftSuspenders’ API mainly consists of methods that facilitate the mapping of
types (and, optionally, names) to responses. Internally, this already is a
two-step process: First, an object is created that contains the request
configuration (i.e., the type and the optional name) and second, this request
is assigned a response of a certain type: A value, class, singleton or rule
mapping.
While 2.0 will ship with a façade to make porting from 1.x easy, the real
interface will expose this process as the two steps it really is. Look forward
to seeing mapping commands that look (approximately) like this:
12345678910
injector.map(YourClass);//current equivalent: injector.mapClass(YourClass, YourClass);injector.map(YourClass,'name');//current equivalent: injector.mapClass(YourClass, YourClass, 'name');injector.map(YourClass).to(YourClass);//equivalent to the first mapping (i.e.: optional)injector.map(YourClass,'name').to(YourClass);//equivalent to the second mapping (i.e.: optional)injector.map(YourInterface).toType(YourClass);//current equivalent: injector.mapClass(YourInterface, YourClass);injector.map(YourClass).asSingleton();//current equivalent: injector.mapSingleton(YourClass);injector.map(YourInterface).toType(YourClass).asSingleton();//current equivalent: injector.mapSingletonOf(YourInterface, YourClass);injector.map(YourInterface).toValue(value);//current equivalent: injector.mapValue(YourInterface, value);injector.map(YourInterface).toRule(otherRule);//current equivalent: injector.mapRule(YourInterface, otherRule);varrequest:InjectionRequest=injector.map(YourClass);//current equivalent: var request : InjectionConfig = injector.getMapping(YourClass);
Basically, the API will be somewhat more DSL-ish, without going all the way
into that direction, though: I like to think of it as bundling up all
parameters related to one concept in one method call: First everything related
to what gets mapped, then, optionally, to what it gets mapped and finally,
how its being mapped.
Additionally, the small rest of the API will be subject to some tweaks, I
suppose.
Factory mappings
I haven’t really gotten through the concept phase for these. The absolute
minimum is support for injector.map().toFactory() and
injector.map().toFactoryMethod(), but if I come up with some clever
mechanism for parameterizing specific injections, I would like to support that
as well.
Field mappings
In order to turn SwiftSuspenders into a light-weight one-way binding solution,
2.0 will support mapping of fields in objects with
injector.map().toField(fieldName, inObject). If the mapped field is
bindable, SwiftSuspenders will listen to its change events and update the
affected live injections:
Live injections
Now those are something I’m really looking forward to. By specifying the
live-parameter in your Inject-metadata (as in [Inject(live)]), you
basically create a one-way binding that updates the value as soon as the
associated mapping changes or, in the case of field mappings, the relevant
binding event is dispatched as described above.
Optional injections
These are exactly what you think they are. [Inject(optional)] will instruct
the injector not to throw an exception if it can’t find a mapping for the
requested type.
Weak mappings
Imagine you have a module that you want to test - or perhaps even deploy -
standalone but also want to load into a bigger application. Now this module
might have some configuration that’s different based on what context it gets
loaded into. If its loaded into another application, all or parts of the
configuration should be supplied by that application, but if its running
standalone, it has to deal with configuration all by itself. Enter weak
mappings: These instruct the injector to always ask its parent injector if it
has a mapping for the injection request. Only if that returns empty, the
weakly mapped value, in this case the module’s configuration, is used.
Tear-down with [PreDestroy]
Just as [Inject] is used to build object graphs, [PreDestroy] facilitates
tearing them down. When instructed to destroy a certain instance that it
created itself or that was injected into with injector.injectInto,
SwiftSuspenders will first go through all injection points in the instance and
destroy those recursively (if they are only used by this instance, not if they
are singleton or value mappings, of course) and the invoke all methods marked
with [PreDestroy] metadata.
This will probably be used to replace the currently hard-coded preRemove and
onRemove methods in Robotlegs mediators.
New runtime-loadable configuration format for injection points and mappings
The current XML-based configuration format was solely meant to work around
restrictions in the Flash CS* AS3 compiler which doesn’t support custom
metadata out of the box. This problem has since been worked around, rendering the format obsolete as it is right now. As
quite some people expressed interest in being able to mix hard-coded and
runtime-loaded configuration, I will try to come up with a good format for
that. For now, I don’t have anything in that direction, so we’ll see how that
goes. And if you want to define just such a format: Please do (and tell me
about it).
Standardization FTW
One thing I like about Robotlegs is how @darscan went to great lengths to
prevent as much lock-in as possible: Not only is the framework’s core
just a set of interfaces that
makes it easy to roll your own for each part, the framework specifically tries
to make as many parts of your application independent and even ignorant of its
existence as possible. Toward that end, Shaun started a metadata standardization effort with the
goal of getting as much agreement on the format of injection point-
configuration metadata as possible between the various IoC containers out
there.
And while I like to think of SwiftSuspenders (especially in its future
2.0-form) as being a pretty decent IoC container implementation, you should
definitely check out SmartyPants, Swiz, Dawn,
Spicelib and other IoC
containers if only out of interest. I’d also like for you to tell me of you
don’t like SwiftSuspenders or you think it’s missing some Very Important
Feature, though. Anyway, to allow you to switch from or to SwiftSuspenders as
painlessly as possible, I’ll implement as much of whatever everyone decides
upon as possible in 2.0 and future releases.
That’s quite a lot of work you just described. You really think you can handle all of it for 2.0?
Yeah, I know: This sounds like (and is) a lot. I’ll pack all of this up in the
form of a roadmap on the github wiki, prioritizing stuff and distributing it
across beta releases. Depending on when it makes sense to do a new major
release (which in turn depends on when we decide to release Robotlegs 2.0), I
might let one or two of the described features slip into 2.*.
But, some of these features already exist in forks other people published on github and which I was very bad at keeping up with. It is my hope that I can integrate much of these other great people’s hard work instead of doing much myself.
Update:@stray_and_ruby kindly made me aware of the fact that it isn’t entirely obvious what this post is about. I’m talking about a fairly obscure, but really handy usage of the Dictionary class: Implementing weak references to objects. @sunjammer recently posted about the Dictionary class in AS3. I agree with him: Dictionaries are awesome.
Unfortunately, they’re only nearly as great as he describes them because of
one little snag: Weak Dictionaries are only “weakly keyed”, not “weakly
valued”, meaning that assigning an object as a value creates a strong
reference to that object - even if that very same object is also used as the
key for the entry.
That’s especially unfortunate because it doesn’t allow for efficiently
implementing weak references with low overhead:
you have to use something with much more overhead:
1234567891011121314151617
package{importflash.utils.Dictionary;publicclassWeakReference{privateconst_referenceHolder:Dictionary=newDictionary(true);publicfunction WeakReference(target:*){_referenceHolder[target]=true;//every basic type works as the value}publicfunctiongettarget():*{for(varvalue:*in_referenceHolder)returnvalue;returnnull;}}}
On another note, I naturally had to google “awesomeness” and what do you
think ensued? Correct: Awesomeness! Specifically, the result contained,
besides lots of links to Barney Stinson and HIMYM in general, this fantastic service. I mean seriously: Who doesn’t
like to be reminded of being awesome? And if you ask me, $45 a month is dirt
cheap for that happening reliably and on a daily basis. (Just as the
providers of the service, I’m only half-joking, btw. I’m sure there are lots
of people out there whose life can be improved by such a service.)