There are times when you need to know that continuing a plan will not bear fruit. So it was with Paul and me as we shifted our focus from the TOCS game system onto the game client.
The Old Crux
Our software architecture is a homemade Web application framework called Crux (pronounced “croo”). I’ve mentioned it in previous posts (I think), so I don’t have to discuss its pedigree. Suffice it to say, however, that it’s a mighty big jump from design to implementation.
While the Brick Mill Games’ dice server and the TOCS game client prototype are based on Crux, Crux was never hardened, or “productized”. It was an ongoing mish-mash of working concepts that was difficult to implement. Quite a bit of it was also unfinished. There were code paths that seemed to support some interesting concepts, but that ultimately did nothing. As mentioned in other posts, it was something I had been kicking around while having lattes and pastries at Panera before work over a decade ago.
Its unfinished, undocumented nature, coupled with the loosely-defined TOCS game client API, made for a difficult collaborative working environment. Throw in the fact that it was being developed using languages that Paul had limited experience with, and our productivity ground to a halt. I felt that I couldn’t make necessary changes without shifting the ground under Paul’s feet. Paul was trying to come up to speed with both a language and an architecture whose principles existed only in my mind, some of which were unimplemented and/or had no working examples.
It was getting frustrating and progress was slowing to a trickle. (See also: day jobs, etc.)
After one of our recent scrum calls, we decided that we needed to change tack. Crux needed to be hardened and treated like its own packaged thing and the game client needed to be defined as a separate entity within its environment. I needed to define and finish what I had started years ago and Paul needed to work on something he could sink his teeth into.
Crux 1.5
The Crux framework is a Ruby-driven environment which uses other technologies as its foundation: Rackup, Phusion Passenger and Sinatra. Those technologies are used to bridge the gap between the hosting server and the HTTP protocol. Crux handles the actual service requests and returns the results as either a JSON string or as the contents of a file.
Those are the basics and that is the part that always worked. The biggest changes to Crux has to do with its code library organization and its ability to host multiple environments, called “arenas”, and host multiple “apps”.
Using Rackup’s URLMap class, multiple independent Ruby environments can be run tied to particular sub-URLs off the main domain. These become the Crux arenas, each capable of defining its own CORS access permissions. For example, the user authentication system may be accessed from any web site, but the TOCS services must be run from the game client URL. As service calls are URL-based, subdividing apps and other functionalities into their own access groups makes sense. Also, as service handler and manager code is loaded on an as-needed basis, each app’s arena can have access to its own private library of functionality, while also sharing other bits of functionality.
Under the new scheme, the Crux system libraries are in a folder called syslib. This code forms the fundamental Crux operating environment. Shared libraries are kept in a folder called slib. Some common, Crux-supplied code is installed in there. Other post-installation code that can be accessed by all of the arenas is held in there as well. An analogy would be the folder where DLLs or .so files are kept.
Each app can have private libraries in addition to shared libraries. These are kept in a folder named /lib/<app-name>. Library code contains all of the heavy-lifting logic to support the application’s services.
Finally, each app or functional group, simply called “groups”, will have its own set of three folders: services, contracts and specs. These files will be in folders named: services/<group-name>, contracts/<group-name>, specs/<group-name>. (For most apps, the group name will also be the app name.)
The specifications are the biggest improvements to the system. Whereas boilerplate service code and service contract code had to be hand-written and in sync with each other, the Crux specifications are now used as the “single source of truth” in the system. Each specification, when it is created or modified, will generate the service code and the contract code used by the system. Each code file will also contain codoc-aware documentation comments so that up-to-date documentation can be generated for the generated code files. The lack of a single source of truth for the service APIs was one of the biggest impediments to learning and developing services within the Crux system. To write the correct, proper Javascript code, you had to have access to server-based Ruby code. Now, it’ll be all generated and documented.
Another major improvement is the new authentication system. With Crux 1.5, user credentials are app-aware and app-based. Whereas previous credentials contained singular entries that supported both Crux administration and TOCS account privileges, now they are separated into their own security domains.
The final piece of the Crux system will be the new IMDE, or Integrated Management & Development Environment. It is an HTML/JS app that allows service developers to dynamically test their services, including gaining access to whatever database tables are required by the system. Eventually, a full-featured code editor will be added to allow for the creation and editing of service specifications and/or library code. That last piece is probably some months away.
As of this post, most of the rework has been completed and all of the dice service code has been refactored into Crux specifications and most of the heavy-lifting code has been organized into private service handlers and shared random number generator logic. It has all been tested and is working smoother than before.
The Great War
As great as Crux 1.5 will be to get the game client up and running, Paul has begun our first extensibility exercise with the TOCS system. Whereas TOCS currently supports WWII-era tactical modules, Paul is beginning to push the TOCS environment to an operational WWI-era setting. To that end, we are designing a double-blind division-level game for the WWI Western Front.
When we first started talking about TOCS being its own thing, vs its roots as an ASL campaign scenario factory, we had talked about the idea of being able to migrate the double-blind nature of the system to other scales and eras. When we made the crazy decision to pursue this project, a WWI operational game was the game I lusted after: massive armies lumbering forward into each other’s zones of influence with limited intelligence to guide them. Armies stealing a march on their opponent to avoid encirclement, or vice versa. Cavalry divisions marching ahead doing recon, only to have opposing cavalry block their movements. Units being pulled from one part of the front to appear at another part, under a newly formed Army command, seemingly out of thin air. No perfect birds-eye view of the strategic battlefield. No scripted “idiot rules”. Plan XVII could indeed work given the imperfect intelligence situation of the time. Or, perhaps, the French player has chosen an alternate, historical battle plan?
Paul is actively conducting research to build this type of game module, including keeping an eye on the needs of what a Franco-Prussian War module might look like.
Our Respective Sandboxes
Throughout this project, Paul and I have, at times, worked closely together and have worked in our own separate sandboxes. There seems to be an interesting pattern here. When it’s time to build and/or be creative, we each work separately, at home with our own unique work styles. When it’s time to bring it all together, and buff out the rough patches, we both can scrutinize the other’s work and make it better, forming it and integrating it into a coherent system.
We do still collaborate when we’re at our own drawing boards. It just occurs at a different pace. It allows us to each pursue different parts of this large project at our own speed and efficiency.
Right now, we’re back to our respective sandboxes and the excitement is building again.