Do not assume that better skills, more intelligence, working harder, etc. automatically lead to a better result. Implement only what is required or used (i.e. lean development).
It should be known, why a project is created and under which conditions it will be dismantled.
The commit log is a program, that describes the development of the project. The semantic versioning is used as a default versioning format.
Prioritize a buildable and working project state at every point in the development. Prefer test driven development. Ensure that the project is build, tested and executed in different environments, in order to ensure, that the projects works.
Prefer that backwards compatibility is provided as good as planned.
Being able to easily migrate from an incorrect implementation to a correct one, is more important than creating a completely correct solution, that makes it hard to migrate to other solutions, when the requirements change .
If projects become big or mature enough, it should be considered to partition these into parts dedicated to certain overhaul aspects of the projects in relation to their environment. If projects are not big enough to be split up, it may help to consider every folder with source code as its own mini subproject, where the split is done implicitly:
- Implementation (Impl): the implementation contains the minimal implementation to get the project running.
- API: establishes a common vocabulary and interfaces of the project. It has the authority to define and verify every implementation feature and the interface of the project. It therefore should contain the test suite of the project.
-
Core: this part contains the Implementation and the API.
This is helpful, if a minimal implementation is required,
in order to have an API,
or if an API with a bundled minimal implementation is useful for bootstrapping purposes.
The shortest package path in Java for the project is its core component.
So
net.splitcells.gel
represents the core component of thenet.splitcells.gel
project, where asnet.splitcells.gel.api
is the API component of thenet.splitcells.gel
project. - Extension (Ext): Contains alternative implementations, plugins, extensions, etc. for the project.
- Environment (Env): contains things, that are relevant for the project, but has no direct relation or interaction to the API. This could be a Dockerfile describing the environment of the project.
- Documentation (Doc): Contains documentation, media files and such and may be especially useful for manuals. This may not be required, if the documentation is too specific to the other partitions, but may be extra helpful for manuals directed at the users and not the developers.
In C this project partitioning is a lot easier to be done efficiently, because of header files. In this case, complying implementations can be swapped at will.
In Java this is harder to be done efficiently, as it is impossible to declare static methods, without also stating the implementation at the same location as the declaration. This is important, as all factories are used via static methods. It is possible to retrieve the corresponding factory during each object creation dynamically from the environment, but this is not possible to be done when the best performance is to be achieved.
In order to achieve the best performance, the following can be done. Provide a static final boolean flag, that determines if the most performant code should be used. In every relevant static factory method, create an if branch, that uses the dynamic approach by default. In the non default case, a factory from an appropriate static field should be used instead. Initialize these static fields with null and keep these private. Initialize these static fields with real factories via a public static method, that allows the initialization to be done ones in order to omit invalid use cases.
Maybe the dynamic approach is fast enough, but in performance critical code tests should regularly be done, in order to detect, if the dynamic approach costs too much performance. It's also possible to only support the static approach for performance critical factories. Keep in mind, that both approaches need appropriate initialization functions.
Note, that the dynamic approach allows one to run multiple configurations with completely different factory configurations in one program with one class loader. Maybe this feature is worth the distinction, and maybe not. One of these 2 approaches are sometimes needed, in order to move code to the implementation project.
This project partitioning originally had another naming scheme, as originally the project partitioning was much more oriented towards access control, complexity management and security. Later it was adapted for software projects. The original project partitioning naming scheme is still used for projects, where access control, complexity management and security are more important, than the interface/language that is established by an software project:
- Core: contains the core subject.
- Merger: the merger establishes a common vocabulary and interface between the core and other project partitions.
- Sheath: contains the integration of the core to its environment.
- Environment: the environment contains all not integrated things.