I would say that using a class-based approach or a function-based approach (both using annotations) wouldn’t really be a huge difference since an app (either AppDaemon app or standalone app) could just instantiate the “app” object and use methods provided by it to speak/listen to Hermes (IOC can be achieved for both ways with a little more effort). But there is one problem: what will the framework use for communicating with the external world (MQTT/Hermes)?
A standalone app would need some connection infrastructure (by leveraging an event loop for example), a configuration file for connection parameters, and so on.
An AppDaemon app can leverage a running application server, so no need for anything.
This difference alone forces us to create two different entry points.
Personally I’d try to leverage existing framework(s) – I would not reinvent the wheel by writing another framework from scratch (i.e. if we want to use a “Flask approach”, we should use Flask for real) – that is, if that was your idea @koan and if I understood it correctly.
I also think that creating a framework that can be used in multiple environments (that is, that can be used interchangeably with another framework or application server without touching the app code) brings more complexity and effort than benefits. Think about the compromises we’ll have to make, the complexity we’ll have to handle to make the framework “behave well” in every environment. Also think about the conventions will have to impose on the app’s creator that wants to use e.g. Flask stuff or AppDaemon stuff correctly.
In conclusion IMHO this library should focus on integrating with 1 framework/application server/whatever environment it runs in, since the real “interface” for this library is the Hermes protocol.
As much as I am personally interested in using AppDaemon – as a Home Assistant user I find it extremely convenient – any framework/environment will do. If someone wants to use another framework/environment it will require a new library.
However…
Beware: brainstorming stuff that came out of my mind almost as it was. I was tempted to not include this paragraph, but I’ll leave it here for whatever discussion it might generate
If we really want to make a “general purpose” library, we could implement something like a core module that handles Hermes business logic, and then implement adapters that will make the library plug into other frameworks/application servers/environment. Those adapters would be in charge of publishing/subscribing to MQTT using the framework/environment they are supposed to interact with. An example workflow would be (I might be talking in AppDaemon terms, but I believe the same concepts can be applied to any framework/environment):
- The app would register to events using ways and methods provided by the library
- The library will use the adapter to implement that “listen to events” (the adapter will provide an interface for doing that) (*1)
- The adapter would listen to events by using the means provided by the enviroment
- The adapter will receive calls (service requests from the app or events from MQTT) that will be handled using business logic in the core module
- The core module will return something to the adapter (or signal it some how) that it handled the call
- The adapter will return the result to the app
A similar approach could be used for service requests (not event-based, think about service calls).
(*1) this part is where the library would scan for annotations and subscribes to topics accordingly, without actually knowing how, because the adapter would take care of it.
This seems an overengineered and overly complex design to me. Also I might have missed something because this is the result of a 30 minutes brainstorming. Or I might just be a bad designer but to me the simple fact that it seems to be very complex makes me think that maybe it’s not worth the effort (in relation to the benefits).