Software applications are often complex systems. They usually consist of many parts, cover a number of abstractions, and require a deep understanding of the problem domain and terminology. And Qobrix is not an exception. In this section we will go over conventions and terminology used by Qobrix. Some of these we inherited from lower levels and underlying components. Some were borrowed from other projects and teams. And some – we came up with all by ourselves.
We are big fans of convention over configuration. While it takes a bit of time to learn CakePHP’s conventions, you save time in the long run. By following conventions, you get free functionality, and you liberate yourself from the maintenance nightmare of tracking config files. Conventions also make for a very uniform development experience, allowing other developers to jump in and help.
We follow CakePHP rules and practices, and try to extend the approach even further.
We develop Qobrix at an extremely fast pace (have a look at our Release Notes). So it is very important to have consistency in version names and meanings. Fortunately, we didn’t have to come up with our own scheme. Instead, we adopted Semantic Versioning. It is simple, scalable, and widely used. Here is the summary of what we adhere to:
Given a version number MAJOR.MINOR.PATCH, increment the:
- MAJOR version when you make incompatible API changes,
- MINOR version when you add functionality in a backwards-compatible manner, and
- PATCH version when you make backwards-compatible bug fixes.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
For our past, present, and foreseeable future needs, this is more than enough. In fact, we are not using additional labels at all.
On top of all those conventions we have a few of our own. Very few, in fact.
Configuration Over Implementation
We are big fans of the convention over configuration principles that CakePHP framework promotes. But Qobrix platform needs are often different from those of the CakePHP framework. So we extend the principle to, what we call, configuration over implementation. We try to provide configuration where it is possible to avoid coding. And we still try to provide conventions where it is possible to avoid configuration.
We assume that the development environment is always configured to run on HTTP, localhost, port 8000. During the development, we use PHP internal web server, which helps us to avoid complex and time-consuming configuration of virtual machines, web servers, and so on. It also simplifies collaboration on the same project for multiple developers. And, in case there is a need to do any find-and-replace on the files or database tables, there is no need to figure out which strings to look for.
Universally Unique Identifier
Another assumption that we make is that all identifier fields in the database are always using Universally Unique Identifier (UUID). Most database engines already have native support for UUID fields. And for those database engines that don’t, we utilize 36 character long string (
CHAR(36)). While UUIDs can be a tiny bit slower than incremental integers at times, they save a lot of headache when it comes to data migrations between different systems, environments, and versions.
DATETIME instead of TIMESTAMP
When working with MySQL / MariaDB, we always use
DATETIME field type instead of
TIMESTAMP field type. The reason behind this assumption is that MySQL has special handling for
TIMESTAMP fields. One part of this special handling is the timezone conversion, which can cause data inconsistencies and make troubleshooting so much more difficult:
MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval. (This does not occur for other types such as DATETIME.) By default, the current time zone for each connection is the server’s time. The time zone can be set on a per-connection basis. As long as the time zone setting remains constant, you get back the same value you store. If you store a TIMESTAMP value, and then change the time zone and retrieve the value, the retrieved value is different from the value you stored. This occurs because the same time zone was not used for conversion in both directions.
The second part of the special handling is the automatic initialization and updating for TIMESTAMP fields.
On top of the MySQL, CakePHP also has some logic when it comes to time stamps. In order to make Qobrix behavior more consistent and predictable (especially across multiple database engines), we decided to stick with the application level logic, rather than with the database level one.