So I've established in previous posts how sometimes it's prudent for me to use collections of objects in our application. In my attempt to figure out the right relationship between service/data/value objects, I have went through far too many way too embarrassing designs to belabor; the fortunate thing being that none of them made it to production.
In my 1st approach, I wasn't really thinking about having a service layer. My desire was that app should just be able to ask for a property, and get a guaranteed response--it should never have to know what method to call in order to populate that object ahead of time. This was the frame of mind that I was trying to codify in my "Iterating Business Object" post. This meant that the value object itself knew how to get its own value if one hadn't already been defined.
But I have abandoned that and decided to use the more conventional service model approach. The discussion about "don't come to me, I'll come to you," though only vaguely related kind of convinced me that this approach was an acceptable one. Admittedly, some small part of my mind still thinks the former approach would be really cool, but being a noob, I defer to the currently accepted best practice here.
So I mentioned how we have 100 or so products, and about 3 major subjects, and that when you provide a subject to a product, you end up with a report. The thing about reports is that they also heavily cross-link to other reports (a la, "want to more details? try this report..."). And, of course, part of the search interface involves the user choosing a report for the subject. So in a single request cycle, we are dealing with details about more than one product (but only ever one report--we need to build links to the other reports, but don't need the actual handler, data, and view(s) associated with it).
So this has become my congealed approach to handling value objects, services, and collections. I have a service object, which is a singleton, and has a bunch of methods that talk to the data layer (singleton) to get product details, populate those into product objects (request scope, service uses the "provider" concept to get these objects), and add each product object to a collection (another provided object in the request scope). The service always checks whether the product is in the collection first before adding it. The implementation doesn't ever talk to the collection (shouldn't anyway), it talks to the service which returns either a single object or an array of objects.
I believe this is fairly standard, and it is working really well. We have about 6 different ways to get products (by id, by the report URL, but subject types...). To facilitate this in the collection, whenever I add a product, I index it against the necessary keys for getting it later. This way, I don't have to loop through the array holding all the products each time. The index is just each value in the key and the corresponding product element index in the collection array.
The problem I ran up against today was the need to iterate over the collection in groups. Obviously, this is really easy with queries. Additionally, if it ever becomes necessary to retrieve products by a different index, then I have to create a new access method, as well as a method that will create/populate the index when its added. This seems a bit too procedural. What'd be really cool is a generic getProductBy(property, value) method, but then I need to have an index on *every* property! And what happens when I need to get products by more than 1 criteria, which the way our business works is bound to happen sooner or later?
So super-awesome thing: query column values can be set to objects =0 So I haven't actually built it out yet, but maybe the internal storage mechanism for the collection could actually be a query, instead of an array--after all, queries are generally super-efficient in Coldfusion. Each property on the object would be a column in the query, with an additional column holding the object itself. This makes it so simple to get only the products needed from the collection, even if there's more than one criteria. It also makes it easy to order the collection, which can additionally facilitate grouping. The grouping itself would still need to be done in the implementation (e.g. by comparing the current object to the previous one), and the all the properties about the value object would be stored in 2 places (in the object itself as accessors, and in the collection as a query). Once the products where selected, the column holding the object could be converted to an array via either listToArray(valueList()) or a simple loop...
I'm stoked. Hope this works out well. The only thing left then is some sort of consistent pattern for providing micro-data sets (which usually end up being children of larger value objects) without needing to build out the entire service/collection/value-object model. And related to that, I continue to run into instances where these micro data-sets have the same properties, but are accessed differently/separately in the application. Maybe they do just need to be built into collections of objects... ugh... that seems like overkill.
Geek stuff, including, but not limited to, Coldfusion, Javascript, AJAX, CSS, HTML, and SQL
Tuesday, October 18, 2011
Sunday, October 16, 2011
Fear of change... or reasonable skepticism
Ben Nadel offers some comfort, from 2008, and a very articulate, substantive discussion regarding the value of OOP in Coldfusion. I'm not up-to-date on where his mindset has evovled to in the past 3 years, but some very knowledgeable people have spoken up against pure OOP, and I feel like the distinction between data display versus behaviors hits the nail on the head.
http://www.bennadel.com/blog/1385-Object-Oriented-Programming-And-ColdFusion-What-s-The-Point-.htm
It feels good to have concrete validation of what I have been so dyspepsic over, instead of feeling like a boy crying wolf all the time.
But how to integrate the two worlds? Recently, I've found that working with value objects can do some good, not only in instances where the data has associated behaviors either, but also when the models are used in various places throughout the site, and you want one consistent access mechanism, but are not using the same data access routines (i.e. stored procedure calls) to populate the value objects each time.
We work on a reporting site for a "sporting" organization. You can build reports based on different players in the sport. So taking to heart the concept of encapsulate what varies (I think that's how it goes), a report is an abstract concept that has an abstract concept of subject. We have 3 main types of subjects currently in our app, and about 100 or so different reports. People can build lists of favorite subjects in the sport, but they don't always know the specifics of the player, and may need to distinguish between one or more player who share the same name or other details... So there is a search interface that might return more than one subject. So that is at least 3 different places where I need to deal with subjects in the application: reports, search results, and favorites lists.
In this case, setting up an interface that represents what all the subjects have in common, which isn't much (an ID, a subject type, a subject name/means of identification), allows me to create a contract between the lower, less specialized/more generalized parts of the site and the specific details of both a given subject and a report. A page is always a page, but if a page is a report, then I know I have access to a subject and to that subjects type, ID, and name--onrequeststart and the site header doesn't any longer have to determine who the subject is based on the what report is being requested and build a name for each different subject based on the various pieces of data needed for identifying it.
Additionally, when I populate a subject for a report, 99% of the data is the same as when I populate it for a favorites list or for search results, but sometimes there is more or less data about the subject depending on the context. Additionally, since we try to limit trips to the database, sprocs might be composites of more than one sproc, in which I return the base data, as well as the stuff unique to this context all in one shot. Having a SubjectService provides one common interface to populating the subject value objects with as much, or as little data as needed.
So all in all, OOP has worked out exceptionally well for me in the last few months that I have really started trying to use it based on best practices and design conventions. But last week, for some reason I started to really take it all too far and try to push everything into value objects, because, well, everything should be done consistently. Truth be told, starting out with this stuff, when an approach isn't sitting right with me, instead of trusting my 12 years of experience as a programmer, I figure I must be doing something wrong, not getting it, etc... Then I do a 180 and think "no, I'm not going to let all this new-fangled shiny codes the kids are into nowadays undercut my august skills." Anyway, seeing experts in the community struggle with the same thing is reassuring.
http://www.bennadel.com/blog/1385-Object-Oriented-Programming-And-ColdFusion-What-s-The-Point-.htm
It feels good to have concrete validation of what I have been so dyspepsic over, instead of feeling like a boy crying wolf all the time.
But how to integrate the two worlds? Recently, I've found that working with value objects can do some good, not only in instances where the data has associated behaviors either, but also when the models are used in various places throughout the site, and you want one consistent access mechanism, but are not using the same data access routines (i.e. stored procedure calls) to populate the value objects each time.
We work on a reporting site for a "sporting" organization. You can build reports based on different players in the sport. So taking to heart the concept of encapsulate what varies (I think that's how it goes), a report is an abstract concept that has an abstract concept of subject. We have 3 main types of subjects currently in our app, and about 100 or so different reports. People can build lists of favorite subjects in the sport, but they don't always know the specifics of the player, and may need to distinguish between one or more player who share the same name or other details... So there is a search interface that might return more than one subject. So that is at least 3 different places where I need to deal with subjects in the application: reports, search results, and favorites lists.
In this case, setting up an interface that represents what all the subjects have in common, which isn't much (an ID, a subject type, a subject name/means of identification), allows me to create a contract between the lower, less specialized/more generalized parts of the site and the specific details of both a given subject and a report. A page is always a page, but if a page is a report, then I know I have access to a subject and to that subjects type, ID, and name--onrequeststart and the site header doesn't any longer have to determine who the subject is based on the what report is being requested and build a name for each different subject based on the various pieces of data needed for identifying it.
Additionally, when I populate a subject for a report, 99% of the data is the same as when I populate it for a favorites list or for search results, but sometimes there is more or less data about the subject depending on the context. Additionally, since we try to limit trips to the database, sprocs might be composites of more than one sproc, in which I return the base data, as well as the stuff unique to this context all in one shot. Having a SubjectService provides one common interface to populating the subject value objects with as much, or as little data as needed.
So all in all, OOP has worked out exceptionally well for me in the last few months that I have really started trying to use it based on best practices and design conventions. But last week, for some reason I started to really take it all too far and try to push everything into value objects, because, well, everything should be done consistently. Truth be told, starting out with this stuff, when an approach isn't sitting right with me, instead of trusting my 12 years of experience as a programmer, I figure I must be doing something wrong, not getting it, etc... Then I do a 180 and think "no, I'm not going to let all this new-fangled shiny codes the kids are into nowadays undercut my august skills." Anyway, seeing experts in the community struggle with the same thing is reassuring.
Saturday, October 15, 2011
Enums redux and fear of change
The more I refactor the site to use objects, the more I find areas where enums would be handy, but are just too much overhead for the pay-off. When will we get custom data-types without cfc creation in Coldfusion?
Also, my past posts seem cynical. I am, by nature, cynical of programming and of the http protocol. It is strangely encouraging to know how well the world can operate on concepts so hastily developed and deployed in so many ways, but depressing too. I love learning new things, but am wary of getting excited over shiny new objects that lead to following someone off a cliff. Also learning is something of a war, after all, isn't it? Rewiring our brains, shedding our former selves, and all that jazz...
I have been much more aware lately that the world moves too fast for my tastes, at least the one I'm part of. It's not speed itself that bothers me, but the lack of means and desire to do due diligence. I am prone to inertia, and I try to fight that lately, but I dread the moment when this internal war backfires. My code is much more error-prone lately, understandable when learning something new, but I don't know how much sympathy the business will have...
My code worked before, dammit. It was fast, it was organized (albeit according to a self-made structure that existed only in my head), it was secure, and it was error-free. I love the promise of structure and shared understanding and self-documentation that OOP brings to the table: a place for everything and everything in its place. But I do not like the pressure I feel to implement it, which comes most likely from myself, but sometimes feels like its the whole community ganging up on me and my outdated ways, and I do not like the absence of a "junk drawer" solution, where things that don't fit or make sense can be stuffed. Also, the sort of artificial imposition of order via proliferate hoop-jumping contributes to this feeling that I'm standing on a house of cards, or at least my job is.
I am speaking in hyperbole for the most part, trying to put this shapeless surliness into perspective...
Also, my past posts seem cynical. I am, by nature, cynical of programming and of the http protocol. It is strangely encouraging to know how well the world can operate on concepts so hastily developed and deployed in so many ways, but depressing too. I love learning new things, but am wary of getting excited over shiny new objects that lead to following someone off a cliff. Also learning is something of a war, after all, isn't it? Rewiring our brains, shedding our former selves, and all that jazz...
I have been much more aware lately that the world moves too fast for my tastes, at least the one I'm part of. It's not speed itself that bothers me, but the lack of means and desire to do due diligence. I am prone to inertia, and I try to fight that lately, but I dread the moment when this internal war backfires. My code is much more error-prone lately, understandable when learning something new, but I don't know how much sympathy the business will have...
My code worked before, dammit. It was fast, it was organized (albeit according to a self-made structure that existed only in my head), it was secure, and it was error-free. I love the promise of structure and shared understanding and self-documentation that OOP brings to the table: a place for everything and everything in its place. But I do not like the pressure I feel to implement it, which comes most likely from myself, but sometimes feels like its the whole community ganging up on me and my outdated ways, and I do not like the absence of a "junk drawer" solution, where things that don't fit or make sense can be stuffed. Also, the sort of artificial imposition of order via proliferate hoop-jumping contributes to this feeling that I'm standing on a house of cards, or at least my job is.
I am speaking in hyperbole for the most part, trying to put this shapeless surliness into perspective...
Iterating Business Objects - Redux
After extensive consideration (perhaps not of that high a caliber, but who needs quality when you have quantity...), we decided that IBOs are not the right answer for us, and that true value objects will work just fine. I still haven't run any load testing, so it remains to be seen.
I find it annoying that small sets of data should still be modeled, for posterity, as VOs. The other thing is that sometimes the business is just messy. For instance, an individual can have a number of different licenses. They can only have a single of one sort of license, but multiples of other licenses. We treat the former license differently display-wise too, asking for it specifically by type, not merely outputting it in a standardized grid or anything as we handle the latter licenses. Additionally, there may be a historical record of actions taken when the individual was serving in the capacity of that license, however they may no longer hold the license, and we do not care about the license details any longer, but we do care about the actions taken, and the actions taken are each their own value object because they in no way share attributes, but they only have about 5 properties...
I assume there is some better way to do this, and that trying to impose value objects on micro data sets is self-defeating. It seems kind of ridiculous that OOP needs to be so rigid, and it probably isn't, but my encounters with it so far imply that. I am leery of readily-accepting mob-mentality borne of not fully understanding something but never wanting to question the authority of the guru spouting nonsense... That is probably too harsh, but I'm just saying, I'll cut you.
I find it annoying that small sets of data should still be modeled, for posterity, as VOs. The other thing is that sometimes the business is just messy. For instance, an individual can have a number of different licenses. They can only have a single of one sort of license, but multiples of other licenses. We treat the former license differently display-wise too, asking for it specifically by type, not merely outputting it in a standardized grid or anything as we handle the latter licenses. Additionally, there may be a historical record of actions taken when the individual was serving in the capacity of that license, however they may no longer hold the license, and we do not care about the license details any longer, but we do care about the actions taken, and the actions taken are each their own value object because they in no way share attributes, but they only have about 5 properties...
I assume there is some better way to do this, and that trying to impose value objects on micro data sets is self-defeating. It seems kind of ridiculous that OOP needs to be so rigid, and it probably isn't, but my encounters with it so far imply that. I am leery of readily-accepting mob-mentality borne of not fully understanding something but never wanting to question the authority of the guru spouting nonsense... That is probably too harsh, but I'm just saying, I'll cut you.
Subscribe to:
Posts (Atom)