16

I have a situation where I support what is functionally the same library in multiple languages. There are often constants that need to be shared between these (for example, json field name keys or error codes).

The way I currently do this is by having code defining the constants in each language.

The problem comes in maintenance. If I add a new error code, I need to update it in every library manually. While this is fine for a few it becomes tedious if I have say 5 sdks to update. It'd be nice to have a single source of truth for these too.

I've thought about some sort of config-like file but then it needs to be included in every deployed package which adds complexity to our build/release process.

Is there a better way to handle maintenance of constants which are shared between multiple languages?

4
  • Your approach is fine, enderland. I was trying to find a better solution to redefinition because a lot of times multiple clients consume APIs I program and there really is not an elegant solution. Constants redefinition is still the most straightforward.
    – Andy
    Aug 16, 2017 at 19:09
  • 5
    @DavidPacker no no no you are supposed to have a really elegant solution for me. Don't tell me this is the best there is! :-)
    – enderland
    Aug 16, 2017 at 19:10
  • 1
    I was questioning my choices but then realized that constants are meant to be constant. They are predicable because they are constant. By storing them in a JSON or any other generally parse-able format they aren't really constants anymore. A typical example in my work process is a notification object containing a type attribute for structure identification when transferring it across the wire. Having this, the mobile clients define only constants (types) they understand at the moment of the time and ignore any unknown types. Dynamic definition would cause a lot of problems.
    – Andy
    Aug 16, 2017 at 19:18
  • You need a table of tables that map to rows of constants from tables of languages.
    – johnny
    Aug 16, 2017 at 19:28

4 Answers 4

11

Although I think your current approach is probably the simplest and most straightforward, here are a couple alternative ideas:

  • Extract your constants (and perhaps models) to a different package that is cross-compiled to all your languages. You might be able to cross-compile the entire library, but that may come with a substantial amount of problems. Just cross-compiling constants should be simple enough that there won't be as many issues. You can publish your constants package and depend on it in your language-specific libraries. Haxe can probably do it. This approach is good because you'll still have compile-time checking (for compiled languages)
  • Store configuration in a central service. For example soap web services have the Web Service Description Language (WSDL) and REST services have Web Application Description Language (WADL) which describes the operations and messages of the service. There are also generic centralized configuration services like Spring Cloud Config
  • Config file. I know you've already suggested it, but I don't think it needs to complicate your build/release process very much. Put your config file in a separate build project (where you can version it). Publish the project to your all language specific package repositories (Maven, Nuget, NPM, etc.) then in your language-specific libraries you can depend on the package. This shouldn't be any more complex than having an additional project in your build pipeline.
  • As RubberDuck suggested, code generation is a good alternative to cross-compiling. You can generate constant definitions for each language using a common configuration.
1
  • 5
    @RubberDuck code generation sounds interesting (particularly for one of my tangential use cases, which already involves a code generator anyways).
    – enderland
    Aug 16, 2017 at 22:25
3

Great question! I have the same exact issue; my constants are essentially: what languages are supported in my applications, and additional information about those languages as they pertain to functionality in the app.

Unfortunately, the best thing I've found (as you have) is to simply redefine constants for each language, as you are currently doing (I know, you definitely wanted to hear that).

Obviously it feels wrong because it's the opposite of DRY (WET??). However, constants should change so infrequently that the 5-10 minutes of redefining them for each language does not really bother me. At the end of the day, small issues with some 'elegant' solution like shared config or code generation could take hours or days to resolve, so what is really gained? Added complexity with the risk of something going wrong that could take additional effort to fix is not something that I want to deal with.

Furthermore, if your application has so many constants that redefining them per language when you add or change them takes a significant amount of time, you might just have a more significant code smell to deal with and, at that point, you may want to turn to something more complex.

So in short, redefining them for each language has been my best solution, and I have yet to think of anything more DRY that wouldn't have more risk factor than I want to deal with.

One thing to definitely do, though, is to ensure that your constants are well documented in a generalized (and language agnostic) manner (we have a company documentarion repo with specs, miscellaneous docs, 'drawing board' docs, etc. where we keep this document). Also make sure you have mechanism(s) in place to keep their definitions in sync. That's about as big a problem with the duplication approach as you'll have, except for a small amount of psychological distress from intentional code duplication. But in the end, your constant changes should be very deliberate and infrequent, so synchronicity issues should be essentially nil.


I should also mention that over the years, I've seen multi-language ports of various libraries (too tired to remember what they are at the moment) written by the same group that invariably have constants defined in the languages themselves. No shared config, no code generation (except for Google API client libraries... but come on, Google has the resources to afford such complexity). So I think we've hit a brick wall on this one. Maybe someone will eventually come up with a library to deal with this problem ;)

1
0

Hopefully, the core of you library is written in one language, and the other libraries use FFI (https://en.wikipedia.org/wiki/Foreign_function_interface) to call to the core library. This would give you the central location to provide an api to publish the constants and definitions from. This way everything is self contained within the library. I am only mentioning this as it doesn't seem to be included in Samuel's response.

I think it really depends on how capable your user base is. Are the capable enough to be able to handle passing around an other config file? Are they capable to setup a new service? For the vast majority of users that I have supported, I would want everything to be self contained - this way the users would not have to think about it.

5
  • 1
    Hopefully, the core of you library is written in one language, and the other libraries use FFI Unfortunately we have libraries for both a web client and server code (in multiple languages) so... it'd be non-trivial to pull off (and probably a security vulnerability if we could in the web app to begin with).
    – enderland
    Aug 16, 2017 at 21:51
  • I would suggest that you improve your security, as I would never trust my users enough to keep configuration files secret. Aug 16, 2017 at 21:59
  • How do you deploy web applications which handle error codes? Or json field names? I'm confused by what you think I'm doing that is a security issue. Running arbitrary code on my client's machine is absolutely a security issue, allowing them to parse json from a server doesn't seem to be unless I'm missing something.
    – enderland
    Aug 16, 2017 at 22:02
  • I have worked at companies, who's basis for security were DOS style random number generators and seed values stored as constants. These tended to be fixed very quickly after they are pointed out. However, if you put the seed value out to the world, you would be giving away the key to the kingdom.Since your software seems to be primarily web based, keep the config in a JSON object and let each of the languages parse the same shared file. Aug 16, 2017 at 22:32
  • JSON field names probably doesn't and shouldn't need to be constant. What would be the chances that these field names would need to change, but you don't change the name of the constant itself? You're probably more likely to benefit from generating code to access entries, or using expression language like ObjectPath.
    – Lie Ryan
    Aug 17, 2017 at 3:59
0

I wrote a Python tool called Reconstant to solve this exact problem. I've written about it on Code Review Stack Exchange here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.