4

I've laid out my stuff in a DDD sort of way. There are Repositories to hold my objects, Services to add external functionality, etc.

However what's not clear is what's the best way to share these between controllers? In C#, I'd have a dependency injection framework, and a single instance for the server. Python, being duck typed, doesn't seem to have a need for much DI. However there's still the question of how to get shared objects, that will persist between requests.

So far I've been hanging them off my app object, but seems there should be a more elegant and standard way to do so.

I'm specifically asking about sharing objects that add behavior to the app and could be called upon in different places in the app, not about sharing or changing data between requests.

davidism
  • 121,510
  • 29
  • 395
  • 339
Mathieson
  • 1,698
  • 2
  • 17
  • 19
  • 1
    Do you have an example? – Pax Vobiscum Jul 11 '18 at 13:04
  • @PaxVobiscum - it's a small job service, with typed endpoints for creation request for clarity. Celery would be overkill here, and deployment of services such as it are non-trivial. For job DoFoo, there's an endpoint called /foo that accepts POST, and a payload of a FooJobRequest. It returns a JobStatus, with the ID of the job started. There's also a /jobs/{id} endpoint, that on GET will return the current status of the job (waiting, started, failed, complete, etc). For this to work, with an in-memory store, the same instance needs to be used by Foo to store the new job, and jobs – Mathieson Jul 16 '18 at 17:03

1 Answers1

4

The common way seems to be

  • initialise your objects in a single module
  • have all other modules import the same object from that module

eg define repositories.py

customer_repository = CustomerRepository(options)
...

and in service.py

from repositories import customer_repository
customer_repository.find(id==5)

In general imports are cached, so all the modules should import the same instance of the object. Regardless, since you're doing DDD, those objects should probably be stateless anyway.

You should never do this for shared data that will change, as global data is not thread safe in web applications. If you want to share data between requests, use a database or other external data store.

davidism
  • 121,510
  • 29
  • 395
  • 339
blue_note
  • 27,712
  • 9
  • 72
  • 90
  • Ahhhhh ok, that makes quite a bit of sense - for quick demo purposes I'm using an in-memory repository, and didn't want it recreated on each request. Having it in the module would take care of that, as it's basically a Repository factory in that case. – Mathieson Jul 11 '18 at 13:18
  • One clarification - would that be in the same file as the CustomerRepository definition, or in the module __init.py__ file for the Repositories module if I'm holding it there? – Mathieson Jul 11 '18 at 13:23
  • @Mathieson: not sure what you mean. The *instance* should be imported from the same module, so that it's guaranteed to be the same instance. Whether that instance is initialised in the same file as the class definition, or imports its class definition from another module, doesn't matter – blue_note Jul 11 '18 at 13:28
  • this is an odd case, as it doesn't use persistent data storage for the initial release. It's a feature that might be added quickly. One of the strengths of the repository pattern is to allow a very quick in-memory implementation of storage to exist as scaffolding until a permanent solution is more appropriate. – Mathieson Jul 16 '18 at 16:59
  • When initialising the CustomerRepository with `options`, if `options` needs some app config (e.g. location of data to fetch or something similar) is it a good practice to have an `init_app(app)` in repositories .py that can be called upon flask app initialization with the app object and initialise an instance of CustomerRepository which will then be imported by other modules? – Georgi Tenev Apr 17 '19 at 05:05