Search code examples
cunit-testingdriverproject-management12factor

How to apply 12 Factor App to Linux driver developing?


I'm an engineer currently developing Linux kernel-mode drivers and user-mode drivers. When I came across the theory of 12 Factor App, there is a strong voice echoing around my brain "THIS IS THE FUTURE OF DEVELOPING!".

And I kept wondering how to apply this method to Linux KMD and UMD design and developing since this theory is much too web-app based (I'm a part-time open-source web developer).

Current Developing language: C

Current Testing automation: Custom Implemented Python testing framework (Progress based, NO unit test)

Please give me some suggestions on this. Thanks and appreciated in advance.


Solution

  • As with most development guidelines, there is a gap between the guideline and the enforcement.

    For example, in your "12 factor app" methodology, one of the factors is:

    1. Codebase - One codebase tracked in revision control, many deploys

    Which sounds great, and would really simplify things. Until you get to the point of utility libraries. You see, when you find you are reusing code across multiple projects, you probably want:

    • Independent build and release chains for the multiple projects.

    This could mean two codebases, but the above states one codebase (perhaps one per project, perhaps one per company. Let's assume one per company first, which is easy to see as non-ideal; because, you would have commits unrelated to a project in the project's commit history. Ok, one per project, more sensible; but, what if projects need to share code? Like the libraries that format their communications and control the send / receive protocols? Well, we could create a third "protocol library" so that we have revisioning around the protocol; but, that violates the "one codebase (per project)" because now you have two codebases comprising the single releasable item.

    The decisions here are not simple. The other approach is to copy the protocol code into both projects and keep them in sync by some other means.

    1. Dependencies - Explicitly declare and isolate dependencies

    It's a great idea; and, one that makes development easier in many ways. Again, just to illustrate how a great idea can suffer without clear guidelines on how to implement the idea, what do you do when you are using a library that doesn't attempt to isolate the dependencies the library uses? Many of the more complex libraries themselves depend on other libraries, and generally they clearly declare their dependencies, as do the libraries used by the libraries; however, sometimes the base, core libraries used by multiple projects (logging, configuration, etc) wind up being used at different release versions. The isolation occurred on a per-library basis, but not on a per-project basis. You could fix it, provided you wanted (or could) fork and clone the libraries, restructuring them to properly isolate their dependencies for overall coordination of version numbers; but, generally you will lack the time to work on other people's projects.

    In general, the advice under "12 factor app" methodology is good; but, it leaves you up to performing the work of translating the guidelines into development protocols. Enforcement then becomes a matter of interpertation, and the means of enforcement (as well as the interpertation) fall on you to implement.

    And some of the guidelines look dangerously over-simlpified:

    1. Concurrency - Scale out via the process model

    While this is an easier way to go, it's not how any single high performance web server works. They all use threading, thread pools, and other more complex constructs to avoid process switching. These constructs (which are admittedly harder to use) were created specifically due to the limitations of a traditional process model. After all, it's not common to launch a process per web request, nor would you generally "tune a program for better performance" by starting a second copy on the same machine. Certainly, there are architectures where this could work; but, so far these architectures haven't outperformed their competition.

    Between machines, I wholeheartedly agree. Process scalaing is the only way to go in a distrubuted environment; but, there's not much in this methodology that talks about distributed algorithms, or even distributed computing approaches; so, again it's another thing left up to the implementor.

    Finally, their process commentary seems really out-of-place for writing a command line tool. The push to daemonize things works really well for microservices; however, you can't microservice away even the clients. Eventually you'll have to write something that isn't "managed by systemd", due to starting execution and ending execution without having an always-on service.

    So, it's a good framework, which might not work for some things, even if it is excellent for many things; but, in my opinion, the tooling to enforce it would have to be built by the organization using it because the interpretations one organization might make could differ from another organization.