Jump to: navigation, search

Design a Customizing


Revision as of 11:55, 26 July 2023 by NWE (Talk | contribs)

Customizing UBIK® is a complex endeavor. In this article, we aim to provide a guide and best practices making this task as straight-forward as possible.


[edit]

Strategy

It's important that development of your project is structured well in order to maximize the positive impact of every step you take. An unstructured project will lead to the frequent dismissal of invalid results, going back and forth unnecessarily, because things are done in the wrong order, ignoring the dependencies between tasks.

As a prerequisite for the rest of this article, please consider the following guide: Organize UBIK Development

Architecture

The architecture is something to consider on a rather abstract level, in the beginning of a project, but also on the level of a single task. In the context of a whole project, architecture means defining whether there are multiple UBIK® installations on different sites, what products will be involved and how they are connected topologically and semantically. On task level, architecture means defining which modules are taking care of what responsibility, and how they play together.

We recommend the top-level architecture to satisfy the following restrictions:

  • Network-distances between the database server and the application server (e.g., web services) should be minimal for performance reasons.
  • One should always plan for a staging strategy with multiple environments for QA.

We recommend the task-level architecture to satisfy the following restrictions:

  • Custom code should always be developed in a plugin where possible, with the UBIK® custom code just connecting the plugin code with the UBIK® objects.
  • Custom code should be arranged so heavy-duty processes (involving much data and complex calculations) are performed on powerful machines (and not on the mobile client).
  • Actually, all of the effort should be done on the server if possible, with the client just using out-of-the-box features. This won't be feasible in all cases, though.

Data Model

A good way to design a data model is to create an Entity-Relationship Diagram. It is recommended to do so in the scope of a Technical Design (see Requirement Supply Chain).

Object-oriented and relational

UBIK® is an object-oriented framework, so the data model should reflect entities of the customer's business processes (e.g., invoices and products), as so-called MetaClasses. One can use relations and references to create n:m and 1:n connections and dependencies between such entities (e.g., the relationships between invoices, invoice items and products). Properties with different data types can be modeled for every entity, and one such MetaClass can inherit the properties from another (e.g., there could be a MetaClass "SAFETY_INSTRUCTIONS" inheriting the "Filepath" property from a "DOCUMENT" MetaClass). An important aspect in data modelling, especially for the representation in relational databases, is normalization.

Basic data model

For a use-case to be satisfied with UBIK®, we should create a basic data model for the entities involved in the relevant customer's business processes, without respect to presentation in UBIK® first. This is because we need to rely on a correct and well-defined concept of the data on a fundamental level.

In contrast, a common mistake is to start designing the data model according to the workflow one is trying to customize. There are the following problems with that:

  • The data is not normalized correctly, because properties are not assigned to the "true" entity in the customer's process.
  • As a consequence, there is redundancy in the data and the data model is inconsistent with reality, leading to conceptual problems when using the data later.

Extended data model

The basic data model might not be very good for representation on the mobile application, because it would lead to mixing multiple different entities in the same view. This is a problem because it makes the UI customizing complex and prone to performance issues.

But, worry not. UBIK® is designed to provide views and transformations of a basic data model. So, we can create an extension of the original data model in a second design phase, where we provide a model tailored to the (mobile) use-case. This extension can happen on multiple levels:

  • A new layer of MetaClasses can be used to perform calculations on and combine more basic data.
  • A View can provide a custom hierarchy between instances using relations, queries and custom implementations of view-connections between objects (so-called ViewItems).
  • A Scope can define how to display objects on the mobile application, allowing for a custom representation in the UI.

Also, UBIK® comes with a lot of features one can apply to influence the behavior of (data on) the mobile client, ranging from inter-dependent tasks and work-packages to dynamic selective lists.

Algorithm

Most UBIK® projects have custom code performing more or less complex data processing tasks. The algorithm resulting from custom code can be highly distributed because of the way the life cycle of UBIK® objects can be customized. But it can also be a single interface with a third party system that has to crawl through a lot of data and perform many operations on them.

In any case, it pays off to get a good idea of the virtual processes resulting from the customizing for multiple reasons:

  • Algorithms can scale very badly if their time complexity is not considered.
  • Especially distributed algorithms can misbehave seriously and are very hard to maintain if they are not understood thoroughly.

These two reasons should be sufficient to invest a substantial amount of effort into making the algorithm:

  • Easy to understand
  • Scale well with respect to more input

There are also some quick hints we can drop for you to avoid many problems.

Custom code for MetaClasses:

  • Don't use the "OnSaved" event if you want to modify any object as a result of another object being saved. Use "OnPrepareForSave" instead, to avoid complex saving recursions.
  • Use a custom plugin to create a nice architecture for your code, using the life cycle events only to call it.

Parallelism:

  • Avoid multi-threading, but if you have to implement parallel tasks, use locking wisely to avoid dead-locks.
  • Keep in mind that multiple users could work on the same objects, i.e., your customizing can be executed in parallel, on different processes. This means you have to make sure your code doesn't interfere with itself. Mostly this is relevant for updating and reading from the database, where one process can update a value while another one is assuming a different value.

Performance:

  • Apply caching to reuse previously processed data and to avoid doing the same thing more than once, but clean up your cache if it becomes invalid.

Avoiding crashes:

  • Check every variable for being null before you use it.

Well-formed code:

  • Apply the principles of object-oriented programming (OOP) and the C# coding conventions.
  • For every responsibility in the code, there should be a dedicated software module. An optimal distribution of responsibility will often make your code perform better and easier to understand and maintain.
  • Give all variables, methods and classes really good and human readable names. Good naming and well-structured source code is better than any kind of comments.

UBIK® Features

We are working on improving the Wiki documentation for UBIK® features, to provide a better understanding of what to achieve with which existing feature. One way to find the best feature for your task (and how to use it) is to prompt a Large Language Model (LLM) chat AI, which will search our Wiki for you. You could start with a prompt of the form: "Search the UBIK Wiki for information on <what you want>." Try to use different formulations if necessary. If the information cannot be found on the Wiki, please don't hesitate to open a support ticket on the Augmensys support portal.

Mobile

For mobile features, it is important to consider some basic principles the client works by:

  • The navigation structure is based on the hierarchic relations between UBIK objects.
  • One UBIK object is the primary context of every page, and a list of its children can be accessed from there.
  • Showing multiple hierarchy levels of objects on the same page is most likely a performance killer and hard to maintain, too.
  • Every area of the application has a separate XAML file one can customize to adjust the layout.
  • There is a central Themes XAML file for adjustments that can be reused in multiple areas.
  • When designing a use-case, it is important to consider whether a feature must be available in offline mode, in online mode, or both; for offline use, the respective content must be made available on the device when there's the possibility (since it can't be fetched from the server on demand later).
  • The usage of out-of-the-box features is highly recommended and preferred over the development of new custom features.
  • New, custom features are problematic because of their need to be quality-assured, which is a lot of effort that was probably already invested for standard features.
  • For the same reason, when customizing an existing feature always use the latest standard XAMLs as a starting point.

See also