How dumb and fixed should VOs really be?
I've researched pretty extensively in the forums and the examples for how VOs are written and used, and I seem to find conflicting viewpoints. In this forum post, Stray and Ondina discuss why VOs should be immutable and just typed containers of values.
To this, I ask, why bother typing? If it just contains properties and values, why not use a regular object? The only advantage I see is the added structure to your code.
In this post, Stray explains a bit more in depth why VOs should be unchangeable, and that updating a VO should create a new instance with the updated value.
Is there a reason we should avoid updating values of a VO? If we are trying to reduce calls to a service, it makes much more sense to operate on values tracked in memory, rather than instantiate from a service database on every property update. Rather than make two calls to the database, one to update the data, and one to rebuild a VO, we just make an update call, and on a successful update we alter the properties of the VO appropriately.
On the other hand, look at some examples by Joel Hooks, and you see VOs with significantly more functionality
So... what gives? Is this just a matter of preference, or need for that matter? I tend to lean more towards Joel's approach, since I'm working with VOs that are constantly updated and have some constantly accessed properties that are made up of several smaller properties (for example, imagine full name, made up of first and last name, or perhaps an isManager boolean on an employee VO). I guess this is mostly a philosophical discussion with regard to MVCS, but as this is very new to me, I would like to proceed with best practices in mind, but I'm struggling to figure out what those are!
Comments are currently closed for this discussion. You can start a new one.
|?||Show this help|
|ESC||Blurs the current field|
|r||Focus the comment reply box|
|^ + ↩||Submit the comment|
You can use
Command ⌘ instead of
Control ^ on Mac
Support Staff 1 Posted by Ondina D.F. on 29 May, 2015 03:46 PM
That's the best laugh I've had in awhile.
I should not have been taking a sip of water while reading the title of your post.
Now, you have to buy me a new keyboard. Kidding:)
It is a very good question and I understand your frustration too well!
What to use, Stray's or Joel's style? Both are good.
But, if you feel that Joel's approach is more appealing to you, go for it.
I'll try to address your concerns in more detail in the next few days.
Support Staff 2 Posted by Ondina D.F. on 01 Jun, 2015 04:43 PM
There is sufficient reading material out there on the internet and on this forum about the advantages of type safety or strongly typed data, so I'll just mention a few things on the subject.
Some analogies :
club admission: simple entry ticket vs. identity card
counterfeit product vs. real product
var i:* = "123"; vs. var counter:Number = 123;
as3 Object vs. VO class :
You'll have to try this out to see the various errors.
A VO makes it easier to catch errors at compile time, or at least you'll get a run time error (for example, if you pass SomeVO to someTolerantMethod), which is really very, very good and desirable from a programmer's perspective.
someTolerantMethod will accept all kinds of "objects". If you pass an Array in one place and an Object somewhere else, it doesn't care (no CTEs), but the consequences might be disastrous.
A VO is a guarantee that you get what you expect.
A VO is a wrapper for properties.
A VO is an organized container for data. Imagine that you want to move out of your house. You can either throw every item you possess into a big container, or you can put your bathroom stuff into a labeled box, BathroomVO, your kitchen stuff into another box, KitchenVO, your books into BooksVO, and so on.
The advantage of using separated boxes for each group of items is obvious, isn't it?
A VO is a data carrier. It transports data from an application's tier to another safely, and in a recognizable and identifiable manner. An analogy - I admit, a bit far-fetched - would be a PoliceCar, a SchoolBus, a FirefighterTruck, etc.
My analogies are not very good, but I hope you'll get the idea, and I encourage you to build your own analogies with real objects. You'd be surprised how much it helps to 'de-obfuscate' ambiguous terms or programming concepts.
VO is a much abused or misused term, and has given rise to many arguments and debates on different programming platforms.
Some people talk about VOs, but they actually mean something like a robotlegs Model. The term Model, on its turn, is also very ambiguous..
Stray's definition of a VO is adhering to Martin Fowler's definition:
I think, that we all agree on the fact that an application of any type is dealing with data.
Data can be external to the application or generated by the application, internally or through user interactions. The robotlegs MVCS is about having specialized classes for retrieving/storing data from/to external sources (Services), retrieving/storing data from/to cached /in memory resources (Models), transporting data (VOs), and presenting/receiving data to/from a user of the app (Views), that easily communicate with each other (the classes) through events/signals/callbacks/promises.. You can name your classes as you wish, the fact remains, data flows in different directions throughout your app.
You'll almost always see a pattern of retrieving, storing, manipulating, transporting, and presenting data, occurring repeatedly.
How "clever" should a class be is actually equivalent to how many roles a class should have.
The robotlegs MVCS should help you identify the roles of different classes. It should not hinder you whatsoever from designing your classes in a way that is more appropriate to your application. The term "best practices" should disappear from the surface of the earth;) MVCS is just a recommendation, an example of usage, and as such it can't cover all possible use cases and their combinations.
If you think that an immutable VO is not what you need, but you somehow want to follow those best practices in the sense of using unambiguous names, give the class the roles you wanted it to have, and call it SmartDataCarrier or whatever else, to differentiate it from a VO à la carte:)
The different definitions of a VO have at least one thing in common: a VO is a data carrier and it is strongly typed. Dumb VOs might be as useful as clever ones. It really depends on the use case. To me, more important than the IQ (ha!) of VOs is how they fit into the overall structure of an app. If you use an immutable VO in one place and any other variation of a VO in other places, you may want to use meaningful names for those classes, in order to make it clear to you (and your co-workers) what the classes are supposed to be doing.
But, as a general rule, I think, that any class that tries to be too clever is problematic, not only a VO.
MVCS classes are sometimes (actually very often) making use of helper classes, that are not part of the MVCS schema. For example, a Service can use Parsers to translate raw data into a desired format, Factories to build VOs or Models and so on. That means that not every class in an application, especially in a large and complex one, will fit exactly into the definition stated in the MVCS. If we were very strict, a Service should only retrieve or send data from/to an external source. Its single responsibility should be the communication with the external sources, right? But, another recommended practice is to parse the data as soon as it arrives, so the Service has one more role now, thus it makes use of a Parser. That's an example of an acceptable deviation from the SRP.
I think, you can't avoid imperfections and deviations from the so called best practices, if you want your application to work as you desire. More often than not your intuition will help you decide what's appropriate and what's not.
That sounds good, but it is not clear to me where you intend to update the VO and what will happen with it afterwards.
I know. It's confusing. It is difficult for me to take sides. As I said, both, Joel's and Stray's styles are ok. I prefer to use a combination of both in my projects.
But, I often recommend a flow like this:
because it is what it has been mostly used in tutorials and has been considered to be a best practice in many, many discussions.
For many use cases it is indeed the best solution, and for beginners a 'safer' way of coding, until they find their own style.
The conflicting opinions on a subject or another in this forum only show how different projects' requirements are and how many use cases there are, and that what's best in theory is not always best in practice, or not always that easy to implement.
I'm afraid, I didn't answer all your questions, but I have to stop now.
I've already spent an hour writing this.
If you want more clarifications, it would be better to have a concrete use case as a base for the discussion.
3 Posted by dkarten on 02 Jun, 2015 08:44 PM
Thanks for your in-depth responses. Your knowledge and wisdom is greatly appreciated. I am starting to wrap my head around the whole MVCS structure. I certainly get it, still some of it just seems counterintuitive to me. There are a few things that bother me if we subscribe to using immutable VOs. I know you said it is not absolute, and we can skate outside of the "best practices" of MVCS, but maybe this can illustrate where I am struggling with the concepts a bit more.
If we display a collection of our VOs in a DataGrid or DataGroup or dropdown list an extremely useful way to keep this data up to date is to use the Flex [Bindable] tag. If we make the VO class [Bindable], any updates to an object in the collection propagate immediately to the view without us having to wire any events from the model to the mediator. But immutability renders this binding completely useless, no?
Second, I'm building a value object from a sequence of server calls. Unfortunately this particular service only allows you to get one piece of data at a time. I want the VO to represent the state of the data after all calls are finished. If we keep our value object immutable, we have to construct a new version of it every after every call. How do we keep track of the values that we've already gotten? One solution is to track the values retrieved from the server in a plain old object, and create an instance of the VO at the end of all these calls. Another is to add a convenience method to my VO similar to the Contact example here. Even another is to alter my API of the service to consolidate these calls into one asynchronous process that resolves with the full set of values. I feel like this couples the VO too closely to the service. What would be the most convenient, I think, is to just give my VO setters and getters and incrementally update after each server call, but then it is no longer immutable.
I end up trying many of these things and, unhappy with the messiness of it, throw my hands up in the air, not sure of quite how to proceed. Perhaps I am adhering to strictly to the architecture. I have something that works, but it doesn't seem right to me.
4 Posted by dkarten on 02 Jun, 2015 09:03 PM
Also, it just occurred to me rereading your response. Perhaps these issues are jobs for a model, but I don't see how to construct the model class appropriately. There are several types of objects which play a prominent role in my application, and I see these first and foremost as value objects, since their properties/data are saved, loaded, and tracked in a database.
Since the application can deal with potentially hundreds of each of these object types, I have built a number of model classes that deal with collections of these types. From what I have read in the forums and RL best practices, model classes should be singletons, so it makes sense for the models to deal entirely with the collections, this way we don't have to inject things by string ID, which would get very messy very fast. So, in my understanding, it does not make sense to create a model class that you can use for individual VOs. Maybe I am wrong here though, and I need to create some sort of model that takes a VO, performs operations on it, and returns new instances of the appropriate VO after manipulation? Or am I muddling commands and services together here?
Support Staff 5 Posted by Ondina D.F. on 02 Jun, 2015 09:58 PM
I'm about to go to bed, so I'll give you a more in depth answer tomorrow. I just wanted to let you know that your second message about needing a model is closer to the "truth".
Just do not despair. Take a deep breath, relax or go for a run. Everything will be alright, I assure you. :)
Support Staff 6 Posted by Ondina D.F. on 03 Jun, 2015 04:01 PM
I'm extremely sorry, but it seems that I won't be able to answer your new questions today.
I underestimated the duration of a meeting I was attending today....and now my head is spinning making it hard for me to concentrate on the topic of our discussion.
Consider this to be the error handler of the Promise() I made yesterday ;)
So, here, a new deferred.promise to answer when I get more time - hopefully already tomorrow..
Until then could you please clarify a few things:
Assuming that you are talking about a database table, do you mean that you have to send a new request for a single record (table row) at a time? . If so, do you request the next record right after the previous one arrived, or is the next call depending on user interactions or other conditions in your app? [many successive requests, many responses]
Or, do you mean that the server is slow and you don't want to wait until the entire data set arrives to populate your datagrid? You want to refresh datagrid's dataprovider in succession, right? [one request, one slow async response]
Regarding the question about how to manipulate VOs in a Model, you can see that in Joel's examples that you mentioned.
Until I tell you more about VOs and Models, think about this analogy:
The VOs could be the rows of a database table. Its properties are the db table-columns. A collection of VOs can represent 1 to n table-rows. The Model stores the collection, manipulates it (CRUD + other operations) and it makes it available to the rest of the app.
See you soon:)
7 Posted by dkarten on 03 Jun, 2015 07:31 PM
In the second example, I'm not talking about a database table unfortunately. It is an external service which uses NativeProcesses and a web connection to do some validation. They have an API for ActionScript which I have abstracted into a service in RL, but the actual calls to their server are hardcoded in native code. I have to retrieve a several pieces of data, but unfortunately their API only supports getting one feature at a time (and actually restricts from making another server call if one has not been resolved yet!). For now, I have a loosely typed DTO (it's just an Object) that stores data retrieved when the server responds. At the end of all the required calls, we build a VO from the dto, and pass the VO to the model. Any time the features are requested again, the DTO is mutated with any new values and a new VO is constructed and passed to the model. This seemed like the best way to achieve an immutable VO in this case. The other solution I see is change my getFeatures() process to return all the data in one container (either a VO or DTO), but this seems unnecessary and tightly coupled.
I completely understand that VOs should correspond to database rows, and that is how I have constructed them thus far. I guess the big block for me still is that I want to be able to update the VOs tracked in my models' collections without doing a total refresh from the database. This is huge for me because there are many user interactions and data changes elsewhere in the model that will update certain properties on certain VOs. So any update to an immutable VO means creating a VO representing the new state and replacing the old one in the collection (which you could find by row id say) with the new one OR executing more asynchronous database calls. This seems a bit archaic when instead I can create a VO with bindable properties that is mutable, perform my database update operation on it, then in the result handler of that update call, I can update the property on the VO and have it's change reflected across any views it is represented in, rather than refreshing the entire collection in the model and broadcasting it to every necessary view. Am I overestimating the expense of this "refresh" operation vs. the single property update, and consequently making things much more complicated for myself?
I can very easily see how to enforce immutability on my VOs by constructing them in callbacks from the database and passing them to the model, but one of the big reasons I wanted to implement a framework like RL is to give myself as a developer more control over tracking data in memory (the model) and wiring that properly to the view. If I were to pass immutable VOs from the db to the model, I almost don't even need it, can pass it straight to the view and class out my SQL service to represent interactions with different tables.
I read your discussion of VO/Model approaches here http://knowledge.robotlegs.org/discussions/questions/790-why-model-... and found it very informing. I will have to reread it a bit and see how much of that situation I can apply to my own. Once again, thank you for debating MVCS philosophy with me. I have no one to really discuss it with and sometimes talking out design issues, especially with someone knowledgable as yourself, just helps you figure everything out properly.
Support Staff 8 Posted by Ondina D.F. on 04 Jun, 2015 06:42 PM
First of all, thank you for your kind words!!!
The AddressBook example, you mentioned, was inspired by demos used in another framework, namely PureMVC. Many of the Robotlegs users, me included, have used puremvc before coming to Robotlegs. I still use puremvc in some of my projects.
I know that you understood how VOs were used in the AdressBook example, so please don't get offended if I'm going to repeat some notions already known to you.
In the original puremvc example a Proxy communicates with an external data source via a 'Delegate', that encapsulates the logic for the remote call. In the added responders (result/fault) the Proxy manipulates the data (parsing it for example) and makes it available to other actors, either through Proxy's API or via notifications.
The Mediators are allowed to retrieve a Proxy and they also can listen to Proxy's notifications.
If a View needs a list of items from a database, for example, its Mediator is doing this:
view.listOfItems = someProxy.listOfItems;, where someProxy.listOfItems is the server call result as an array.
If another View is editing an item from the listOfItems, its Mediator passes the edited values from the View as a VO to someProxy, someProxy via its delegate sends the data to a db, and when there is a result, it sends a notification with the current VO, and the Mediator who registered a listener to that notification, passes the new VO to the View.
The View editing the items is using the properties of the VO as the source for data binding for its input fields. There are 2 instances of the VO: a currentVO and an editedVO. When an item is edited, the View sends an editedVO (via Mediator) to the Proxy. When the Proxy gets a result from the delegate it sends a new VO which will then be passed to the View to replace the currentVO.
The logic used in this example is absolutely fine, in my opinion. Why am I mentioning the puremvc approach?
Because, for one thing, robotlegs was inspired by puremvc and some of the examples were ported from puremvc. A lot of the concepts used in robotlegs have been borrowed from puremvc, as well. The main difference between the 2 resides in the use of the Model tier.
A puremvc Proxy "manipulates the data model, communicating with remote services if need be to persist or retrieve it".
In an attempt to make the separation of concerns more clear, Robotlegs MVCS has split the Proxy into 2 classes: a Model for manipulating and persisting the data, and a Service for communicating with remote services. This is good, in my view. But, it seems that many people have a hard time with this approach. There was a lot of debate going on on the puremvc forums over proxies' roles and the best place to retrieve them (in a command vs. directly in a mediator) . The debate has been continued on the robotlegs forums...with an added cause for confusion about the difference between a Service and a Model.
Based on what I've learned over the years from puremvc and robotlegs authors and 'gurus' + all the discussions on different forums + my own experience, I dare to say, that accessing a Model or a Service (injected as interfaces) in a Mediator is absolutely alright, when this kind of coupling is not producing undesirable side effects throughout the application, like, for example, destabilizing the state of the entire application or parts of it, or making it hard to manage the relationships between classes. When loose coupling is very important or when a Mediator becomes bloated with too many responsibilities or has too many dependencies, a Command can encapsulate all the logic for accessing the data. In addition to loose coupling, having the code in a Command makes it easier to change it in a single place, if need be, instead of many places/many mediators.
So, if you wanted, you could have a service-promise resolver directly in a mediator, especially if you don't need a model to persist the data. The service parses the data into a collection of your choice and the mediator simply passes it to the view's list dataprovider. Done.
First of all, to achieve this you'd need to operate on the same instance of a VO. A VO would be mapped as a singleton and then injected into all views needing it, or better into their mediators which would pass the VO to them. BUT, this kind of binding could lead to unpredictable results, if you don't have a mechanism in place to synchronize the data and to update the collection of vos. What if a view is allowed to operate on a part of the model's collection, and another view on another chunk of data, but the VO is always the same instance? Or, as in the AddressBook example, if there were several views, each of them editing a different item from the list? Maybe I don't understand what you meant. Have you tried it out? Does it work?
So, you have the same List/DropDown/DataGrid in different views, whose items are bindable VOs? You update the property on a VO in the result handler of the service, and you expect the list to reflect the changes? Maybe you need BindingUtils or an ObjectProxy for this?
Unless I missed the point entirely, this scenario, even if it worked as you wished, may be harder to manage than the archaic way;)
In the rl AddressBook example, the VOs are allowed to update themselves with the values of the edited VO before they are sent to the Service or from the Service to the Model. But, that doesn't make them more 'bindable' in the sense you've described above.
Why aren't you content with this solution? How are you passing the VO to the model? Where are you calling the service?
You don't need to send every change to the database immediately. That's what Models are for, to hold and manipulate the data in memory. When you decide (on some condition or user interaction) that the data should be sent to the db, you can send only the items (vos) that have been changed. To know which ones have changed, you could flag your changed vos in the collection or something like that.
If you have to send each VO to the database after it has been updated, you probably don't need a Model at all, nor VOs for that matter. Many people use exactly this approach: db->service->event->mediator->view ->mediator->command->service->db or the shortcut view->mediator->service->mediator->view.
To be continued...
Support Staff 9 Posted by Ondina D.F. on 05 Jun, 2015 11:09 AM
I'm re-reading our conversation, and now I'm realizing that you cited my dialog with Stray in your first message also because of the bindable VO that I mentioned in there. It was just a thought I had back then, when I was also struggling to understand the use of concepts like VO and Model in the new robotlegs context (linguistic or conceptual context).
I've never implemented it, because I feared that it would introduce too much complexity into my code.
But, if you think that binding is a better solution to your problems than the combination of Models, VOs and Events, by all means, use it!
Look at Shaun's (the author of robotlegs) examples regarding BindingUtils
, ObjectProxy: http://stackoverflow.com/questions/13904382/trying-to-use-bindingut...
To be continued..
Support Staff 10 Posted by Ondina D.F. on 05 Jun, 2015 02:36 PM
After rereading our discussion, I really don't know anymore what's clear to you already and what's not. This makes it difficult for me to talk about the different use cases, that you presented in a more or less theoretical manner, without repeating myself or without mentioning things that you already know. Sorry for that.
A VO can be used only because it is a strongly typed data carrier and for no other reasons. Imagine a set of properties like color, width, height, x, y, someString, etc.. that will never change. You want to inject them into several views to render their components in a specific way. You could use named injections for each property or for an object or collection of your choice holding those properties. But, a better alternative is to use a strongly typed wrapper for those properties, that the injector can instantiate and map it .toValue in your context-config files. Such a VO could have getters and also other methods like for example one that returns width+height.
Such a VO is also useful when using as3-signals, but that's an entirely other topic and I don't want to get into it.
Also, if a server call returns a set of properties like the ones above, you can, but you don't have to use a VO to transport them to different parts of your application. Any other object may be as well suited for data transport as a VO.
You can keep a set of properties directly in a Model, if you so wish. The Model can keep track of those properties without using a VO. How you access those properties or what kind of an object you use to transport them between classes, it's up to you.
Give me an example. What do you mean by "several types of objects" ? Do you mean something like Users, Books, Pets? If the answer is yes, then one User would be a VO. A Users Model would be the place to keep 1 to n users in memory.
But you said: "I completely understand that VOs should correspond to database rows....", so "several types of objects" might mean something else.
This means to me that you have a UsersModel, a BooksModel and a PetsModel, etc, and
UsersModel can hold a list of potentially hundreds of UserVo s. Right?
I think you know by know the difference between Singleton an mapped asSingleton.
I'm sticking with the Users Model. Do you mean that you'll never need a list of users anywhere in your app, thus why having a UsersModel (users) for a single UserVO ?
Keep the properties of the User in a UserModel (user) with getters, setter and any other methods that you need for CRUD or other operations on the User.
Of course you can call it UserVO instead of UserModel, but it would be confusing. Now, the dilemma remains how to transport the user to the views and from the views back to the model, right? However you want. But, what about using a VO? ;) If a VO is your choice, then we are back to having a UserModel and a UserVO for the purpose of transporting the data, which is ok.
I know that you said later that this wasn't about a database call, but just for me to understand your use case, let's say it was a call to a strange db which would give you just one property at a time for a User, say, call 1 gets you the userName, call 2 userAge, call 3 userPhone and so on. When all properties are loaded, you want to add the UserVO to a list of VOs in a UsersModel? I'm sorry if I got it wrong.
I thought futures and promises would solve exactly this kind of problem, but since I've never used them, can't say much about it. You said in another discussion that you used promises. Why aren't they solving your issue?
How have you solved it before using robotlegs or any other framework?
11 Posted by dkarten on 05 Jun, 2015 05:03 PM
You are correct. A more relevant example may be an app for keeping track of a basketball tournament. You have things like games, teams, rounds, scores, etc. Then we would have things like GameVO, TeamVO, RoundVO, ScoreVO. But they're all very interconnected. Assigning a Score to a game can advance a team to the next round say, or change their record (wins/losses). But these are only single properties, and the rest of the values stay the same. On the model side, we would have a GamesModel, TeamsModel, RoundsModel, ScoresModel all to track collections of their respective VOs and perform operations on them.
Yes, I do. I certainly meant asSingleton.
So what I'm talking about here would be a UsersModel, which would track the collection of users, and then a UserModel, which would perform individual operations on a UserVO. This seems redundant though, but if you pass the UserModel one VO, you could operate on it and have it spit back out a new VO with the updated values, and this doesn't break immutability. I guess UsersModel could have a getUser method, and then any methods that would go in this separate UserModel would just be absorbed into UsersModel and take a UserVO as an argument. Again though, if the UserVO is supposed to be immutable, where do we store all the data we want to operate on without making our UsersModel too fat? Some of my VOs have 15+ properties. Perhaps this is a sign they need to be broken down further into more models and VOs?
As for the single property service calls, I'm pretty happy with the solution I have come up with for them which I mentioned above. The API that I have been given is event driven, so the need for a global object/variables to track features or passing a variable reference through a sequence of event handlers is there. I use a promise chain to do this, but the calls to the server must be executed in a "synchronous" async manner, meaning I cannot make another call until the current one has been resolved. So the process is basically getFeatureA() -> addEventListener -> make server call -> catch server response in event listener -> save value and resolve promise in event listener -> getFeatureB() -> repeat etc.
So getFeatures() returns a chain of promises getFeatureA().then(getFeatureB).then(...). All I was saying is it would be nice to have this promise chain resolve with the values in one cohesive object, but this seems impossible without a lot of anonymous functions. I don't like tracking the properties globally because you have to be more careful about clearing out old values, etc., but it will do for now.
Thanks again for all your thoughts and advice!
Support Staff 12 Posted by Ondina D.F. on 08 Jun, 2015 03:58 PM
Now I understand, or so I think, what's giving you headaches.
Maybe yes, maybe not. It is the same dilemma as with the normalization of database tables. How far is far enough?
It also depends on what the Models represent. Sometimes they are a one to one representation of a db table and the user of your application is presented with the entire set of properties.
Some other time the client has to deal with results from a db join operation. Whether you keep the data in a Model that aggregates those join results, or you split it into more Models, it's up to you, eventually.
If the 15+ properties belonged to the same object and they should always be manipulated together, I would keep them inside a single VO.
Too fat in terms of how many methods the model has, or how many items it has to hold in the collection?
Would having a UsersVO, holding the collection of UserVOs, make your life easier? If yes, then just create a UsersVO.
You don't need a separate UserModel that operates on a single UserVO. The UserVO will always be added/removed/updated to/from/in a collection.
Perhaps you're referring to what I said in my previous post:
" Do you mean that you'll never need a list of users anywhere in your app, thus why having a UsersModel (users) for a single UserVO ? Keep the properties of the User in a UserModel (user) with getters, setter and any other methods that you need for CRUD or other operations on the User."
But, if you know that you'll need such a list of users, having a UserModel and a UsersModel would be redundant indeed.
It looks like you think that having 100+ VOs in a collection of VOs is worse than having 100+ weakly typed objects in a collection?
Maybe you don't need VOs at all, but just a collection kept in a bindable class (UsersVO) and operate on it. As I said, I don't want to discourage you from using bindable models or vos, just that I'm not proficient with this technique, thus I can't help you much.
Not really related to the above:
Personally, I don't like to load tons of data from a server and to keep it in client's memory. I try to paginate large amounts of data, whenever possible. I would also consider caching the data in a local database, sqlite for example, to avoid too many trips to the main server(s).
But maybe that's not what you want or you need.
This sounds to me like a datagrid with columns like this:
Game Name | Game Time | Team One Name | Team One Score | Team Two Name | Team Two Score
I'm going to 'think out loud' about your use case, so excuse me in advance for the following rant and the repetition of questions you asked yourself already ;)
gameName and gameTime are properties of the GameVO, which has lots of additional properties, that may be the subject of yet another datagrid shown in another View. Same for other columns.
Let's call the datagrid, GameOverview for the sake of the discussion.
The first difficulty, I see at the moment, is deciding which kind of data provider should GameOverview utilize: column-wise or row-wise data providers?
GameOverviewModel aggregates only the needed columns from different collections (gameCollection, scoreCollection, etc) into a special collection to be used only by GameOverview
Instead of having a dataprovider for the entire datagrid, you could have different dataProviders for each column.
But, a column in the GameOverview is actually a freestanding collection (an array of gameNames, for example)
The Model corresponding to such a datagrid (say GameOverviewModel) should be able to update the collections representing the columns. If the cells are editable, you want the collection, to which an edited cell belongs, to be update as well, and each view that uses all or parts of the collection should reflect those changes.
On one hand, maybe you don't want GameOverviewModel to keep a reference to many collections that would normally reside in different models, GamesModel, TeamsModel, RoundsModel, ScoresModel.
On the other hand, it wouldn't make sense to assign the entire gamesCollection to the dataprovider of the column that corresponds to gameName, since gameName is just one property of the GameVO.
Then, what if more than one cell has been modified in the GameOverview? How to notify GameOverviewModel about the changes in different collections? A single event with several vos as payload, or several events with one vo? How many events will be needed to notify all interested parties about the change of just one property of just one VO?
What if a cell of GameOverview should be updated first after performing some calculations in a model, like the changes to the score that you mentioned?
What is better, to work with several models, GamesModel, TeamsModel, RoundsModel, ScoresModel, or to have a GameOverviewModel that operates on all collections used in GameOverview? But, if GameOverviewModel is holding those collections, what if another view needs just the gameCollection and nothing more? Which model should take care of it? Instead of operating on all collections, perhaps GameOverviewModel could collaborate with the individual models in order to keep data in sync. A Command is also a good place for orchestrating such complex relationships and data flow.
...lots of possible scenarios and twice as many questions arise all of the sudden. I don't think there is a simple solution to this. At least I can't give you one without giving some thought to the matter.
Do you know the book Enterprise Development with Flex by Yakov Fain and their open source Clear Toolkit? There are some very interesting solutions to bindable collections. Look at DataForm, DataCollection , OfflineDataCollection classes from chapter 3 for inspiration regarding data synchronization functionality. Their DataCollection takes care of the communication with the server as well, which I don't really like, but if you modify the class to act more like a model than like a model+service, it might become useful to you.
Something like Parsley's Decoupled Bindings might have been the solution you are looking for:
http://www.spicefactory.org/parsley/docs/3.0/manual/ (chapter 5)
But Robotlegs doesn't offer such features.
13 Posted by dkarten on 10 Jun, 2015 04:09 PM
Thanks for all your wisdom on this. I will look into the Presentation model and all the other knowledge source you suggested. I am starting to get an idea of how I want to approach the problem, I think I am ready to dive in and let the solution evolve organically. It may not completely obey best practices, but if I can get something that works and stays relatively in the framework, I will be quite happy. You can mark this as resolved!
Support Staff 14 Posted by Ondina D.F. on 11 Jun, 2015 12:18 PM
I'm glad to hear that.
Don't worry too much about not obeying best practices. There is a saying, I don't know if I can translate it well: If the frame is too small, don't cut down the painting.
Anyway, since you are coding with the awareness in mind of what might be divergent from the so called norm, you'll be able to easily refactor your app at some point, should the need arise.
Ondina D.F. closed this discussion on 11 Jun, 2015 12:18 PM.
dkarten re-opened this discussion on 26 Aug, 2015 03:20 PM
15 Posted by dkarten on 26 Aug, 2015 03:55 PM
After much programming, thinking, and reading, I wanted to re-open this with a few more questions and thoughts.
I've come to realize that one of the big problems I was wrestling with above, i.e. mutable vs. immutable VOs is due to a bigger separation. After getting more a of a framework up and running for the application, I've come to realize that I have two cases. On the one hand, there are VOs which should be treated as immutable and shuttled between views and models strictly as carriers of data. On the other, there are a number of entities which are long lived objects throughout the app, and truly defined by their identity (in this case database primary key) rather than their attributes. Once an entity is created, it is used, frequently updated, and persisted throughout the runtime until the user requests it be deleted.
With that in mind, how do entities fit into Robotlegs and the MVCS structure? Should entities have a method that creates a snapshot of their current state in a VO? Should models deal with lists of entities?
Support Staff 16 Posted by Ondina D.F. on 27 Aug, 2015 01:17 PM
It doesn't matter if an Object with attributes is an Entity or a Value Object, they are both belonging to the M layer in the MVCS.
Depending on its role within an application, an Object can be defined as an Entity or a VO. Or, in other words, the same Object can be an Entity in one scenario, and a VO under other circumstances.
Whether there is only one unique entity instance or a set of entity instances, you'd still need to manage their persistence within your application. Your dilemma seems to be about where to do that: from within the Entity itself or in a separate class like an EntityManager or EntityContainer or whatever names those classes have on other platforms. We would call it a Model, that would have a property referencing multiple entities as a collection of some sorts ( array, list, dictionary) and that would also have methods to act upon the collection (find entities by their primary key, update them, etc).
So, in my opinion, from a persistence point of view it doesn't matter if the objects are entities or vos as long as you're dealing with just one object at a time. If you let them update themselves or you use a Model to do that, you'll still be able to send the correct data to an external database.
But, if you need to keep a set (collection) of objects in memory, you need something like a Model to manage their states and lifecycle and to make them available to whomever needs them inside your application.
You can do it like in the AddressBook example that we've already discussed. Instead of sending the updated vo to the Service->DB, you send it to the Model which will find and replace the record in its collection and keep it in memory until you decide to send the data to a database.
Or, do you mean having something like a UserEntity and a UserVO and maybe also a UsersModel? That would be overkill, in my opinion.
Conclusion: If it is more suitable for your project, create your entities with accessors and mutators. To manage and/or keep in memory a set of entities use a class like a Model.
dkarten closed this discussion on 28 Aug, 2015 03:46 PM.
dkarten re-opened this discussion on 28 Aug, 2015 08:04 PM
dkarten closed this discussion on 28 Aug, 2015 09:18 PM.
Ondina D.F. re-opened this discussion on 29 Aug, 2015 08:47 AM
Support Staff 17 Posted by Ondina D.F. on 29 Aug, 2015 08:48 AM
I think your questions about Value Objects and Entities are better answered by this book, that I warmly recommend reading (in case you haven't already):
Implementing Domain-Driven Design by Vaughn Vernon
Here an online article from the book, chapter 10 Aggregates:
Ondina D.F. closed this discussion on 29 Aug, 2015 08:48 AM.