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.
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:
- Core: the core 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 core feature and the interface of the project. It therefore should contain the test suite of the 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 core 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 sometimes used:
- 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.