I entered this answer expecting to be strongly disapproving of this approach, but I'm surprised to say that this is not the worst approach, in the right context.
The problem with your question is that you haven't really elaborated on your scenario. There are several possibilities here that would argue pro/con this approach. Without that context, it's impossible to judge if this proposed approach is needlessly complex or whether it is justifiable because of the problem its absence would create.
The overall missing consideration in your explanation is the focus on having a single source of truth.
- These are 2 different applications written in 2 different languages
Having two different applications doesn't mean that they can't both depend on the same library. There are cases where it makes sense to ensure that two applications always remain consistent about some of their sources.
An example here is when writing a backend and frontend which communicate with each other using models. It makes a lot of sense to put these models in a library of their own so both applications can use it. This ensure that when one of the applications changes the model, those changes also impact the other application.
The models, and in your case the enum, would be a single source of truth; as opposed to having defined the same thing independently twice and being forced to remember to update one when you've updated the other.
If, however, in your case the enums are currently just coincidentally the same and it is possible that they will diverge in the future (i.e. a change in one application doesn't need to be propagated to the other application), then you are correct that immediately defining these enums separately is the right approach.
- Doing this creates a hidden dependency between these solutions and they will lose their "independence"
Well, yes, but in the scenarios where this approach is a good approach, that dependency would be by design.
"Independence" does not necessarily mean that they have no connection whatsoever. As an example, microservices have an independent lifecycle, as it is the main goal of having microservices; but this doesn't mean that a change in one microservice cannot possibly impact another. Ideally, you'd strive for backwards compatibility so that you are not immediately forced to change, but that doesn't mean that you would never have any reason to want to change it.
whether we should be sharing an enum that will go into the database
- The database should be the final source of truth regarding the up-to-date enum
- Even if Sqlite doesn't support enums, and we'll have to create many tables for all of our enums, it's not the point
I would advise against both storing an enum in the database (using it to enforce FK constraints, I assume), and at the same time relying on the enum in your codebase. This would mean you no longer have a single source of truth.
Enum values make sense when dealing with a closed set of values which don't change during your application's (single deploy) lifetime. The benefit of having enums is that you can avoid magic values when performing checks like if(o.Foo == MyEnum.MyValue)
.
A database "enum" (i.e. a table with simple PK/name fields) makes sense when you're dealing with an open set of values which can be changed during your application's (single deploy) lifetime, e.g. by the end users. However, the consequence of this is that your code can no longer rely on the existence of a specific value (as it can be changed), so you lose out on the ability to specifically reference a given enum in your codebase. A database "enum" is effectively data for the end user (not your code) to make sense of.
It doesn't make sense to do both at the same time, as this would mean that to keep them in sync, you would need to adjust and redeploy your application whenever someone changes the enum.
If your response to that is that there is no logic to ever update the database enum table; then what's the point of having it in the database to begin with? Since there is no way to update the enum (which implicitly also means you're sure there is no outside actor which could be changing these values in the database unbeknownst to you), then your codebase can clearly manage the values using the enum that was defined in the codebase.
If the goal of having the database enum is query optimization, this can be achieved by putting an index on the columns that contain an enum value (without needing an FK to some enum table).
At the very best, the only reason to also add an enum to the database would be if e.g. some external reporting tool needs access to the enum value names to generate its report. But in such a case, the use case for the database enum and the codebase enum is completely independent of one another. Your codebase doesn't use the database enum, and the reporting tool doesn't use the codebase enum.
If other parts of the database change, then we would have to update both solutions anyway.
See the previous point. If the database changes and your code needs to be redeployed because of it; then you're doing something wrong.
Complicates our (already complex) solution and build process even more
To be fair, I don't think I have enough experience on this kind of C++/C# interoperability and what is required to get it working.
I do agree that it takes some effort to write those ifdefs; but I also have to admit that it's a one-off. Once written, any future maintenance on the enum values can be done without even needing to read to adjust those ifdefs.
I also wonder if those ifdefs cannot be simplified using a templating tool that can generate the correct code files for you. It seems the following pseudocode would cover all your enum needs:
if (language is C#)
{
EnumKeyword = "public " + EnumKeyword;
EnumNamespace = EnumNamespace + "Managed";
}
If that is correct, then your enum files would only have to specify the C++ keyword and namespace, and the templating tool would be able to generate both a C# and a C++ compatible enum definition. If correct, this further simplifies the enum definition, while at the same time retaining your single source of truth (albeit behind some code generation, which can be automated).
Conclusion
Keeping a single source of truth is a very important tool in your belt as a developer if you intend to lower future maintenance cost and the possibility of introducing bugs by forgetting to keep things in sync.
The proposed approach, while clever, does in fact achieve a single source of truth. That can be a very good thing in the right context; and can justify the existence of that approach.
In that same vein, putting the enum also in the database would undo your single source of truth. Unless there is sufficient justification for it (e.g. that external reporting tool), it should be avoided.