As I understand Entity caries fundamental properties, methods and validations. An User Entity would have name, DoB...email, verified, and what ever deemed 'core' to this project. For instance, one requires phone number while a complete different project would deem phone number as not necessary but mailing address is.
So then, moving out side of Entity layer, we have the Use-Case layer which depends on entity layer. I imagine this use-case as something slightly more flexible than entity. So this layer allows us to write additional logic and calculations while making use of existing entity or multiple entities.
But my first uncertainty lies whether use-case can create derived values(DoB => Age) from entity properties and even persist them in storage or does it need to already exist in User Entity class already ? Secondly, does use-case layer even NEED to use entity, could I have a use-case that literally just sums(a, b) and may or may not persist that in storage anyways? Thirdly, when persisting entity related properties into database, does retrieving them require once again validation, is this redundant and hurting performance?
Finally, the bigger quesetion is, what is use-case ? should use-case mean to be adaptable by being agnostic of where the inputs comes from and what it serves to? does this just mean the inversion dependency removes the responsibility of what framework it ties to. I.e. using express or Koa or plain http wouldn't force a rewrite of core logic . OR does it mean adaptable to something even greater? like whether it serves directly at the terminal-related applications or api request/response-like-applications via web server?
If its the latter, then it's confusing to me, because it has to be agnostic where it gets/goes, yet these outputs resembles the very medium they will deliver to. for instance, designing a restFUL api, a use case may be...
getUserPosts(userId, limit, offset). which will output a format best for web api consumers (that to me is the application logic right? for a specific application). And it's unlikely that I'll reuse the use-case getUserPost for a different requestor (some terminal interface that runs locally, which wants more detailed response), more or less. So to me i see it shines when the times comes to switch between application-specific framework like between express/koa/httprequest/connect for a restapi for the same application or node.js/bun environment to interact with the same terminal. Rather than all mightly one usecase that criss-cross any kind of application(webservice and terminal simultaneously or any other).
If it is allmighty, should use-case be designed with more generalized purpose? Make them take more configurable? like previously i could've add more parameters getUserPosts(userId, limit, offset, sideloadingConfig, expandedConfig, format: 'obj' | 'csv' | 'json' ), I suppose the forethought to anticipate different usage and scaling requires experience - unless this is where the open-close principle shines to make it ready to be expandable? Or is it just easier to make a separate use-case like getUserPostsWebServices and getUserPostsForLocal , getPremiumUsersPostsForWebServices - this makes sense to me, because now each use-case has its own constraints, it is not possible for WebServieces to reach anymore data fetch/manipulation than PostsForLocal or getPremiumUsersPostsForWebServices offers. and our reusability of WebServices does not tie to any webserver framework. I suppose this is where I would draw the line for use-case, but I'm inexperienced, and I don't know the answer to this.
I know this has been a regurgitation of my understanding rather than a concrete question, but it still points to the quesiton of what the boundary and defintion of use-case is in clean architecture. Thanks for reading, would anyone chime to clarify anything I said wrong?
But my first uncertainty lies whether use-case can create derived values(DoB => Age) from entity properties and even persist them in storage or does it need to already exist in User Entity class already ?
The age of a user is directly derived from the date of birth. I think the way it is calculated is the same between different applications. Thus it is an application agnostic logic and should be placed in the entity.
Defining a User.getAge method does not mean that it must be persisted. The entities in the clean architecture are business object that encapsulate application agnostic business rules.
The properties that are persisted is decided in the repository. Usually you only persist the basic properties, not derived. But if you need to query entities by derived properties they can be persisted too.
Persisting time dependent properties is a bit tricky, since they change as time goes by. E.g. if you persist a user's age and it is 17 at the time you persist it, it might be 18 a few days or eveh hours later. If you have a use case that searches for all users that are 18 to send them an email, you will not find all. Time dependent properties need a kind of heart beat use case that is triggered by a scheduler and just loads (streams) all entities and just persists them again. The repository will then persist the actual value of age and it can be found by other queries.
Secondly, does use-case layer even NEED to use entity, could I have a use-case that literally just sums(a, b) and may or may not persist that in storage anyways?
The use case layer usually uses entities. If you use case would be as simple as sum two numbers it must not use entities, but I guess this is a rare case.
Even very small use cases like sums(a, b) can require the use of entities, if there are rules on a and b. This can be very simple rules like a and b must be positive integer values. But even if there are no rules it can make sense to create entities, because if a and be are custom entities you can give them a name to emphasize that they belong to a critial business concept.
Thirdly, when persisting entity related properties into database, does retrieving them require once again validation, is this redundant and hurting performance?
Usually your application is the only client of the database. If so then your application ensures that only valid entities are stored to the database. Thus it is usually not required to validate them again.
Valid can be context dependent, e.g. if you have an entity named PostDraft it should be clear that a draft doesn't have the same validation rules then a PublishedPost.
Finally a note to the performance concerns. The first rule is measure don't guess. Write a simple test that creates, e.g. 1.000.000 entities, and validates them. Usually a database query and/or the network traffic, or I/O in common, are performance issues and not in memory computation. Of cource you can write code that uses weird loops that mess up performance, but often this is not the case.
Finally, the bigger quesetion is, what is use-case ? should use-case mean to be adaptable by being agnostic of where the inputs comes from and what it serves to? does this just mean the inversion dependency removes the responsibility of what framework it ties to. I.e. using express or Koa or plain http wouldn't force a rewrite of core logic . OR does it mean adaptable to something even greater? like whether it serves directly at the terminal-related applications or api request/response-like-applications via web server?
A use case is is an application dependent business logic. There are different reasons why the clean architecture (and also others like the hexagonal) make them independent of the I/O mechanism. One is that it is independent of frameworks. This makes them easy to test. If a use case would depend on an http controller or better said you implemented the use case in an http controller, e.g. a rest controller, it means that you need to start up an http server, open a socket, write the http request, read the http response, extract the data you need to test it. Even there are frameworks and tools that make such an test easy, these tools must finally start a server and this takes time. Tests that are slow are not executed often, are they? And tests are the basis for refactoring. If you don't have tests or the tests ran slow you do not execute them. If you do not execute them you do not refactor. So the code must rot.
In my opinion the testability is most import and decoupling use cases from any details, like uncle bob names the outer layers, increases the testability of use cases. Use cases are the heart of an application. That's why they should be easy testable and be protected from any dependency to details so that they do not need to be touched in case of a detail change.
If it is allmighty, should use-case be designed with more generalized purpose? Make them take more configurable? like previously i could've add more parameters getUserPosts(userId, limit, offset, sideloadingConfig, expandedConfig, format: 'obj' | 'csv' | 'json' )
I don't think so. Especially the sideloadingConfig, format like json or csv are not parameters for a use case. These parameters belong to a specific kind of frontend or better said to a specific kind of controllers. A use-case provides the raw business data. It is the responsibility of a controller or better a presenter to format them.
I'm working on a project that brings in a ton of data from one endpoint into a a single reducer. I'd like to convert that data in ES6 Classes, so I can give them helper method, provide relations between the data, and not have to work with plain javascript objects all the time. Also, to get relations between the data, I'm having to do n-squared computations and that's slowing down the frontend.
Here are the options I'm seeing:
1) Create a selector that connects with the redux store. This selector could get the data from the reducer and convert it into multiple ES6 classes that I've defined. If the reducer gets new data that is different, then the selector will recreate the ES6 class instantiations.
2) https://github.com/tommikaikkonen/redux-orm
This seems fantastic as well.
3) Create multiple selectors on the data set to that will compute a specified relation in the data set, so I can just call that selector each time I want to get a relation that would otherwise be an n-squared computation to get.
My question is which route of the three should I take? Is there an alternative besides these 3? Or do people just work with javascript objects mostly on the frontend and not deal with ES6 classes.
Update:
Two months later, and I'm still using Redux-ORM in production and it is fantastic! Highly recommend.
It's certainly entirely possible to do all that handling with "plain" functions and selectors. There's info on normalization in the Redux FAQ, and I have some articles on selectors and normalization as part of my React/Redux links list.
That said, I am a huge proponent of Redux-ORM. It's a fantastic tool for helping manage normalized/relational data in your Redux store. I use it for normalizing nested data, querying data, and updating that data immutably.
My Practical Redux blog post series includes two articles talking about Redux-ORM specifically: Redux-ORM Basics and Redux-ORM Concepts and Techniques. The latest post, Practical Redux Part 5: Loading and Displaying Data, shows Redux-ORM in action as well.
The author of Redux-ORM, Tommi Kaikkonen, actually just put up a beta of a major update to Redux-ORM that improves the API and behavior, which I'm looking forward to playing with.
I definitely recommend it!
Overall I'm happy with using Backbone.js for my company's frontend application. However I've noticed a lot of foundational problems that I wonder if anyone else encountered.
The biggest issue is that the frontend team does not control the API that powers our application. The objects passed are fairly complex in structure. Nested arrays, sub objects, etc.... This of itself is expected. The API serves a different purpose than the frontend. What each considers an "object" are completely different things.
In practice this leads to issues. Namely, one API endpoint may be broken into multiple frontend models. This is a common problem when dealing with APIs. It's typically addressed through Data Access Objects or a Data Access Layers that translate API objects into internal objects. Backbone by contrast expects models to be tightly coupled with the API endpoints. Sync operations on a model (i.e. save, fetch) immediately reach out to the API.
Adding to the issues, I seriously believe that toJSON in Backbone does too much. It's used to reproduce the model in a format that can be consumed internally; defines how the model should get posted to an API; and used for equality checks between models for many internal operations. Any of the three could get broken out into their own method.
Has anyone else dealt with this? What strategies did you use? Implement DAOs? Is there a fork of Backbone that accounts for these issues?
[edit]
A closer to real world case that I've encountered. When we query the API for results, there's about a hundred filters we can pass along with the request. The overall filter structure is pretty simple on that end an array of filter objects like so:
{
filterName: '',
// '~', '=', '<=', '>='
operator: '',
value: ''
}
For one particularly problematic filter, depending on the 'operator' we either allow the user to select a single option or we allow the user to construct a "sentence" from the available options. The former option renders as an HTML select, the latter we implemented with a lextree parser. Obviously the two necessitate wildly different code so we split this into two different classes, but to the API the filter is the same regardless of our implementation.
This is straightforward enough, but issues with Backbone come into how the classes are defined. We may want to make use of the built-in get/set functions. But this will dump properties into attributes, which affects the default toJSON which is also used to build the API representation of this filter, and whether this filter is equal to another filter of the same type.
With a Data Access pattern there'd be another layer that knew how to translate that filter to the API and vice versa. Any CRUD operation would get picked up by the specific DAO and processed by proxy.
Yes I know there is a plugin called Backbone-Relational but I have a serious problem with its fetchRelated function which, in my opinion, renders it useless for me.
So I was wondering if there are any alternatives? Or do we even need plugins like Backbone-Relational at all? How would you handle following scenario with pure Backbone:
Let's say we have two Backbone models: Company and Person. A Company instance can have many Persons. So company.get('employees') will return an array of Person IDs. If I want to get details of related employees, I'll have to iterate over the array and fetch() each of the Persons from server. But what if those Person instances have been already downloaded? Is there a clean way to make sure that there is no redundancy?
May be we can maintain a Collection for each model and dump every instance we download into it. Then we can download an instance only when it is not present in the Collection. But I think it will make code look horrible.
So please share your experience guys. Thanks!
As you suggested, I would give my Company model a Persons attribute. But you seem to forget collections also have a fetch method (as well as many other methods you'd find pretty useful, as the get method).
Also, as a last thing, I'd like to quote Backbone's doc (regarding the fetch method of Collections):
"Note that fetch should not be used to populate collections on page load — all models needed at load time should already be bootstrapped in to place. fetch is intended for lazily-loading models for interfaces that are not needed immediately: for example, documents with collections of notes that may be toggled open and closed."
Sorry if the question is vague but I am really having trouble finding information on this. I come from the Flex/ActionScript world where, for the most part, we have very simple Value Objects (VOs) to represent things like a User or an Address and we have Models that usually represented collections of those VOs along with business logic. There were some frameworks that would include a view model, MVVM. I know that there is no "right way" to do these things but I can't seem to point my finger on the basics.
Are all Backbone views supposed to have their own models? Given that I will likely not have a view called "User", would I also include domain models?
Would folders look something like this?
App
models
domain
User
Address
view
UserProfileModel
views
UserProfileView
collections
Users
Again, sorry if this doesn't make sense or is too general. I am just trying to get an idea of how far along the JS world has gotten in terms of MVC patterns. Thanks.
I don't think there is an only-one answer here. Every case will have an answer.
Are all Backbone views supposed to have their own models?
No.
There will be Views that will make reference to a Model, other ones will be making reference to a Collection. There will be also Views making reference to multiple Models, and others those will make reference to no-Model at all.
A View is an User Interface. It shows data to the User and listen to the events the User trigger on this data representation.
For example, if I have a Model called Friend and I want to create an interface to list a bunch of this Models I'll have:
FriendsView: which is a View that represents a Collection of Friends.
FriendView: which is a sub-View of FriendsView wich represent only one Friend. It can also listen to the click on the destroy button for this Friend.
But also I'll want to have a form to search from Friends in my server:
FriendSearchView: which not have reference to any Model or Collection. But is listening to the User filling an input field.
Would I also include domain models?
I don't know what do you mean with domain models but if you are asking about where to put the business logic Backbone is very agnostic about that. I recommend to put as much calculation as possible into the Models or Collections. Also you can use your own pure JS Util library.
Keep the Views clean. Only responding to User events and calling Model and Collection methods as needed. Also listening in changes in the Model or Collection from which it is showing the data.
How folders should look like?
Well, Backbone is again agnostic about this. There are a lot of literature about this.
My projects use to be small, less than 30 files. I put all of them in the same folder with a naming convection like this:
Friend
Friends
FriendView
FriednsView