jfroelich / rss-reader

A simple Chrome extension for viewing RSS feeds
Other
10 stars 0 forks source link

Implement a services layer #817

Closed jfroelich closed 5 years ago

jfroelich commented 5 years ago

Return to when I tried to do this the first time. This will organize the modules in the src directory and lead to the way to creating the controller and view layers.

In MVC, the services layer sits between the model and controller layers. The services layer exposes higher level operations to the controller that otherwise do not fit well into the controller layer. The services layer encapsulates common operations that instruct how to operate on the model, and do things to the model that involve functionality that is not simply database operations. Some apps combine the model with services, and say the model is not simply data operations. Some apps combine services with the controller layer. I like the idea of an explicit layer.

jfroelich commented 5 years ago

always enjoy fowler: https://martinfowler.com/eaaDev/uiArchs.html

This is not the services layer concept however.

jfroelich commented 5 years ago

Several articles suggest that data sanitization and validation occurs at the service layer and not within the repository (database) layer itself. Right now i have that functionality located in the database layer. One idea is to create a database module within the service layer, that acts as an intermediary between higher layers and lower layers. In fact I did this at one point. Then, I would move all validation and sanitization out of the repository layer and into the service layer. Of course, one of the reasons I strayed away from this is because of how redundant it feels. It splits a single concern (e.g. create a new object in the database) into multiple modules, and that feels precisely like the wrong meaning of separation of concerns. At the same time, maybe it is the right meaning. I am on the fence.

Second to that, is the decision to broadcast messages from within the database layer. At one point I had a wrapper module higher up (and ideally in some kind of services layer) that added on this functionality to the database. That way the database focuses exclusively on its one concern of storing stuff, and there is no concern about how it notifies interested observers of changes. Note that my original implementation was complicated by the fact that I strongly coupled the observer implementation to BroadcastChannel. In fact, I should have strongly tied it to a Channel interface (protocol), of which BroadcastChannel is just one implementation. The smell that so concerns me is that BroadcastChannel is highly specific to the browser context, but I have this awkward motivation that the database module and the services layer should somehow not be specific to the extension context, and the ties to the extension context only come in at a higher layer.

Third, is basically what I am saying before, is that I think what I am revealing in this exploration is that I want a core set of functionality that is very clearly not extension context specific. And this is why I struggle so much with things like the module that takes care of notifications. That module needs to know how to open the view. That means it needs to use extension-specific code to do so. And things within the services layer are where calls to show a notification occur. That is the conundrum. One idea is to introduce an extension layer above the service layer. Anything that needs extension specific functionality has to go through this layer instead of directly accessing the services layer. Then, all extension-specific code gets moved out of the service layer and into this higher extension-context-specific layer. This example is a bit muddied because it is not even clear that notifications are extension-specific. They are browser-specific, but for the issue of needing to open the extension as a result of clicking on a notification.

jfroelich commented 5 years ago

Good description of service layer and separation of concerns: https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/models-data/validating-with-a-service-layer-cs

jfroelich commented 5 years ago

Similar concern is the resource-utils in the db. I think I should largely just deprecate the get-url, has-url, etc functions. Force things to work right on the data with no use of things that have extra knowledge. Then, think about how to abstract away the raw format of resource objects. Basically, have multiple formats. There is a format at the lower resource layer (the db or repository layer), and there is some kind of correlated-but-not-identical higher format. For example, perhaps an extreme one, the view should see a resource and get an object with a url property, even though this property is actually an array at the lower layer.

jfroelich commented 5 years ago

One issue with decoupling view from model entirely is related to the need for stateful transactions, e.g. to execute multiple transactions on the same connection, because connection overhead is too costly to abstract it away and do it per transaction.

jfroelich commented 5 years ago

Ok I think one step forward is to experiment again with the redundant db-service module in the services layer that wraps the db module in the db layer, and completely decouples the view from the db layer, and also then consider moving sanitization/validation and observer stuff out of db and into service. Also, know, other services would then rely on the wrapper module too, so basically nothing above the db layer except the db-wrapper-service knows about it. Still on the fence.

jfroelich commented 5 years ago

One idea: create feed-service and entry-service. both are actually backed at lower db layer by the same resource storage schema. but nothing stops me from abstracting away at a higher layer. particularly because i pretty much never ever query for both kinds of resources at the same time. this would obviate the need to call the generic get-resource method and pass in a resource type. it will create two methods for every one, but that actually seems fine, since i am already doing something similar with the type-specific logic that happens in the db layer. i could also do things like create-feed (which secretly calls create-resource properly).