After completely rewriting FRI from scratch (and renaming it Arcadia), I have decided to rewrite my other big project, Roomie. This absolutely needed to be done. Roomie had some good functionality, but I had hit the limit for its extensibility. Roomie’s engine was a monolithic blob of ugly code, with very little room to make it into a full scripting language with features like custom functions and if statements. My redesign of Roomie, which I call RoomieRemake for now, is completely expandable, is properly multithreaded, and has all of the potential to be a robust, featurefull scripting language. Just like Arcadia, I am proud to declare that RoomieRemake shares absolutely no code with its predecessor. Not even a single copy/pasted line of code! More on that in a bit, but first an end scenario:
I’m not sure why I instinctively personify computers as needy and with low self esteem, but anyway…
In rewriting Roomie, I built up the infrastructure in the core engine to allow me to easily add commands. In the old Roomie, I tried to organize commands’ code as best I could, but I still ended up with big files with lots of functions, and a hulking switch statement at the top.
Here is the switch statement for the Z-Wave commands code file:
There was also another junction point higher up the line that would decide which kind of command was being called. In RoomieRemake, I do things a bit more generically. Every command is represented by a class, which all derive from a “Command” class. That means I can just have this:
As I continue development I will optimize things like command selection, but the point here is that I don’t have a whole bunch of special cases for different kinds of commands. This is just part of the code that makes a command run, of course, but part of the redesign included breaking up functionality into neat, orderly bundles. The master list of commands is populated dynamically with reflection.
A big time-waster in the old Roomie was validating variables, so in my new approach that is all handled in the definition of a higher-level “Command” class, while subclasses of Command register what arguments they expect, their types, and even default values if applicable.
Here is the old code for the ZWave.PowerOn and ZWave.PowerOff commands. Look at all of the duplicate code. Several times after redesigns I would have to go and manually change many lines of very similar code.
Comparing that to the new approach, here is the ZWave.PowerOn command:
By the time the command class is actually defined, Command has been abstracted into ZWave command, which has been further abstracted to SingleZWaveDeviceControlCommand. Verbose, sure, but by the time I get to defining the command, I know that all of the validating of variables and finding of the device and connecting to the ZWave controller have already been taken care of. Plus, if I ever want to add functionality to a group of similar commands, I can just write in the code in a parent class’s definition. That’s inheritance and type safety at work.
You might have noticed that I didn’t include the whole method signature in the above screenshot. That’s because it’s reaaallly long. Some might see this as a disadvantage, but a big problem I had with the old Roomie is not having enough information to work with to make the proper decisions. Basic commands recieve as arguments the CommandInterpreter that is calling them, a Scope object that represents the nested scopes containing variables, and an XmlNode containing the original command XML. (Did you remember that RoomieScript is an XML based scripting language?)
That Z-Wave command was already really abstracted, with arguments defined in higher abstract classes, so here’s an example of a command that derives directly from Command:
Here the constructor calls a method defined in the Command class that defines an argument of type String. By the time Execute_Definition is called, the engine has already verified that the Text argument is specified. If there’s a problem, the engine reacts appropriately. The CommandInterpreter, which represents a thread, doesn’t care about all of these extensions to Comamnd, of course. It simply calls the selected command’s “Execute” method, which is concrete in the base Command class.
Finally, here’s a shot of the two Solution Explorer windows. On the left is the old Roomie, and on the right is RoomieRemake. You can see that in the remake, extra functionality is in other projects, which RoomieRemake hooks into as plugins at runtime. That way, anyone could write a pluggin for Roomie.
SO that’s what I’m working on. I hope to release this sometime in the near future. If you’re interested in testing, either Roomie or Arcadia, shoot me an email. If you think I’m a huge nerd, well you’re wrong. I’m more accurately a gigantic geek, but you could call me a dork anyway.