Working with hierarchies of packages

PID methodology allows to decompose your project into small packages. The basic structuring of a PID project follows the pattern shown in following image.

The goal is to separate functionalities into packages, and to define dependencies between packages whenever required (e.g. when the code of an application #ìnclude an header file of a library). The packages can be either:

  • native packages, directly developed with PID
  • external pakages, that are external project imported into PID using wrappers to make them behave quite like native packages.

Working with little packages rather than a big project that does everything has several advantages:

  • it limits the number of persons working at the same time on same git history, whose benefit it to limit conflicts.
  • their API being more limited, it is far simpler to maintain and to make it evolve while preserving version compatibility.
  • their reuse is increased as developers can just take the esssential functionalities they need without having to understand the whole complexity of a big project.

Generally with PID the structure of a project can be summed up like this:

  • external packages and platform configurations, defined using wrappers provide some of the base functionalities used in native packages.
  • native packages are used to implement higher level libraries, by defining dependencies to external packages and platform configurations.
  • final applications are developped in separated native packages that themselves define dependencies to native packages containing libraries and when required to external packages and platform configurations.

Finaly we get hierarchies of packages defining dependencies between themselves that can be represented as an acyclic graph like in previous figure. The basic meaning of a dependency between two packages A and B is: B uses functionalities defined in A.

A dependency can also have a slightly different meaning : B extends functionalities defined in A (see previous figure). This is for instance the situation you face when you want to define a software framework with extension points: such kind of projects’ base package(s) implement base functionalities for a given application domain, as well as a mechanism to provide new functionalities (using extensions packages) in order to adapt to various applications requirements. You can imagine for instance:

  • a package providing a core library with some specializable classes and extension packages providing libraries specializing those classes.
  • a package providing an application with some plugin mechanisms and extension packages providing plugins.

In PID those closely related packages should be organized in a common framework (a specific deployment unit used to regroup knowledge on related packages) to ease their common documentation and help users to know what are the available packages participating to the same logic (i.e. the same API or functionality). We often use this kind of pattern to organize our developments and improve the reuse of people work.

From PID internal mechanics perspective there is absolutely no difference between those two kind of dependencies, they work strictly the same. Indeed difference between usage and extension is pureley related to the internal semantics of developped packages and obviously PID does not care about semantics.

Isolating independent projects

When working with a PID workspace, developper have to understand that:

  • this is (as far as possible) an isolated development environment. The only side-effect in can have is to install system dependencies when using platform configuration requirements inside packages. Anyway for a same requirement the effect on the host workstation should always be the same thus avoiding conflict when using many workspaces.
  • inside the same workspace resolution is global: depending on what package you are building, dependencies resolution mechanism can modify the configuration (typically versions of dependencies in use) of many installed packages, or even rebuild packages if they currenlty use incompatible dependencies.

Most of time this is not a big problem as PID detects what to rebuild and generally what to adapt depending on the package your are currenlty building, so the final configuration of packages naturally converges to a global solution that satisfies all requirements of all packages. For instance if you have many final packages (typically those containing only final applications) they will most of time end to use same or compatible versions for their common dependencies.

However, sometimes there is simply no global solution due to the respective contraints of final packages. Practically PID will need to rebuild/reconfigure each of them before using it if you build another one just before. This is obviously a quite boring situation that probably means that they do not participate to the same global project, otherwise developpers would have take care to have compatible contraints.

The solution for this is quite simple: use another local workspace.

Using different workspaces so allows you to have isolated development environments. There is absolutely no restriction on the number of pid-workspace in use in your workstation. Also you can “share” any number of packages between workspaces: each workspace will contain its own deployment of a package so their resolution is completely independent from one workspace to another. If you do modifications on one package in one workspace (for instance you release a new package version) the only operation to get modification in other workspaces is to update this package in each of these workspaces. And the update may even be automatic if you change versions of dependencies.