I am still an beginner/intermediate programmer at best so apologies if I misuse terminology.
I work with SCADA software for my job, specifically Ignition by Inductive Automation. It's made for rapid application development, and all you really need to know is that it's built upon java, so what I end up using in practice is jython 2.7.
The application I work on strictly a database CRUD application for tracking office paperwork, invoices, sales orders, etc. I realized after a while the structure of each of these forms is essentially the same set of steps, with slightly different implementations at different steps.
For creating a new invoice for instance, I get some data off the screen, I validate any values that might not be good (ex: a age that is negative) and throw an error if there is one, if not, I sanitize the data if needed (sometimes due to poor GUI design ie changing a string date to a date object), and then I run a named query with the parameters to make an insert inside of a db transaction (and running any other database queries that are related to the invoice inside the same db transaction in case something goes wrong I rollback). If everything was successful, I log a message to a history thread for the object, or if not, I log the error to a server and tell the user something went wrong.
Now some things, this abstract class (think this is the right term) Form takes care of a few things behind the scenes - it automatically figures out where the subclasses named queries should be - for invoices it will look in a folder called
forms/invoices for named queries called
delete for the appropriate actions. The Form class also has a generic way of running subclasses create/update/delete statements within a the database transaction, and I keep all error parsing inside the abstract class Form so that every subclasses handles db errors or validation errors the same way.
As an example, for creating a new record, this is what my Form class looks like
def create(self, newData): self.logger.info("running create") # Have to reset this here in case of multiple creates, don't want a false positive on the second item self.resetResults() self.newData = newData self.modifyNew() self.validateNew() self.sanitizeNew() self.inputDefaultValues() # Database transaction/error catching - but only on the top level if not self.middleOfTransaction: self.tryAndFailDBOperationGracefully("inserting") else: self._create() # TODO - decide - if we should even update the UI if there's an error after the db stuff. Leave for now self.updateUIAfterInsert()
Some of these things the user needs to implement if they want -
updateUIAfterInsert are all
pass in the
Form class and can be skipped if not used but otherwise should be implemented if you want them to run. Other things like
_create are all things subclasses should not overwrite.
So how can I document something like this, what is the right way to inform someone via a UML diagram that if you want to use my Form class, here's how it works, and here's what you need to do on your end to subclass it properly? Also related - is this Form object an abstract class or is it a Interface? I am confused about the difference.