Design pattern for reusable, context-specific model attributes - ruby-on-rails

In a complicated system you may have business logic related to what a user can see in a given context that you want to re-use across your system.
For example, amazon.com offers different prices to different users depending on a bunch of different rules. Those prices have to be shown consistently in search, product detail pages, email ads, etc.
If you're not yet at the place where it makes sense to extract out internal service APIs, where does this kind of user-specific model logic go in Rails-style MVC? It doesn't belong in the Model (requires too much context), but also doesn't belong in the Controller (needs to be re-used across many views in many controllers).
What are the leading design patterns for this type of problem?

I guess such complex decisions should introduce a ProductService into your system with some PricePipeline inside it. When any part of the system requests a list of products, passing some filters, ProductService fetches products from DB, instantiates PricePipeline manager and passes a list of products with their initial, DB-loaded prices to each member of PricePipeline manager.
Some caching is obviously required, but... that's another question, isn't it? ;)

Related

MVC app, where does this logic belong?

At work last week we had a meeting / presentation about rethinking how we do MVC, based on what's probably a lot of research by our boss and some reading into other SO questions. One takeaway for me was that when people say "separate logic from data" it would probably me more accurate to say "separate logic from your data source". If you do the first, you might fall prey to an anemic domain model. Am I correct in this?
Secondly we learned that MVC doesn't contain your business logic anywhere. This should be in a separate service layer or BLL apart from the web app. Reconciling these two points seems a bit tricky - does a particular piece of logic go with the data objects, as basic OOP principles dictate, or in a separate layer?
Here's a specific example that I need help with right now. I'm pretty convinced that this would belong in the service layer but I still have other questions. Let's say I have some behavior that takes as input multiple different entities of different types. It runs, and then as output, it can modify the input entities, and generate new entities as records. In my case it's for a game, but you could say it's like a transaction. There are multiple people involved, some products, and a receipt generated.
The easy question, where would you put this logic? Is it a separate class that gets instantiated?
The hard question (for me) is who is responsible for calling this code? It would feel wrong to have the controller do it. Or is that exactly its job? What if it doesn't get run on any one particular page, but whenever the user accesses the site after a particular time? Base controller?
In general, how do you decide between "this belongs in my entity class so that it isn't just a pile of getters and setters" and "this belongs in my service layer"? Or am I mixing things up... do the entity classes belong in the service layer?
Let's sort out some terminology first. What you're referring to as the "service layer" is more commonly called the "Domain model", as you say, not to be confused with a MVC model. At the most basic level, the MVC model encapsulates the domain model. How the two interact isn't defined by the pattern itself but the models store states the logical way is to realise there are two different states:
The domain state- in the real world this will more often than not be stored in a database somehow but the domain model should not expose any data source to the MVC model. This allows domain models to retain proper encapsulation. Any logic which mutates or accesses this data should be done here with relevant but abstract accessors for the MVC model to access.
The application state- that is things like "Which record is being edited at the moment?"
To answer your question it really depends on what you are doing with the data. If you're doing any kind of processing then this should be done in the domain model. If you're just fetching collections of data which are needed for display purposes then the MVC model should query the domain model(s) to retrieve the relevant data. The view should then inquire the model for this data.
So to answer your questions:
In thisspecific case: The transaction which processes the data should be inside the domain model. It has direct access to all the relevant data and should just be called with any required parameters. This promotes reusability because it's not directly tied to the MVC model.
Technically, if your controller is accessing the domain model directly it's closer to an MVVM implementation than an MVC one. However, this is not a bad thing, provided your domain models take arguments which aren't tied to domain logic there's not real issue. However a controller should not be constructing a domain object (e.g. creating a user account and passing it to the model). The reason for having the domain model which sits outside the MVC triad is for exactly that: So that it doesn't matter what calls the code, the domain logic is agnostic to the architecture it's running in. This is a good thing. MVC is presentaitonal, sometimes domain logic is just data processing. In regard to "whenever the user accesses the site after a particular time" this is domain logic so should certainly go in the domain model. Where depends on exactly what triggers the event, but in this case it could be part of the login routine or similar.
Indeed. The entities (by which I'm assuming you mean objects which refer to a single domain object, a user, a product, a blog, etc?) will probably not contain much logic themselves as they are mostly data structures. An order may have a "getProducts()" or "getDeliveryAddress()" which fetches related entities but the domain model would do any processing on the data itself.
As a rule of thumb, almost any logic that mutates data or processes data that comes from multiple entities should happen in the domain model. There are two main reasons for this: 1. Reusability, that logic can be reused from anywhere. 2. Encapsulation. Once you start putting this logic inside entities you end up with a situation where domain entities have dependencies on other domain entities. This leads to very brittle code in the real world as you end up with arbitrary rules being introduced at a later date such as "These customers don't have to enter payment details". "This is a corporate customer and they don't have a billing address" if you've modelled your "Order" class to be constructed with dependencies on a set or products a user and a billing address this becomes a larger task than dealing with that at an earlier stage in the domain model.

What is Business Logic?

Can the term business logic be used to describe:
account roles (admin, end-user, unregistered-user, moderator) that control what data is available to the end user?
If not, can someone give offer a term to describe the above situation, and correct me in exactly what business logic means? How does it differ from business rules? examples? Would you put the Business Logic Layer in the Controller in Rails/RoR?
What you are talking about is Role Based Access Control which is a type of business logic.
Business logic would be the operations that get carried out when Models calls are made. The business logic is in the model, not the controller.
Business Logic is the layer of your application where all the control statement of your application is written.
For example you have a simple application of Selling tickets online. Now when you are developing application you has some logic to be implemented for Selling tickets like date of booking should not be holiday. So this rule that you wont sale tickets for holiday is nothing but a Business logic.
For details see this site
http://en.wikipedia.org/wiki/Business_logic
The basic idea is to keep your controllers as thin as possible. Mostly that means that the controller accepts data from the network, and sets up variables needed in the view, and chooses the view.
The process of determining a role, an admin, etc, is a question to ask of a model... probably something like User, or Role, etc. The logic of how that is determined is in the models. The controller coordinates with this information to select a view or redirect if not allowed, etc.
Sometimes I find myself in a controller, doing a complex query to get a certain set of records. That's a code smell that I need to take that query and make a scope or a method in a model somewhere.
If you find yourself chaining a lot of calls on a model, it's probably time to move it to the model. If you find yourself opening up a lot of records, making decisions, and updating records, it's probably time to move to model.
If it's needed to decide what view to show the user (or whether to show it!), the controller is just fine.
Business Logic to me means anything particular about the business processes that you need to implement in Ruby.
For example, if you have a site where people purchase tickets, you might have a business process that says, "A user can only buy one ticket, until the day of the event, after which he can buy up to 5, if tickets are still available". So you have to write that up in Ruby - it's Ruby code that is implementing a business rule.
In contrast, in the same system, you might have code that splits out a ticket as a PDF. I wouldn't consider that "business logic", because it's not a business workflow rule... yes there's business value in printing tickets as PDF, but it's not about the workflow of how the business processes work (or should work) to enable it to serve its customers better.
Where as that rule about buying only 1 ticket? That's a policy of this particular business, a business rule.
Your example, as #Vinnyq12 pointed out, is more of a Access Control description... which you could say might be a type of business logic, yes.

Designing a reports controller Rails

I am designing a controller for reports. There will be about 10 different reports such as:
Courses Allocated
Courses Assigned
Logins
..etc..
Should I create a controller "reports" that would have urls such as:
/reports/courses_allocated?course=abc&start_date=2001-01-01&end_date=2011-01-01
/reports/courses_assigned?course=abc&start_date=2001-01-01&end_date=2011-01-01
There will also be ajax actions that will return data such as get_courses_by_category. (Should this ajax action have it own method, since it has to do with reports, or should this be part of the courses controller)
I am just looking for recommendations on how to design a report system which is mostly just complex sql queries that generate graphs in highcharts (Ajax loaded data) and tabular data.
Reporting is annoying, with that in mind you should spend as little time as possible on it. I recommend using searchlogic for make your models easier to query, it'll save you writing all the plumbing from your query string -> sql query.
Another thing that's worth thinking about is that your query roots will most likely be scopes, so if you were to have (for example):
/courses/allocated
That would (maybe) map to Course.allocated.
You could have a report controller, there's certainly nothing wrong with doing that, but I personally like to model my reporting around my existing controllers.
I have been thinking about this problem as well and concluded that for a situation where you have reporting associated with multiple models but following similar patterns a reports controller and perhaps generic code in lib makes sense. Reports have needs that are more common to themselves than they are to the models upon which they depend, for example: sort, search, filter, and then charting, exporting to files, permissions, etc.
My rationale is that when designing an application, you should think about it as an API, even if that's not how you are using it. Good APIs are consistent and predictable, and in effect this is what the controllers provide. Simple RESTful CRUD actions (generally speaking) belong in controllers associated with models.
Reporting is different, partly because it tends to cross models, and partly because there are different patterns and are likely to grow over time. For example, we have a report for our business partners that brings together payments, users accounts, and products in a single report; other reports provide a roll-up of metrics across multiple models. Reporting is its own thing.

Where does the "business logic layer" fit in to an MVC application?

First, before anyone screams dupe, I had a hard time summarizing it in a simple title. Another title might have been "What is the difference between a domain model and MVC model?" or "What is a model?"
Conceptually, I understand a Model to be the data used by the views and controller. Beyond that, there seems to be a great deal of differing opinions on what makes up the model. What's a domain model, versus an app model, vs a view model, vs a service model, etc..
For example, in a recent question I asked about the repository pattern, I was told point blank that the repository is part of the model. However, I have read other opinions that the model should be seperated from the persistence model and the business logic layer. After all, isn't the Repository pattern supposed to decouple the concrete persistence method from the model? Other people say there is a difference between the Domain model and the MVC model.
Let's take a simple example. The AccountController that is included with the MVC default project. I've read several opinions that the Account code included is of poor design, violates SRP, etc.. etc.. If one were to design a "proper" Membership model for an MVC application, what would that be?
How would you seperate the ASP.NET services (Membership provider, role provider, etc..) from the model? Or would you at all?
The way I see it, the model should be "pure", perhaps with validation logic.. but should be seperate from business rules (other than validation). For example, let's say you have a business rule that says someone must be emailed when a new account is created. That doesn't really belong in the model in my view. So where does it belong?
Anyone care to shed any light on this issue?
The way I have done it - and I'm not saying it is right or wrong, is to have my View and then a model that applies to my view. This model only has what is relevant to my view - including data annotations and validation rules. The controller only houses logic for building the model. I have a service layer which houses all business logic. My controllers call my service layer. Beyond that is my repository layer.
My domain objects are housed separately (in their own project, actually). They have their own data annotations and validation rules. My repository validates the objects in my domain before saving them into the database. Because every object in my domain inherits from a base class which has validation built in, my repository is generic and validates everything (and requires it inherits from the base class).
You might think that having two sets of models is duplication of code, and it is to an extent. But, there are perfectly reasonable instances where the domain object is not appropriate for the view.
Case in point is when working with credit cards - I have to require a cvv when processing a payment, but I cannot store the cvv (it is a $50,000 fine to do so). But, I also want you to be able to edit your credit card - change of address, name, or expiration date. But you aren't going to give me the number or the cvv when editing it, and I certainly am not going to put your credit card number in plain text on the page. My domain has these values required for saving a new credit card because you give them to me, but my edit model doesn't even include the card number or cvv.
Another benefit to so many layers is that if architected correctly, you can use structuremap or another IoC container and swap out pieces without detrimentally affecting your application.
In my opinion, controller code should only be code targeted at the view. Show this, hide that, etc. The service layer should house the business logic for your app. I like having all of it in one place so it's easy to change or tweak a business rule. The repository layer should be relatively dumb - devoid of business logic and only query your data and return your domain objects. By separating the view models from the domain model, you have much more flexibility when it comes to custom validation rules. It also means you don't have to dump every piece of data into your view in hidden fields and push it back and forth between the client and server (or rebuild it on the backend). Your view model will then house only the information relevant to the view - and it can be customized to have bools for view logic or counts or enums so that the view itself isn't cluttered up with complicated logic statements like
<% if (!String.IsNullOrEmpty(Model.SomeObject.SomeProperty) &&
Model.SomeObject.SomeInt == 3 && ...) { %>
While everything seems spread out and over-layered, it has a purpose for being architected this way. Is it perfect? not really. But I do prefer it to some past designs of calling repositories from the controller and having business logic mixed in the controller, repository, and model.
I too often wondered how exactly the MVC elements fit in a traditional web application structure, where you have views (pages), controllers, services, and data objects (model). As you said, there are many versions of that.
I believe the confusion exists because of the above stated, widely accepted architecture, which uses the "anemic domain model" (alleged)-anti pattern. I won't go into much details about the "anti-patternness" of anemic data model (you can look at an effort of mine to explain things here (Java-based, but relevant for any language)). But in short, it means that our model holds only data, and business logic is placed in services/managers.
But let's assume we have domain driven architecture, and our domain objects are the way they are expected to be - having both state and business logic. And in this domain-driven perspective things come into place:
the view is the UI
the controller gathers the inputs of the UI, invokes methods on the model, and sends back a response to the UI
the model is our business components - holding the data, but also having business logic.
I guess that answers your main questions. Things get complicated when we add some more layers, like the repository layer. It is often suggested that it should be invoked by the business logic placed in the model (and hence each domain object has a reference to a repository). In the article of mine that I linked I argue that this is not quite a best practice. And that in fact it is not a bad thing to have a service layer. By the way, domain-driven design does not exclude the service layer, but it is supposed to be 'thin', and only coordinating domain objects (so no business logic there).
For the anemic data model paradigm, which is widely adopted (for good or for bad), the model would be both the service layer and your data objects.
In my opinion,
Model -
Should not contain business logic, it should be pluggable(WCF like scenario). It is used to bind to view so, it should have properties.
Business Logic -
It should be placed at "Domain Services Layer", it is separate layer altogether.
Also, will add one more layer here "Application Services".
App Services talks to Domain Services layer to apply business logic and then lastly return the Model.
So,
Controller will ask Application Service for Model and the flow will go like,
Controller->Application Services(using domain services)->Model
The MVC pattern and the Asp.net framework makes no distinction on what the Model should be.
MS's own examples include persistence classes in the model. Your question about membership being in the model. This depends. Are classes in your model owned by something? Is there a link between who logs in and what data is displayed? Is there filtering of data part of a permissions system that is editable? Is who last updated or edited an object part of your domain as in somebody else needs to see it or something for backend support?
The email example is also it depends. Are you familiar with domain eventing or eventing in particular? Do you have a separate service to send emails? Is the act of sending an email part of your domain or is it a application level concern outside of the scope of your system? Does the UI need to know if an email was sent successfully or not? Do emails that fail to send need retries? Does the content of the email sent need to be stored for support or customer service requirements?
These types of questions are overly broad and subjective but I'm answering so you and everybody who voted you up can understand this.
Your requirements/timelines/resources all bleed into your system's architecture. Even the revenue model can have an effect. You also have to consider the pattern you are shooting for. DDD is much different than persistence-as-model applications and all the slop in between are also valid for certain apps. Are you shooting for testing the app? All of this has an effect.

DDD principlers and ASP.NET MVC project design

Two part questions
I have a product aggregate that has;
Prices
PackagingOptions
ProductDescriptions
ProductImages
etc
I have modeled one product repository and did not create individual repositories for any of the child classes. All db operations are handled through product repository.
Am I understanding the DDD concept correctly so far? Sometimes the question comes to my mind that having a repository for lets say packaging options could make my life easier by directly fetching a the packaging option from the DB by using its ID instead of asking the product repository to find it in its PackagingOptions collection and give it to me..
Second part is managing the edit create operations using ASP.MVC frame work
I am currently trying to manage all add edit remove of these child collections of product through product controller(sound right?).
One challenge I am now facing is;
If I edit a specific packaging option of product through
mydomain/product/editpackagingoption/10
I have access to the id of the packaging option
But I don't have the ID of the product it self and this forces me to write a query to first find the product that has this specific packaging option then edit that product and the revelant packaging option. I can do this as all packaging option have their unique ID but this would fail if I have collections that don't have unique ID.
That feels very wrong..
The next option I thought of is sending both the product and packaging option IDs on the url like;
mydomain/product/editpackagingoption/3/10
But I am not sure if that is a good design either.
So I am at a point that I am a bit confused. might be having fundamental misunderstandings around all of this...
I would appreciate if you bear with the long question and help me put this together. thanks!
In my mind, this is one of those muddy things that pops into DDD.
In code, I treat an aggregate root as a container for any "relationships" it has and any Entity Objects that cannot exist without the Aggregate root.
For instance, let's take the Customer->Order->LineItem->Product example that's been bludgeoned to death by now. The aggregate root as I've displayed it is customer in this scenario. That stated, you don't always want to get to the order through the customer. You might want to find orders on a specific date.
Turning it on it's side, you also wouldn't have a Customer that doesn't have an order. The two are in a somewhat symbiotic relationship so one isn't the aggregate root of the other.
The point is that you don't want to have to load a customer through an order, but you don't necessarily want to load an order through the customer either.
Starting at Order, however, it's unlikely that you'd want to just retrieve a LineItem and you're certainly not going to be creating them w/o an order. To that end, the Order serves as the gateway to LineItems. LineItems wouldn't need their own controller or repository. They only exist within the Order itself and, as such, are part of the Order (in this case, Order becomes the aggregate root) and are managed by the Order Entity.
But, a LineItem would likely have a relationship to a Product within the system. Products would have their own controllers, repositories, etc because they can exist outside of the Aggregate root.
In summary to my rambling, I tend to look at it this way: if an Entity can exist by itself, it should have a controller. Entities that cannot exist on their own (LineItems in this case) should only be managed solely by their container (aggregate root).
Will some DDD purist please correct me if/where I'm wrong?
As to the second part of your question, I would need some more details about how you envision these other Entities working. With what you've put here, I'd imagine that PackagingOptions are related to a product and would be part of a Product aggregate root. Now, implying that you're editing them begs the question of is this a lookup table in the system or are they one-off values and, as such, should be treated as Value Objects?
Kaivalya,
Regarding your last comment (stateless http):
It depends on the context. Before getting into the details, I should tell you a basic principle about aggregates:
Aggregates define a group of related objects that should be treated as a single unit for the purpose of data change.
This is extremely important. The purpose of having Aggregates is to enforce invariants. For example, you may have a policy like "An Order cannot exceed $500". Then, to enforce this policy, you put Order and OrderItem together in the Order Aggregate. This way, any time you add a new OrderItem, it should be added via Order object. There, you can check the total price and make sure it does not exceed $500. If you don't have such invariants in your domain, then there is no point loading all these objects together.
Now, getting back to your comment:
If you do have invariants that should be enforced, then it is okay to load the entire aggregate even though it may have some overhead. Yes, HTTP is stateless and you load your whole aggregate just for modifying one of its child objects and then throw it out. That is okay. What is important the most here is that you are enforcing your invariants. This is what DDD is for.
The purpose of DDD is to capture all business logics in your domain. You could definitely achieve a better performance if you didn't have to load the entire aggregate, but how would you enforce your invariants? You'd most likely have to do it in your stored procedure. Yes, it works, and it is fast, but dealing with business logics in stored procedures during maintenance is a nightmare. That is why DDD has evolved. So you can model your business requirements using object-oriented languages/tools, so they are easier to understand and modify.
Just remember, DDD is a great approach but not for all types of projects. If you are dealing with a project in which there are lots of business logics and the chances of them changing due to the nature of a business is high, then you should use DDD. However, if your project is more of a "read something/writing something" without much business logic involved, using DDD is a headache. You could simply use LINQ to SQL (or SqlDataAdapters) and send your objects to your Views. You don't even have to worry about finding Entities, Value Objects, Aggregates, Repositories, etc.
Hope this helps,
Mosh

Resources