solidarity icon indicating copy to clipboard operation
solidarity copied to clipboard

Support Other Backend Languages

Open danielberkompas opened this issue 7 years ago • 2 comments

I recently wrote a similar project for Elixir. If we want to use solidarity for Elixir backend (or other) projects, there are some changes we would need to make.

As I see it, solidarity's core concept can be divided into three parts:

  1. Rule file
  2. Plugins
  3. Validator

Rule File

The config file format must be able to specify the following kinds of checks for backend projects:

  • [x] Existence of binary in $PATH
  • [x] Version of binary in $PATH
  • [x] Existence of ENV variable
  • [x] Existence of file at filesystem path
  • [ ] Conditional on ENV. Web environments require different checks in each environment. Checks must be able to be made conditional on ENV values.
    • For example, elasticsearch and Postgres are on separate hardware in production
    • The existing platform option is not a good fit for this, because we can't assume that dev environments will not be Linux.

Plugins

Plugins that generate configuration files (snapshots) for a given language or framework should be written in that language. There are several reasons for this.

  1. They can easily read their own, proprietary configuration.

    For example, if my solidarity-elixir plugin were written in Elixir, I could reliably determine which Elixir version to require in the .solidarity file.

    Mix.Project.get().project()[:elixir]
    "~> 1.5"
    

    If my solidarity-elixir plugin were not written in Elixir, I'd have to a) assume where the project config files are, (not always in the same place) and b) use an unreliable regex scan on the files, since I could not interpret them. In contrast, the Elixir app already knows all of this stuff when it boots.

  2. Idiomatic, tight integration. If my plugin is written in my target language, I can provide idiomatic features and interfaces for it that my target audience expect. (For example, mix or rake tasks for Elixir or Ruby developers) This will boost adoption.

    • This also allows plugins to provide native functions which users can call at runtime or when their app boots
  3. Easier plugin maintenance. The author of an Elixir or Ruby on Rails plugin already knows those languages and can most easily maintain a plugin in those languages. This will lead to higher adoption because you don't have to maintain javascript code in order to maintain a plugin.

Validator

Backend projects must run the validator at the following times:

  • [ ] Compile-time. Backend apps must fail to compile/deploy if the production server has invalid configuration. This prevents broken code from making it to production and embarrassing bugs.
  • [ ] Run-time. Configuration values can be removed at will from a backend server, without recompiling the code. Therefore, the validator must also run when the app boots. The app should still boot if configuration is invalid, but an error should be reported to Honeybadger, etc.

The validator must also have:

  • [ ] Zero runtime dependencies. We cannot assume the presence of the Node runtime for Elixir (or other) backend apps, because:
    • Not all Elixir apps use Node. Many are backend-only.
    • When Node is used, it is only used at compile-time, not run-time. (This is also true for Ruby on Rails)
    • Elixir (and other language devs) will resist adding the entire Node runtime to their dev/prod stack just so they can use solidarity. This will result in low-to-no adoption outside the javascript community.

Proposal

  • [ ] Rewrite the validator binary in a language that has zero runtime dependencies, with the following API:
    • solidarity [optional file]
      • Loads.solidarity file at designated location, if provided. Otherwise, assumes project root.
      • Parse file
      • Validate each configuration rule with a system command
      • Returns 0 if all successful
      • Returns 1 if one or more checks failed, printing a list of all failed checks
    • solidarity [optional file] --dry-run
      • Prints a list of the exact system commands that solidarity will use to validate configuration.
      • This will be useful for debugging.
      • Returns 0
    • solidarity merge [file a] [file b]
      • Mergesfile a, a solidarity config file, with file b, another solidarity config file.
      • Returns 0 if successful, removes file b
      • Returns 1 if failed, prints reason, leaves files in place
      • This allows plugins to generate their own solidarity file, which will then be merged into the main file for the project. Plugins only care about their own rules, and don't have to worry about merging them with the existing file.
        • Plugin runs, creates .solidarity-plugin-name file
        • Plugin calls solidarity merge, which merges changes and removes the plugin file.
    • solidarity --help
      • Displays help
      • Returns 0
    • solidarity --version
      • Returns the current version of solidarity
      • Returns 0
    • This API is very limited and simple, and should be easy to achieve in Go or Rust despite our team's limited familiarity with them.
  • [ ] Move existing snapshot and javascript-specific plugin functionality to a plugin: solidarity-javascript
  • [ ] Document how to make a plugin
    • When installed, each plugin would download the zero-dependencies solidarity binary from the main solidarity repo's releases
    • Each language would get to define its own snapshot extraction logic and functionality in its plugin, as described above.
    • Each plugin would be responsible to build its snapshot to .solidarity-plugin-name, and then call solidarity merge .solidarity .solidarity-plugin-name

danielberkompas avatar Oct 21 '17 13:10 danielberkompas

@GantMan and I talked about it, and a cause for some hesitation was that in rewriting the validator, we would lose access to the features provided by Gluegun. But I suggested that we could sacrifice those features in order to get the benefits of adoption and features of the target-language, as you mentioned above, @danielberkompas.

We would also be able to keep the Gluegun features for any JavaScript-based plugins by keeping the JS validator. It could either be included in the general validator, or moved to its own project and repo; I don't know which would make more sense.

I'm interested in helping out with this. Gant mentioned that GO would be an appropriate language for the validator, so I might go learn that after any further soon discussion.

morgandonze avatar Nov 10 '17 23:11 morgandonze

@danielberkompas Please, take a look https://github.com/iegik/solidarity-bash

iegik avatar Jun 01 '23 09:06 iegik