I’m trying to come up with some basic “principles” for the design of the next generation of our Theatre Management System. I want to call them “Commandments”, but I didn’t think that would fly with the other developers so much. Here’s what I have so far:
- Standards are good, even if they’re only draft standards
- We should use the SMPTE proposed standard ShowPlaylist and ShowSchedule instead of our proprietary mis-mash, even if we have to add kluges to the standard items to support our pre-show.
- Parsing XML is hard. Querying a database is easy.
- XML files should be parsed once, their information put in a database, AND THEN THE XML DELETED. If we need to send XML to another place (like for migration), the XML can be created on the fly, migrated, and then deleted again. One reason for this is that, for instance, you don’t want to keep dynamic things like ShowSchedules around, but want to generate them for just the auditoriums and date ranges that are being requested. The content library would be replaced by a simple program that waits for inotify events on a file drop-box, parses the XML, updates the database, fires an event and deletes the XML. The only long term file management would be for files that are opaque, trackfiles and KDMs and the like.
- Text should be translated at the GUI layer, not below it.
- This principle has been violated several times, which has lead to such stupidity as having to make sure the ContentPlayer configuration file knows what language the TMS is set to, and TWO language configuration parameters in certain config files. Next person to violate this principle gets an appointment with my boot. In TMS:TNG, any messages that originate anywhere but in the GUI will be a class that has a numeric error code and optionally some non-translated arguments (like file names, projector names, dates, times, etc), and they will be translated at the point of displaying to the user, not before. For convenience, the message class should have a “toString” method that will produce an English version of the message for logging, a “getMessageKey()” that will return the key that is used in the properties file, and “toFormattedString” that you can pass in the ResourceBundle and it will return a translated and formatted string.
- Databases aren’t the heavyweight horror that they used to be.
- We should seriously consider using a database on the FeaturePlayers as well as on the TMS, and doing the same sort of database content library replacement there as well. If not a full PostgresSQL, maybe a sqllite3 one? sqllite3 has one small flaw – it’s thread safe, but if there is a transaction updating a table, nobody can read the table until the transaction commits. I think we’re already doing the same thing with thread synchronization locks, so probably not a big deal.
- Anything that touches the database should signal an event to let everybody else know that it happened.
- We’ve actually done a pretty good job of this so far. I think there have been places where we haven’t send out events because we didn’t think anybody else cared, but it’s a mistake to think that this will always be the case.
- We’ve got too many config files.
- The proliferation of config files has been an upgrade nightmare. I’d like to see one or two config files for each machine, max. Does the CP really need 9 config files? That’s slightly crazy. One possibility would be to put the configuration into the database – we already have some configuration in the database, and a program that modifies that database table and sends an event to tell any interested parties to reload their configuration. If we did more of that, maybe we wouldn’t have to restart the whole system whenever the configuration changes.
- The GUI should be more separate from the actual “work”.
- I’d like to see the GUI separate from a daemon that does the actual content creation, scheduling, etc by a defined API, so that if we want to replace it with a different GUI (say, in JavaFX or AJAX or remote access or something new) we don’t have to rewrite the whole thing.
- Event handlers need to return quickly and not block.
- If your event handler needs to do anything time consuming, or if it’s going to make calls to another process, or fire its own events, then it MUST fire off a thread or add the activity to a queue and return quickly. Slow handling of events and/or doing too much in an event handler causes thread contention. One consequence of that is that if you cannot assume that just because you’ve sent an event, that everybody who subscribed to the event has finished dealing with it. For instance, if you send a “FEATURE_UPDATED” event, you can’t assume that all listeners are currently looking at the updated feature yet. Listeners that need to handle events in the order they come in should consider using an event processing queue rather than just spawning off threads.
- We should use database transactions.
- Currently, we run our database in auto-commit mode. In places where we put the database in an inconsistent mode, or where we wipe a table in order to repopulate it, we should use transactions so that other users will see the database in the pre-operation consistent mode until you finish the transaction. A good example of this is where ingestd wipes out the _available tables in order to repopulate them on restart – since the information in those tables before this process is hopefully not totally wrong, it would be better if other processes saw what was in those tables before until the repopulation is done.
- The current process of synchronizing things between the FPs and the TMS is horrible and should be replaced.
- We’ve spent way too many builds on this release trying to get this right. This shouldn’t be this hard. Throw it all away and build something else. I don’t have any brilliant plan for how to do that, but I think Kris made a pretty good start when he simplified a big chunk of it.