Last year I wrote about making sure you're editing the correct file. Now I have a similar topic.
It happened to me, that I was mentally expecting some value, so I was baffled why the code doesn't work. It was a numeric code, so it wasn't apparent that actually the code did what it supposed to do (duh!) and I was in fact expecting some other code, which wasn't the one I was getting.
Line number Ctrl+G, semicolon
Bookmarks
I came up with a method of “tags”, prefixed with a colon or two. That way it won't mix with variable or method/function names and will cycle through all there tags.
In the example below I have a function buttonSaveAction
, but because my mind goes first to "save" or "savebutton", I created a tags "savebutton" and also "create" and "update" for multiple things that can come to mind when looking for this particular function:
It won't mix with a line number, because this is a string. And because there can be multiple “saveXXX” tags, the major one is with double-colon prefix.
Past few years I've been struggling with a universal data model for Quid. I had it in my mind since Qedy PHP, but something didn't seem right. It was either too complex or not flexible enough.
The general idea is to have Objects as a “data spine” of the whole system, which would be referenceable from any module. Object is pretty much an empty shell, only with display name and validity dates.
Database queries are simpler, because I finally caved and put elem type also in the relation table, so I don't need to JOIN elems
table all the time (for most relations) anymore. It's only a CHAR(1), which made the decision much simpler for me.
Another big step was to include elem_elems
relations into the core itself. Previously I considered it just a helper information for stuff like suggesting right Objects in a particular autocomplete list. Also, this relation table got elem type, this time for the target elem only.
I don't use ORM, so I once again added my favorite debug option for SQL queries – adding a space character at the beginning of the query will print it (with variable names properly replaced by their values, of course), and adding second space will also prevent the query from executing, which is very helpful when debugging UPDATE or DELETE statements, because you can repeat them without any need to rollback data changes.
I figured out another way how to include module management, now as part of all installed “features” in the app, and once again I'm quite happy how it turned out to be. It's somewhat aside, yet important for the app to work properly, which is exactly what I wanted.
The biggest pain was, as usual, permissions. It took me several iterations to achieve what I wanted. Because testing was tedious and I often broke something by fixing something else, I had to write a simple testing method to include all five major groups (visitor, user, assistant, boss, admin) for both list and detail.
I failed to keep it simple, but to be fair, it's probably not possible. I opted for simpler data structure, but I had to create three separate queries for page data (for either list, detail or a new entry), plus two distinct queries for permissions, but ultimately it works just fine.
I also found another way how to deal with processes and even this one is quite as I wanted it to be, despite it's not ideal – I was forced to abuse class.order of the same elem to distinguish between state ''as'' Object and state ''in'' an Object.
I updated code for generating simple state diagrams in SVG and on top added support for multiple diagrams at once, because one Object can have multiple states (like a purchase could have a delivery status, insurance status and a payment status at the same time).
I used to have a method to test all the different SELECTs, but I rewrote it for practical use and created a simple app, that actually uses those database queries to display valid data. I can use it as an emergency app or backend API, with shared modules between them, and as a CORS proxy. The API will also come in handy, when I'll start implementing autocomplete features into the tool.
For unknown databases it can now also create a database and a directory structure for rapid app init, fetching all the specs from a central repository. I've decided to make it a “Swiss Army knife” of sort for Qedy apps. Because I suspect I'll use it for debugging a lot, there are several debugging features not just for the app (like logs or table contents), but for the tool itself as well.
Because of this, I worked on data import part. Now it can not only import data into selected table, but it can also analyse given dataset and assume the best data type for each column. For numbers it provides min and max value (to determine optimal type and possibility to be unsigned), for strings it finds shortest and longest text (decision: char × varchar + length) and it looks for empty values as well (allow NULLs).
For each column it creates an object with all the parameters, so if there's more than one type possible, it defaults to varchar. Like in the following example, showing gathered data for column `code`:
It also checks value count and for limited number of repeating values it offers it to be an enum (list of values). It stops adding new values after certain number of unique entries, because after that it's not going to be an enum and it would be just a waste of memory.
After I expanded it fairly, it now seems a bit too complex, but still manageable. There are queries with fair number of JOINs, but they do fair amount of stuff, so the “weight” is justified.
It looks like with this shot I may finally hit a bullseye, but only time will tell.
2024 Update: There are some wrinkles here and there, but generally it's IT!