Hi, I''m currently evaluating the conversion of a j2ee app to a RoR app. Without going into much detail, the app lets users compose a meal and shows the amounts of nutrients associated to that meal (eg salt, sodium, ...). These nutrients are read from a database. In the original app we use a "service" that abstracts all the database level code etc. This service implements an interface that defines the functionality. That way, we can swap the services when needed, but the interface stays the same, so no adjustments are needed. (eg. McDonaldsService instead of ''normal'' food, when the app is placed in a McDonalds to say something) And that''s where my problem lies. How can I achieve the same level of abstraction in Rails? In concreto, how can I define my model so that I can change the original model to another model without changing much? The only solution I see at the moment is defining a very general model that fits all the different services, and put everything in a big table. However, that way we are losing the power of abstraction we had with j2ee. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On 2/6/07, Joram <joram.barrez-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > Hi, > > In the original app we use a "service" that abstracts all the database > level code etc.Could you describe this service in more detail? Some of us might know specific details about the Java stuff you are doing.> This service implements an interface that defines the functionality.Well Ruby makes the whole java concept of interface disappear. Look up "duck typing" - if two Ruby classes have identical method definitions they are interchangeable. If they share subsets of method definitions, they are interchangeable in contexts where only those subsets are used.> That way, we can swap the services when needed, but the interface > stays the same, so no adjustments are needed. > (eg. McDonaldsService instead of ''normal'' food, when the app is placed > in a McDonalds to say something) > And that''s where my problem lies. How can I achieve the same level of > abstraction in Rails?Well a rails user might consider that an obfuscation, not an abstraction. And the question of whether that abstraction is desirable comes to mind. It just strikes me as an unusual way to achieve separation of customer data. You could just have separate databases for each customer, or maintain a customer table that has relates to the master food/nutrient lookup table.> In concreto, how can I define my model so that I can change the > original model to another model without changing much?Are you changing the model or the data? I see nothing in the problem that would indicate that the food_product, ingredients, nutritional_information models are essentially different between (e.g.) McDonalds and Ben & Gerrys, just that each customer would offer a customer specific range of food products.> The only solution I see at the moment is defining a very general > model that fits all the different services, > and put everything in a big table.Thats pretty much how a Rails user would do it, but they would define multiple tables for each model and relate them correctly.> However, that way we are losing the power of abstraction we had with > j2ee.Do you need that power? Or is that abstraction solving a problem introduced by a weak previous implementation? Like inadequate distinction between customer data (objects) and actual model types (classes). I am sorry if I came across a bit aggressive/blunt but your problem appears to be the kind of overcomplicated java-centric solution to a simple problem that I have to deal with far too frequently than I should have to. It actually sounds like you basically maintain different databases/data models for each customer with different ORM strategies, and try to treat them as similar at the ''service'' level by wrapping each ORM implementation in a common interface. A Rails solution would seek to normalise your DB schema first by doing appropriate E-R modelling. In the Java/J2ee/Java Web Framework world it is more common to treat the database as an implementation detail, and go with code-first approaches (which gets a lot of Java projects into trouble). regards, Richard. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Thank you Richard for your long reply! I''ve gathered some more information about the problem. The "service" approach is used to abstract the database totally from the rest of the application. The benefit of doing that is that the datamodel can change in a drastic way, but the rest of the app is unaffected since a service is used to access the information. The problem is that in fact the datamodel can change (eg another data source provider, forced by the government, so no discussion is possible about the database schema). By changing the datamodel, the objectmodel however should not change. What does change is the translation between the data- and objectmodel. However, in Rails, when changing the datamodel the objectmodel is changed automatically (which is in most cases a good thing). But if the model changes (eg other combination of attributes to achieve the same functionality) the controller will likely have to change... So that''s what my question is about. Is there any way in Rails to define an ''interface'' to a model, so I can use this interface in the controllers. When the model changes because the data model changes, the controllers should not be affected. Thank you for your time! Joram On Feb 6, 2:53 pm, "Richard Conroy" <richard.con...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On 2/6/07, Joram <joram.bar...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > > Hi, > > > In the original app we use a "service" that abstracts all the database > > level code etc. > > Could you describe this service in more detail? Some of us might > know specific details about the Java stuff you are doing. > > > This service implements an interface that defines the functionality. > > Well Ruby makes the whole java concept of interface disappear. > Look up "duck typing" - if two Ruby classes have identical method > definitions they are interchangeable. If they share subsets of method > definitions, they are interchangeable in contexts where only those > subsets are used. > > > That way, we can swap the services when needed, but the interface > > stays the same, so no adjustments are needed. > > (eg. McDonaldsService instead of ''normal'' food, when the app is placed > > in a McDonalds to say something) > > And that''s where my problem lies. How can I achieve the same level of > > abstraction in Rails? > > Well a rails user might consider that an obfuscation, not an abstraction. And > the question of whether that abstraction is desirable comes to mind. It just > strikes me as an unusual way to achieve separation of customer data. You > could just have separate databases for each customer, or maintain a > customer table that has relates to the master food/nutrient lookup table. > > > In concreto, how can I define my model so that I can change the > > original model to another model without changing much? > > Are you changing the model or the data? I see nothing in the problem that > would indicate that the food_product, ingredients, nutritional_information > models are essentially different between (e.g.) McDonalds and Ben & Gerrys, > just that each customer would offer a customer specific range of food > products. > > > The only solution I see at the moment is defining a very general > > model that fits all the different services, > > and put everything in a big table. > > Thats pretty much how a Rails user would do it, but they would define multiple > tables for each model and relate them correctly. > > > However, that way we are losing the power of abstraction we had with > > j2ee. > > Do you need that power? Or is that abstraction solving a problem introduced > by a weak previous implementation? Like inadequate distinction between > customer data (objects) and actual model types (classes). > > I am sorry if I came across a bit aggressive/blunt but your problem appears > to be the kind of overcomplicated java-centric solution to a simple problem > that I have to deal with far too frequently than I should have to. > > It actually sounds like you basically maintain different databases/data models > for each customer with different ORM strategies, and try to treat them as > similar at the ''service'' level by wrapping each ORM implementation in a > common interface. > > A Rails solution would seek to normalise your DB schema first by doing > appropriate E-R modelling. In the Java/J2ee/Java Web Framework world > it is more common to treat the database as an implementation detail, and > go with code-first approaches (which gets a lot of Java projects into trouble). > > regards, > Richard.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On 2/6/07, Joram <joram.barrez-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> However, in Rails, when changing the datamodel the objectmodel is > changed automatically (which is in most cases a good thing). > But if the model changes (eg other combination of attributes to > achieve the same functionality) the controller will likely have to > change... > So that''s what my question is about. Is there any way in Rails to > define an ''interface'' to a model, so I can use this interface in the > controllers. When the model changes because the data model changes, > the controllers should not be affected.Ruby has this built in. Let''s say you have a table to store an item name (string) and it''s price in dollars. class Item < ActiveRecord::Base # columns are name and dollars end You originally have the price in dollars, but you change the datamodel to have the price in pesos: class Item < ActiveRecord::Base # columns are name and pesos CONVERSION_VALUE = 10.9378 # 1 Dollar = 10.9378 pesos def dollars pesos/CONVERSION_VALUE end def dollars=(value) self.pesos = value * CONVERSION_VALUE end end This gives you the same interface as the model with dollars. Jeremy --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Joram wrote:> However, in Rails, when changing the datamodel the objectmodel is > changed automatically (which is in most cases a good thing). > But if the model changes (eg other combination of attributes to > achieve the same functionality) the controller will likely have to > change... > So that''s what my question is about. Is there any way in Rails to > define an ''interface'' to a model, so I can use this interface in the > controllers. When the model changes because the data model changes, > the controllers should not be affected.Joram, I hear and I believe that I understand what you are saying. There is no notion of an "interface" per se in Ruby, as others have stated. One way to go is to add methods directly to your model classes which would provide a model-agnostic set of behavior for your controller to use. Or you could build another layer and create a set of mediator/adapter classes that would be used "between" your controller and model objects. Basically, this would be the same set of methods as you might create given the first approach, but actually factored out into their own objects (which, frankly, they probably should be in the first place). Obviously, you would have to manage the marshaling/unmarshaling of data between the models and this new layer that the controller manipulates. Bottom line, is that you are free to create other objects to supplement the Rails framework if you feel that you need them. I''m curious to hear whether your database schema has already changed enough to justify such a heavily decoupled approach. Thanks, Wes -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
apsoto-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
2007-Feb-07 18:02 UTC
Re: Coding to an interface in RoR?
Well since the database is abstracted why do you need active record models? Why not just use plain ruby objects or the Struct class if it''s just data? However, if you want some sort of ''interface'', I would do as such: Define a module as your interface, but in this case it''s also getting implementation, not just the ''contract'' the interface brings: Module MyInterface def method1 end def method2 end end In your object that requires that interface include the module, require ''my_interface'' class MyModel include MyInterface end On Feb 6, 4:24 am, "Joram" <joram.bar...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Hi, > > I''m currently evaluating the conversion of a j2ee app to a RoR app. > Without going into much detail, the app lets users compose a meal and > shows > the amounts of nutrients associated to that meal (eg salt, > sodium, ...). > > These nutrients are read from a database. > In the original app we use a "service" that abstracts all the database > level code etc. > This service implements an interface that defines the functionality. > > That way, we can swap the services when needed, but the interface > stays the same, so no adjustments are needed. > (eg. McDonaldsService instead of ''normal'' food, when the app is placed > in a McDonalds to say something) > And that''s where my problem lies. How can I achieve the same level of > abstraction in Rails? > > In concreto, how can I define my model so that I can change the > original model to another model without changing much? > The only solution I see at the moment is defining a very general > model that fits all the different services, > and put everything in a big table. > However, that way we are losing the power of abstraction we had with > j2ee.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On 2/6/07, Joram <joram.barrez-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > Thank you Richard for your long reply!No problem.> The "service" approach is used to abstract the database totally from > the rest of the application.Essentially below the waterline, everything is custom, you get an implementation-specific PersistenceService, which returns only implementation-neutral types (models). The database ORM is effectively wrapped by whatever you are using.> The benefit of doing that is that the datamodel can change in a > drastic way, but the rest of the app is unaffected since a service is > used to access the information.Well the implementation of everything below service layer is not trivial.> > The problem is that in fact the datamodel can change (eg another data > source provider, forced by the government, so no discussion is > possible about the database schema). By changing the datamodel, the > objectmodel however should not change. What does change is the > translation between the data- and objectmodel.I understand. This is a strategy to re-use all code above the service-layer, and make it pretty much 100% implementation neutral. But this becomes only implementation neutral from a *type* or *interface* perspective. If the schema is very different from the original reference (i.e. totally different table relationships) several problems creep in: - first you will lose a lot of performance without leaning heavily on Hibernate style performance features (like in memory object caching). - you are also probably limiting your ability to perform unusual queries against the DB, as the implementation of the service layer has to translate the relationships, which means that query implementations will be limited - you are doing a lot of CPU-intensive model translation in the context of your application> > However, in Rails, when changing the datamodel the objectmodel is > changed automatically (which is in most cases a good thing).Well that would be a *feature* of rails. Though Rails does have features for working with legacy databases, like defining getters in models and mapping them to differently named table fields. Though if relationships change there is not a lot you can do there.> But if the model changes (eg other combination of attributes to > achieve the same functionality) the controller will likely have to > change... > So that''s what my question is about. Is there any way in Rails to > define an ''interface'' to a model, so I can use this interface in the > controllers. When the model changes because the data model changes, > the controllers should not be affected.Well you kind of can. This is close to the Java model you describe, but there is no service, or distinction between service models, and controller -used models. 1. You can just define arbitrary models with no relationships 2. map the models to the implementation specific table schema, using a simple vendor specific configuration code and/or file 3. Do Model.find(:foo) at the controller level and tease the relationships and data conversion together using model helpers (that use vendor specific libraries or mixins) 4. The models will present a consistent interface to controllers and views 5. It will also perform like an absolute dog, Rails isn''t meant for this kind of in-code model mapping, and you are likely to be pulling back bigger result sets than necessary Depending on the size of the source database, you could simply create a second database (possibly even in memory) and translate the implementation specific database into the reference database. Not a perfect solution, keeping the reference database (that the models look at) up to date is a problem. There is also the "I hate the people I work with, and in 2 weeks time I am going travelling the world" approach: - do implementation specific metaprogramming - use metaprogramming techniques to dynamically alter your models & relationships to match the implementation database - quake in fear at the insanely ambitious use of metaprogramming, but keep your fingers crossed, as *it just might work* There is also the other Rails approach: 1 - writing controllers & views is simple, just make a bespoke implementation for each schema model, and keep the tests intact 2 - refactor controllers and views to use the new models 3 - bill accordingly regards, Richard. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Thank you Jeremy, Wes, Apsoto and Richard for your contributions! You have given me insight into a difficult subject. I haven''t got much to add anymore at the moment, your information has given me a lot to think about! Greetings, Joram On 7 feb, 20:02, "Richard Conroy" <richard.con...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On 2/6/07, Joram <joram.bar...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > > Thank you Richard for your long reply! > > No problem. > > > The "service" approach is used to abstract the database totally from > > the rest of the application. > > Essentially below the waterline, everything is custom, you get an > implementation-specific PersistenceService, which returns only > implementation-neutral types (models). > > The database ORM is effectively wrapped by whatever you are using. > > > The benefit of doing that is that the datamodel can change in a > > drastic way, but the rest of the app is unaffected since a service is > > used to access the information. > > Well the implementation of everything below service layer is not > trivial. > > > > > The problem is that in fact the datamodel can change (eg another data > > source provider, forced by the government, so no discussion is > > possible about the database schema). By changing the datamodel, the > > objectmodel however should not change. What does change is the > > translation between the data- and objectmodel. > > I understand. This is a strategy to re-use all code above the service-layer, > and make it pretty much 100% implementation neutral. But this becomes > only implementation neutral from a *type* or *interface* perspective. If the > schema is very different from the original reference (i.e. totally different > table relationships) several problems creep in: > - first you will lose a lot of performance without leaning heavily on Hibernate > style performance features (like in memory object caching). > - you are also probably limiting your ability to perform unusual queries > against the DB, as the implementation of the service layer has to > translate the relationships, which means that query implementations will > be limited > - you are doing a lot of CPU-intensive model translation in the context > of your application > > > > > However, in Rails, when changing the datamodel the objectmodel is > > changed automatically (which is in most cases a good thing). > > Well that would be a *feature* of rails. Though Rails does have features > for working with legacy databases, like defining getters in models and > mapping them to differently named table fields. Though if relationships > change there is not a lot you can do there. > > > But if the model changes (eg other combination of attributes to > > achieve the same functionality) the controller will likely have to > > change... > > So that''s what my question is about. Is there any way in Rails to > > define an ''interface'' to a model, so I can use this interface in the > > controllers. When the model changes because the data model changes, > > the controllers should not be affected. > > Well you kind of can. This is close to the Java model you describe, but > there is no service, or distinction between service models, and controller > -used models. > 1. You can just define arbitrary models with no relationships > 2. map the models to the implementation specific table schema, using > a simple vendor specific configuration code and/or file > 3. Do Model.find(:foo) at the controller level and tease the relationships > and data conversion together using model helpers (that use vendor > specific libraries or mixins) > 4. The models will present a consistent interface to controllers and views > 5. It will also perform like an absolute dog, Rails isn''t meant for this > kind of in-code model mapping, and you are likely to be pulling back > bigger result sets than necessary > > Depending on the size of the source database, you could simply > create a second database (possibly even in memory) and translate > the implementation specific database into the reference database. > Not a perfect solution, keeping the reference database (that the > models look at) up to date is a problem. > > There is also the "I hate the people I work with, and in 2 weeks time > I am going travelling the world" approach: > - do implementation specific metaprogramming > - use metaprogramming techniques to dynamically alter your models > & relationships to match the implementation database > - quake in fear at the insanely ambitious use of metaprogramming, > but keep your fingers crossed, as *it just might work* > > There is also the other Rails approach: > 1 - writing controllers & views is simple, just make a bespoke implementation > for each schema model, and keep the tests intact > 2 - refactor controllers and views to use the new models > 3 - bill accordingly > > regards, > Richard.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---