More Thinking About Model-View-Controller (MVC) And Application Architecture
Ever since my talk about MVC (Model-View-Controller) with Steven Neiland, I've been thinking non-stop about my own application architecture and how to improve it. For the last two weeks, I've been watching presentations and reading articles about domain modeling, MVC, design patterns, and just about anything else that looks relevant. It's both exciting and daunting. I've also been trying to put together some MVC-learning code, but that's a slow process. One of the biggest hurdles in all of this is just figuring out what functionality goes where. I thought sitting down and sketching out the application architecture would help me think through feature distribution.
As of this morning (9:36 AM on June 5th, 2012), here is my current understanding of how an application should generally be put together. I stress the date/time as this understanding may change by the time I am done writing this post! Note that the arrows in this diagram are meant to be general and not exhaustive in nature.
As I've been doing all my reading and watching of materials, I came across a quote from Billy McCafferty that I think outlines some key ideas that I'm pulling into my application architecture:
... if you're putting any logic into your controller class that you would have to copy and paste, almost verbatim, into, e.g., a WCF service class to replicate the same sort of behavior, but for a different client interface (e.g., WCF vs. MVC), then it's likely a sign that your controller is doing too much and that the code may instead belong in an application service. In a different light, if you're putting anything into the application service layer which would preclude a different client type (e.g., WCF vs. MVC) to leverage it, then you may be introducing controller concerns into the application services. Following these rules of thumb, your controllers remain more appropriately paired with the web tier of your application while your application services provide the true gateway to the rest of the application.
While these concepts have been discussed previously, something in McCafferty's wording makes it very clear for me.
That said, I still have a ton of questions and gray areas. But, keeping this architecture in mind, I'm gaining some ground (hopefully) on the following topics:
Since only one client in my above architecture (WWW interface) understands session management, it makes sense that the Controller is the only part of the application that should know about sessions. This means that it is the Controller's job to translate session-data into method-invocation data when communicating with the Service layer.
Spelled-out more bluntly, nothing in your Domain Model should make a reference to Sessions (or URL, or FORM, or CGI for that matter). Doing so may preclude you from ever using a client that doesn't support session management (ex. WebSockets).
- The FORM scope doesn't exist during a WSDL-based request.
- The SESSION scope doesn't exist during a WebSocket request. getHttpRequestData() will also fail during a WebSocket request.
This is still a tricky one for me! At first, I thought all transaction management should be done at the Controller level so that it could tie together atomic actions across multiple entities; however, an application may not actually be using a Database as its persistence layer - it may be using flat files; or, it may not be using any persistence beyond in-memory caching. As such, I think it makes the most sense to move all transaction management out of the Controller and into the Service layer.
This brings up a really interesting question though: Can the service layer make calls back to itself (ie. one service object talking to another)? And, if it can, do we run the risk of accidentally creating nested Transactions?
In ColdFusion 9, you can now have nested transactions without error (the inner-transaction is simply ignored). But, this feels like the wrong "fix." It feels more like a nested transaction should be considered a "code smell" indicating a bad decision.
While I don't have a good answer to this feeling, I have read some things that may be on the right track. Specifically, I've seen people create a divergence between "Application Services" and "Domain Services." While I haven't read too much on it, it seems like the Application services sit above the Domain services and dictate "workflow".
The Application Service layer seems like it would be the perfect place to implement Transaction management, with the caveat that the application service layer represents high-level actions and should probably only be called once per incoming client request. This means that Domain services can talk to each other while Application services cannot.
Data Transfer Format
If the Controller's job is to take incoming request data and pass it off to the Domain Model (via the Service layer interface), what format should the data take? I've seen a number of approaches to this and the one that sits most comfortably with me is to keep this data as low-level as possible. Meaning, don't deal with Domain Entities; rather, pass "dumb" data structures into AND out of the Service layer.
By "dumb", I don't necessarily mean that it has to be Structs and Arrays and Strings. I only mean that it shouldn't be Domain Entities. From what I've read, if you want to create "Form Model" classes that create a Typed data transport, that is fine - so long as you understand that the Form Model may have little to do with the Domain Model.
NOTE: Until I understand this aspect better, I will probably just pass in individual, named arguments to my Service layer methods.
Last night, I came across an Anti-Patterns blog post by Mehdi Khalili that seems somewhat relevant to data transfer. In it, he said something that I thought was very interesting (paraphrase):
The Domain Model should never be in an Invalid state because it doesn't expose state - it only exposes behaviors.
Granted, this was in the context of ORM (Object-Relation Mapping); but, it feels like something I should think more deeply about. If I can put the Domain Model into an invalid state, then perhaps I should consider approaching a problem in a different way.
Gathering View Data
This is another area that is still gray for me. Clearly, the one part of the application that knows about the View is the Controller. As such, the Controller is the one that must gather some data and select a View to render. But, what about parts of the View that don't relate directly to the given request (ex. the Header area of a Master Layout)? Should the Controller gather this data? Or, should the View be able to make requests directly into the Domain Service layer?
I've read points of view on either side that typically come down to Ease of Implementation vs. Ease of Testing. I don't know where I stand on this yet.
When it comes to application architecture, I still have more questions than answers. And, I know there's no "one true way," to putting an application together. But, as always, I like trying to come up with guidelines before I come up with exceptions. More to come!
Service objects can definitely talk to one another. You might have a logging service or a mail service, for instance, that multiple other service objects will use. This is where an object factory like ColdSpring makes managing dependencies much easier.
As far as the last topic is concerned (gathering view data)...and this is from a Mach-ii perspective...it's typical to render a view into an event argument called contentArg.
The layout event is announced from the controller and the event-handler takes the content in the event object and wraps the site-wide header and footer html around it.
Ben, great thoughts and I had these same ones in 2009 while getting ready to rewrite all our CF apps. I ended up rolling my own that looks very much like your image above. One thing, I always have a viewState object that retrieves items for use in the view. It's up to the controller to match data from the model to the view state in the format needed. The end result is I have a model/domain layer that is used for both front-end and back-end applications without needing any extra work within the components. I do have a number of helper functions I use to maintain state and manage URL and form variables. A vestige of the Fusebox days, I clean both Form and URL variables out into their own event arguments and use that instead. It helps clean everything also.
"Spelled-out more bluntly, nothing in your Domain Model should make a reference to Sessions (or URL, or FORM, or CGI for that matter)."
I always build an adapter for the session scope, and simply tell the development team to never access it directly.
This solves a few problems for me, some of which will be relevant to CF, some will not.
Session["Login"] could be null. Because .Net stores session information as a top-level object type, it could also represent an int, a string, or an object of type Login.
There's also nothing controlling what gets set to Session["Login"], for the same reason- it's typed as "object".
I write a session adapter with Properties exposed for each piece of information to be stored in session, typed to match the datatype that is to be stored. So, while Session["Login"] could be anything, SessionWrapper.Login will always be of type Login, can only be populated with Login objects, and if appropriate (it isn't always), be set to a default, non-null, value if Session["Login"] is null.
The Controller layer then interacts with the SessionWrapper object, and passes the values it pulls from there to the application domain layer.
And in code reviews, kick back anything that refers to the session directly. :)
I do the same sort of thing as Matt by using a session facade object that hides the internals of the session from the service layer.
I have to do a lot more thinking on this idea of "Domain" vs. "Application" services. I think having a divergence makes a lot of sense there (but I've only thought about it superficially). With the divergence in place, I think inter-sevice communication makes a lot of sense, so long as the Domain Service *never* talks to the Application Service (as this probably wouldn't make any sense in that direction). It would make sense, however, for the Application service to talk to the Domain service.
... much thinking to be done.
I like the idea of a "viewState". I actually started playing with that idea - just a Struct called "viewState". But, how do you populate it with things like Aside data and Footer data - things that are more Layout-related than request-related. I assume you wouldn't want the Controller to repeatedly/explicitly get the Aside data every time a request comes in. Would that be delegated to some sort of Helper Render component or something?
Am I making any sense :)
I've heard a few things about the Session Facade pattern, but haven't dug into it much. I'll have to revisit it. I like the idea of having a consistent interface for Session.... but at the same time, I definitely have parts of my application that have their own sort of session-usage (ie. they have a few session values that none of the rest of the Application even knows about).
I know that is probably a really sloppy approach - I try to at least Initialize all the session values in onSessionStart(). But, part of the app just get "tacked" on later (like mini-report modules) that aren't really related.
Ben, yes. I'm somewhat lucky that all my apps must "look like" the rest of the site so we actually have a custom tag that renders all of that stuff based on calls to the CMS. Between the opening and closing tags is where my application's content goes. I use the front-controller way of doing things. It returns an "event" object which contains a bunch of stuff including "output". That's what is outputted in between that layout tag's open/close.
On the session item. My controller will access the session data, however, it will pass that information to the model or view in the respective state object/arguments. It never passes the full session over. Granted, I need to keep our MVC simple due to the level of the other developers which may/may not be the best way to do what I'm doing.
I think that all sounds good. Re: the Session stuff, I think we are saying the same thing. I think the Controller *should* be the one accessing the session and passing around the data.
Yes, I think we are saying the same thing. Anyways, I found the blog post that helped me roll my own simple one:
I basically did the same thing he did and that's what we use. I even went so far as to use the old Illudium P36 code generator to spit out everything I need to scaffold an application.
Yes service objects can call each other. In fact it is almost a requirement in some cases. Remember how my securityService getUserId() method was called by the saveMethod of another service.
When it comes to the controller & layout, remember that the controller is the *Framework* the controller files you define are just rules for that particular action/event that the controller is executing for a particular page request.
Global actions like gathering the data for the header for the main layout happen in the controller but at the global level (eg onRequestStart) and not the action level.
In regards having the session call in the controller, this is actually a bad idea imo because you are accessing a storage mechanism (session) to get data to pass back into the service layer.
Think of the session as a datasource, no different to a database or 3rd party api. And where in a db you would have tables, in the session you would have named datastructures like shoppingkart and user.
So what you do is you have a single service which has ownership of a particular datastructure within the session and any other service which requires access to that data struct has to call the owning service (all within the service layer).
A good way of keeping track of this is to name the session structure after the service component. So you would have a shoppingkart.cfc service with a session structure of session.shoppingkart.
Of course this does not address instances where you would need to switch to a different storage mechanism for example client variables etc...but that really is an outlier case, no different to switching database engines from sql to nosql.
On a side note, I am not a fan of having a session facade. My reasons are too long to get into here.
I agree 100% that the service layer should never know about form or url variables. Those are variable which are coming in from the user which means the controller should pass them in.
CGI is one of those it depends scenarios. If I were to put the cgi scope in the service layer I probably would wrap it in its own service.
For your situation where you have to deal with both session authentication and stateless(websockets) then what you have to answer is answer this. Are you hitting the same url for both session'd and stateless AND if you are do you care about authentication AND do you present the data in the same way.
If any of those three cases are not a match then they should have separate controllers. Which in turn means you can do something like this.
--- Controller ---
--- Feed Service ---
@Steven, that was a great explanation on how to handle session data. I never would've thought about it like that but they way you described it, that makes perfect sense.
I'm going to try do a cfmeetup on mvc architecture to demonstrate some of these things because there is so much theory behind it its almost impossible to explain concisely.. And there are so many different ways to tackle it.
But when you see it in code in makes sense.
Im waiting for Charlie to get back to me, but I'll let you know when I have confirmed it with him. (Im hoping I can do it next week).
If you have parts of an application that use session variables that you want hidden from other parts, try subclassing the SessionWrapper.
@Steven, make it a series, do an overall, then follow-ups on each of the 3 areas with code and maybe a walk-through demo/little hands-on. It's like me and unit testing, I know I should do it, I know there are tools/frameworks, but for some reason I just don't get how to do it regardless of how many sessions I attend or people I talk to about it.
I deal almost exclusively with MVC. I always struggle with how the data gets into the view. For instance, if you have a view that displays part of a product... Surely, getting the product struct from the model is the controller's job, and it then passes it into the view? Okay, that works very nicely on paper.
But... given that there is only one idea of a 'product' that the view will understand, wouldn't it make more sense to just pass a product ID into the view and have the view get the product data from the model direct?
The former idea is more conceptually valid and more appropriate to the idea of MVC, in my brain anyway. The second is at first glance messier and not as 'nice', but it does mean that you can just call the view with an ID and you don't need to worry about passing anything except a simple ID in.
So, how does one get past this issue? What's the 'party line' and is there any advantage to one over the other from a practical point of view?
That breaks the concept of mvc as applies to a web application.
The idea is that the controller asks the model/service for a datastructure. It loads the appropriate view and then passes the datastructure to that view to display.
The controller knows nothing about how the service gathers the data, only that it will return a structure with a given set of keys:value pairs.
Likewise the view does not know how the controller gets the data structure or how it chose the view, only that the controller will give it a structure with defined key:values for it to display.
The only logic that should ever go in the view is some conditional display/hide.
To reiterate, the view does not understand the concept of a product. It only understands that it will get a data structure with defined values. This is where MVC for web apps and MVC for desktop apps diverges somewhat.
The reason why this is so powerful and important is because once you have agreed the data structure format you can have two separate teams building the application. One team knows it needs to build a service that takes in say a productid and returns a struct with keys X,Y and Z.
While the design team can build a view which outputs X,Y and Z from a structure.
These efforts run in parallel until both are finished and the controller then ties them together in the application.
I'm with Steven on being against a literal "session facade" because it really doesn't "encapsulate" anything - your code still refers to SessionFacade everywhere and just calls getters / setters instead of having using a struct (that happens to be called "session"). The correct way to encapsulate session scope usage, IMO, is to isolate it to certain specific methods of the service that actually depends on it (as in Steven's ShoppingKart CFC).
On one of Ben's original questions, about Domain Objects and Controllers, I let my controllers talk directly to the domain objects. That's where the bulk of the logic is. A controller might use a service to obtain a domain object (userservice.get( id ), for example) but then it just talks to the user object, up to and including calling save() on it. [Aside: my CRUD persistence is usually handled by data gateway object but I tend to inject both FooService and FooGateway into my Foo domain object so that operations can occur on the domain object, even if it ultimately delegates the behavior to the service object or the gateway object. I find this makes the code more readable while still separating concerns nicely. An adjunct to that is that I'm not as adverse to the Active Record pattern as I used to be - as long as it's implemented via delegation somehow (through aggregation of a gateway or a generic persistent bean base class).]
I also let Views have direct access to Domain Objects rather than forcing data thru some artificial "view state" or "data transfer / value object". It reduces complexity: the controller asks the service for a domain object, tells the domain object to do some stuff and then makes it available for the view to ask questions of the domain object. There's an accompanying rule, of course: views _never_ call anything but getters on the domain object!
In addition to reducing complexity, it's also more efficient: you're not constantly copying data around just to avoid allowing objects to be queried. As for encapsulation (yes, I can hear you crying about that!), who are you trying to protect your objects from? You're not writing a library with arbitrary 3rd party users - you're writing clean, simple code that your _colleagues_ should be able to understand and use easily. Have coding guidelines and peer review rather than architecting "rules" into your code.
Trust your developers. If they can't be trusted, fire them - don't punish the good developers by making them jump thru hoops just to do something that should be simple in a much more complicated way!
Overall, I try to keep the number of objects to a minimum: one controller per site section, one domain object per... well, domain object! Services only where you need them to orchestrate operations across multiple domain objects (fetch by PK or example query is the simplest example). Services may span multiple related domain objects. Gateways for persistence, again potentially spanning multiple _tightly coupled_ domain objects. "All" business logic inside your domain objects - services only contain orchestration code, and delegate to domain objects as much as possible.
The change I'd recommend to Ben's diagram would be to promote Domain Entities to the top of the Domain Model, alongside Application & Domain Services and allow Controllers to talk to them directly and Views to read from them.
My contention is that the obsession with encapsulation and the proliferation of objects associated with dogmatic separation of concerns is something that's grown up in the Java world to provide a "manager" in the code, to look over every developer's shoulder, to make sure they "conform" to rules... rules that are necessary because instead of hiring a small number of good developers that can think for themselves, most companies that are heavily in bed with "enterprise" Java tend to hire vast teams of junior / mediocre-at-best developers who need to be herded around like sheep.
Hmm, that became a bit of a long rant...
Yes, I know it breaks the architecture, and believe me I don't actively seek out ways to have the view do this ;-) I was just thinking outside the box. From a practical point of view, of course, it would be very handy to just be able to call a function and have it get the data and display it, but of course if you did it that way you wouldn't be doing MVC. :-)
And another thing...
On domain objects vs data structures (in the context of the view), one of the tenets of functional programming is a focus on the correct data structure that is used, with functionality separated out, and most importantly _immutable_ data. This makes it perfectly safe for the view to get hold of the raw "object" (data structure) since it can't actually modify it. Again, the justification in the OO world for value objects / data transfer objects / view state structures is all based on protecting data from being modified by clients of that data (views etc) - it's a "manager in the code, policing the rules".
Now, in functional programming, you don't have rich domain objects with behavior and data glommed together like in OOP, so you have some sort of "module" per domain object to contain the business logic and you have a documented and/or self-describing data structure for the actual entity properties. The latter can't change so encapsulation of properties isn't needed. Calculated properties can easily be handled (by preprocessing the data where needed or by wrapping it in a closure if you want lazy evaluation of such properties, or various other techniques) - so that's not a valid objection :)
But in the functional world, once you have immutable data, you don't need getters and setters, you don't need traditional encapsulation, you don't need artificial data types (generic data types like maps and vectors work better because you can apply all of the language constructs to them without needing to write adapter code), and you have automatic separation of concerns because you cannot blend behavior and representation - controllers interact with services to get data and pass data to views. Period. It's a simpler world, and MVC is much less painful.
I'll make one revision to my last post. The data returned from the model, does not necessarily have to be a struct. It can be an array, query, list or an object.
What is important is that the view is not doing the work of asking the model to fetch something by an ID. It simply is given some data structure by the controller that it outputs.
Im not a fan though of creating objects just to pass data between layers. Apart from the overhead incurred by creating objects, you really have to answer what problem are you solving.
What do you accomplish by creating a product object to pass to the product view as opposed to a simple structure?
Is there any benefit to having this in you view.
I'm with Sean when he says trust your developers. If you are creating a session facade because you cant trust them to follow the agreed upon design rules then you have either a management or a hr problem to solve, not a technical problem.
You beat me to the punchline. Well said.
Looks like I'm a little late to the game, but figured I'd drop a few thoughts into an excellent discussion!
I've learned that the complexity of the architecture should scale with the environmental constraints and the complexity of the problems you're solving.
For example, in the case of a simple, self-contained app, passing along your "real" Domain Objects to your View layer is a simple way to go -- there'd not be as much benefit to creating Value Objects in that case (other than encapsulation).
But if your app is talking to, say, a REST based service tier (and the Domain Objects live there), then it might actually be easier for the View layer to work with struct representations of your Domain Objects, because they've gotta get serialized to go across the wire anyway.
I try to keep in mind the general design principles I've learned (e.g., Separation of Concerns), but also let common sense challenge them. Maybe that's where programming becomes a bit of an art.
Basically for calculated properties you do want to pass an object, not a struct.
Why? What is the benefit over just passing the values out of the model?
At the end of the day all you are doing is creating an object to wrap some data values which are being pulled from a data source.
Where is the payoff to compensate for incurring the cost of creating an object?
Why is a configuration like this less valid?
-- Service --
-- Controller --
-- View --
It is just as easy to do a calculation in the service layer as it is in an object. Maintenance wise it is still just one place to change the code if a calculation is updated.
The only benefit I could see is where you would want currently logged in users to maintain the existing calculation logic while new users would get new logic. But even that can be worked around with controlling the load balancer and clustering.
@Steven, yup, and in the functional programming world you'd apply a transform on the core domain object (data structure) to provide the calculated properties, again as a simple data structure.
At World Singles, we have a user "object" that has calculated properties for age (based on date of birth), display name (based on username, first & last name, and preferences), and attributes (which come from another table but need to look like regular properties of the user). We have a series of with-... functions to calculate and add these to the basic data structure. In Clojure, it looks like:
(defn annotated [user]
(-> user with-age
The -> notation takes the object (user) and applies the series of functions consecutively. It's equivalent to:
(with-attributes (with-display-name (with-age user)))
So then we get the user from the database and we pass the (annotated user) out to the view. If we know the view only needs a subset of those attributes, we can pass (with-age user) or (with-display-name user) to the view instead, for example.
I am not claiming you approach is less valid or something. In some cases when the data's schema is relatively simple and has just some static properties, then sure I'd use a simple structure to pass data and I wouldn't create an object just for the sake of creating an object.
But sometimes and depending on the case OBJECTS (domain entities) are more useful and easier to work with.
For example, as I have already said, the calculated properties. In your example they would always be calculated when the structure is created in the SERVICE component, even when you really do not need them (depending on the view you may or may not want to display price range). If you use object, they are calculated only when you ask for them. What if there are plenty of such properties only some of which are used in a certain view? And I personally (!) feel it is easier and more natural to encapsulate method implementation inside a domain entity, rather than make service component do this.
Then, when you use an object you can benefit from the type enforcement, e.g. you can check if an instance of the product really implements getPriceMin(), getPriceMax() methods (e.g. you may have several kinds of products in the set, which may or may not have the concept of sizes and price ranges).
You CAN do this using your approach too, but after all what for do we have OOP and MVC? As I understand the idea of OOP is to shift burden from developer to hardware (so it is OK to make CPU produce some objects if it makes developer's life a little easier).
And I definitely DO PASS domain entities to the VIEW and let it access entity's getter methods. For the VIEW it is OK to know about how data is structured.
Im not saying your argument does not have validity...but my approach is based on the premise that the service should *only* return the data which is needed for that view. I would never consider it acceptable to calculate values which are not used. That would be no better than doing a "select *" on a table. Yes it means that you need either a more intelligent service method or multiple methods for where you have more than one view.
As for products that may not have min max values, I simply check for either key existence in the structure, or a non empty value when outputting to the view.
I know MVC and OOP have benefits but it is important to remember their concepts originated in compiled languages like java that for the most part run on local user machines. We cant apply them blindly to an interpreted language like CF. We have to keep in mind scaling and known performance restrictions (object creation being #1 on my list).
I am all for making developers lives easier, but the reality is that CF has a bad rep for performance because too many developers try to make their lives easier by shifting the burden onto hardware. Throwing hardware at performance issues only works for so long, and trying to fix architectural level performance issues later on is far more difficult.
I always approach application design with my personal best case scenario in mind. "What if this turns out to be the next twitter."
@Kirill, I'm curious as to your language background? What languages have shaped your opinion?
(I ask because you seem to be insisting that only simple systems can be built without objects which is clearly false :)
As I have said, I think there is a trade off - you either spend much more time / money for development or you spend little bit more money on hardware.
I completely agree that storing simple values in STRUCTs might be (well, definitely is) faster than storing them in OBJECTS, in fact I have an application that I built several years ago using procedural code, and it is very fast.
But it seems that your SERVICE is aware of the view / which view is going to use data passed from the service, and that you have to write similarly looking methods in your SERVICE for different views. When you add a new view, you have to go to your service and add a new method? My opinion is that the MVC's MODEL layer should be free from this.
Anyway, I do use objects heavily. Maybe even overuse. They are easy to use. This is what they are for. Does using a lot of objects really impose critical performance issues? I don't really think so. After all, performance was never OOP's objective.
It's always been CF starting from before ColdFusion MX. I've been playing with C# ASP.NET MVC and Haskell lately. It may be that C# books have had some influence on me. But still I think the biggest impact on my MVC and OOP thinking was done by, guess what, FW1. It taught me to develop modules out of the context of the application, and then just plug-and-play it.
And no, I don't insist that OOP is the only tool. I am not one of those OOP adherents. Functional programming is fantastic! I am just saying that OOP is a good and easy tool, why not using it?
I had never thought of the Session object like an in-memory database; a very interesting point of view! I'll have to do some more thinking on that - I have so much history with the ColdFusion framework that it will take time for me to think about it more objectively :)
It would be awesome to see a CFMeetUp. I am sure Charlie will get back to you.
In a talk I recently watched by "Uncle" Bob Martin called "Architecture: The Lost Years":
... Bob Martin talks about how data should get passed into and out of the "Domain" model. Basically, he said that the Framework/Delivery mechanism shouldn't know anything about the "domain model." That is, you wouldn't even pass it back a Product.cfc in the "domain" sense. Rather, you keep the data passed back simple and data-oriented. It doesn't doesn't have to be vanilla objects - it can still be ColdFusion components - but, it just can't be the domain model itself.
I am not sure how I feel about it, but something about it feels really good! What I like about it is that you can build up and mock-out your entire Service layer and build your views **without** having to actually have a domain model in place.
Of course, as @Sean is saying, allowing your Domain objects into your Views can make things a lot easier since you don't have to copy data all over the place.
@Sean, a while back, I was watching a presentation (I think by Google's Misko Hevery) and he was talking about "who are you protecting your code from?" He said something like if you start putting guard logic inside your functions, then you've already lost. Assuming that you have Unit tests for your application, then double-checking all your data is pointless - all it demonstrates is that you don't trust the people you are working with.
I like functional programming :) The little that I've played with it, once you get over the emotional pain of having to "copy" data anytime you make a change, it actually feels really nice and comforting.
I definitely like the philosophy of letting the architecture grow with the needs of the application. Right now, I'm trying to learn about the foundational stuff, so I'd rather err on the side of "extreme" than of "practical." There will always be time to break the rules later ;)
That said, I think the correlation to that rule is to always be **Refactoring!** I can't tell you how many times a small "proof of concept" app *actually* went onto to be the foundation of the "product" without any significant refactoring. It creates for a very scary lifecycle.
(with-attributes (with-display-name (with-age user)))
... there's something so nice about the super-focused separation of concerns in this chain of transformations. Definitely something to be enjoyed in Functional programming.
Did some more thinking about the Service layer, breaking it down into three distinct types of objects:
Data persistence remains one of the most annoying concepts in all of this :)
Yes my web mvc pattern is more closely coupled than a traditional desktop app mvc pattern, but as you have said the pay off is performance.
I take the approach to patterns and design that one size does not fit all, what makes sense for one domain (desktop) does not necessarily work in another (web). You have to be willing to question and adjust the pattern to make sense where you are applying it. Im not saying the pattern itself is wrong certainly there are a lot of concepts that can be learnt from and applied, only that different use case's warrant adjustment.
Personally the only place I ever use objects to represent data is in persisted scopes like application and session because the performance cost of object creation is trivial when the object is persisted as opposed to a new object being created for every page request.
Of course this gets into the whole issue of third party session management systems like memcached and serializing etc but for me its a reasonable trade off.
But again this is a case by case cost benefit evaluation not just blindly following a pattern.
"Uncle" Bob Martin is coming at this from a slightly different point of view but if you consider his advice in the functional programming world, it makes perfect sense: just pass back the data that the view needs and just pass in the data that the service needs and you're all done.
To do that in the OO world means constant copying and shuffling of data back and forth - unless you use adapter objects to wrap the raw data by reference and have them only expose the data that the view needs (in the outbound direction). For the inbound direction, you already have "just plain data" - it's your URL/form scope (or the event / RC that frameworks provide). It adds complexity (in the outbound direction) that really isn't worth it, IMO.
As you note elsewhere, a lot of this is just tradeoffs and it's very hard to know the right tradeoffs to make without a lot of experience under your belt - so it's a safer practice to start off from the extreme of "pure best practice" (if you can find such an absolute) and then learn when bending the rules makes sense. Unfortunately, there's a lot of conflicting advice because some of the "best practice" is based on making tradeoffs, after years - or decades - of experience :) Chicken... egg...
I only recently heard of Uncle Bob (mostly on some Ruby podcasts). It sounds like he's one of the original pillars of the programming world. But, the keynote I watched from his is literally the first thing of his that I've ever seen/read. All to say, I don't really know much about his background or where he's coming from (other than that he sounds like a Ruby developer these days).
I'll agree that the thought of constantly transforming data for Output does sound tedious. I do like the fact that it means you can more easily "mock" out your Service layer when you're working on your application Views and Controllers.
Uncle Bob is indeed a pillar of the programming world. He's into Clojure these days (as well as Ruby) but he's been around forever and has written some great books:
Definitely worth following him on Twitter too:
One point of clarification that I just thought of for anyone reading my comments on session access.
I reason that session storage should be accessed from the service layer because I see it as a data storage mechanism "like" a database.
I do not however advocate creating a gateway for it the way you would a real database. (This is basically what a session facade is, and is an antipattern imo).
I finally got around to redoing my cfmeetup on mvc with fw/1.
Links to the video, code and slide deck can be found on my blog.
Oh awesome! I caught it the first time, but I'll definitely go back and watch it - it's gonna take a number of rounds for this to all start sinking in. I wish I've had more time to play, but things have just been too hectic lately.
Ah no worries, I know the feeling. The most important bit really is the save user example in the webshop2 code. I built it specifically with you in mind.
Hi guys, I also fancy uncle Bob and i will keep an eye on the blog in the future.
About gathering view data, you should gather all data necessary for the partial in the current controller action (which may use methods shared across other controllers and actions).
As I like to say, it´s no brain that most popular web programming frameworks also encapsulate MVC principles: Django, Ruby on Rails, CakePHP, Struts, and so forth
This is a great subject ... I'm currently moving into Java development and have recently been investigating OO design patterns. One subject that I find very interesting in that of 'Design by Contract', which define
" A) The requirements upon the caller made by the class.
B) promises made by the class to the caller."
I'm quite interested in learning more about effective design patterns ...