mardi 11 mai 2021

Design for a flexible centralized configuration object

I recently had to write a couple code libraries for a project where there were a series of applications to be written that interacted with a database that had no ORM (at least not in python) and an API.

The first library was a thin ORM layer that implemented basic SQL queries and functions over the database, with a few optimizations for our use case. The other a development kit for interacting with the API that also added a few optimizations and eased transforming data from the ORM library.

It quickly became apparent that I was reimplementing things for both libraries and the final application. Namely configuration, logging tools, and code to work with our other internal software.

I centralized this code and added it as a dependency to the libraries. To make the configuration of both libraries and the final application programable from the final application I created an "Application" object in the core module and imported it to both libraries where they could register their configurations on the "Application" objects class. That might look something like this:

# orm_library/config.py

from core import Application

Application.register(
    # configuration
    )

The final application then imports the "Application" object and instantiates it with a name and the environment variable to look to for configuration type ('dev', 'prod', 'test'). This is a required piece of boilerplate and will cause the application to fail if it is not present. It might look like this:

# final_application.py
from core import Application

Application(__name__, 'ENVIRONMENT_VARIABLE_NAME')

This is where my question comes in. I know requiring the Application object isn't all to different (on the surface) from how Flask handles configuration, but it stills seems tightly coupled. Given that both libraries and the final application are configurable and should be from the final application, are there any design patterns that would have improved the usability/maintainability of this code? Are there any common libraries that have done this particularly well (Flask was the only one that seemed relevant to me during this project)?

The final import flow goes looks something like this:


      |---→ ORM Library ----------------
      |                                ↓
core -|----------------------→ Final Application
      |                                ↑ 
      |---→ API Library-----------------

Aucun commentaire:

Enregistrer un commentaire