tag:blogger.com,1999:blog-7821856652257554779.post541895337515301512..comments2023-10-22T12:47:47.534+02:00Comments on Andrzej on Software: DCI and RailsAndrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.comBlogger19125tag:blogger.com,1999:blog-7821856652257554779.post-25993548538741619272011-07-25T09:03:32.962+02:002011-07-25T09:03:32.962+02:00I'm just starting to scratch the surface of un...I'm just starting to scratch the surface of understanding the implications of this approach. So far, in my thought experiments, it seems like DCI could be very powerful for structuring code. <br /><br />I'm not entirely sure that Object#extend is the best way to express this in Ruby, I'd prefer to see 'proper' composition (eg., `@waiter = Waiter.new(person)`), but I'm speculating a bit there. I will have to try out some experiments.<br /><br />One thing that stands out is that Rails' controllers are very anemic compared to the concept of Context in DCI. Specifically, I think that Rails' convention of tying Controllers tightly to Data (Models) must be broken to allow for Contexts that express richer concepts than the simple CRUD operations that Rails' controllers are so good at. I suspect that pursuing DCI will lead to a much richer, dare I say more RESTful, approach to application design. <br /><br />It looks like the Context should explicitly name the Roles involved in a given Interaction (request or series of requests), and maybe even the available outcomes (state transitions). <br /><br />I may be making up that last part, but I've been starting to think about annotating available state transitions to facilitate discoverability of REST-based HTTP services, and there may be a way to do that using the DCI model.<br /><br />All together DCI sounds like a really big win!Emmanuelhttps://www.blogger.com/profile/08802744341843266711noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-18672965699788325152011-07-25T05:29:58.156+02:002011-07-25T05:29:58.156+02:00@nick
I don't think you have to do `User.from...@nick<br /><br />I don't think you have to do `User.from_xml`. You can do it in another way, like:<br /><br />Xml::Representer.parse_user(...)<br /><br />Which returns a User instance.<br /><br />So, I think modules which represent the logic layer could also have their module functions, not just instance methods.Gimihttps://www.blogger.com/profile/08843495788810709140noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-66336623601573343842011-07-22T15:01:18.714+02:002011-07-22T15:01:18.714+02:00The lack of unextend in ruby is a serious barrier ...The lack of unextend in ruby is a serious barrier to implementing this model. (I've not examined mixology to understand its true capabilities.) Furthermore, it's not clear to me that ruby's extend is a good model for dci. In multiple places, the article talks about objects referring to each other <i>by role</i>, and you don't get that effect with extend.<br /><br />It seems to me that they entire role-object binding has to take place via some sort of proxy object. The proxy wraps the object, and the roles get added to the proxy. When the interaction completes, the proxy is discarded and the model's methods are undisturbed.<br /><br />As I said, however, this does not address how reference-by-role is implemented.<br /><br />Nathan ZookAnonymousnoreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-86365767851932972792011-06-09T09:01:50.153+02:002011-06-09T09:01:50.153+02:00This was quite valuable to me. Thanks Andrzej!This was quite valuable to me. Thanks Andrzej!Jonas Bruunhttps://www.blogger.com/profile/17440627316083739087noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-74874318782667195012011-05-26T20:24:37.670+02:002011-05-26T20:24:37.670+02:00Thank you for the an interesting post. I have a qu...Thank you for the an interesting post. I have a question about the topic.<br /><br />All DCI examples, I have seen, for sake of simplicity work with couple of objects. But in the real world a programmer deals with graphs of objects. So it rather two object graphs interact in a context.<br /><br />The questions are:<br />* should roles be propagated among graph members <br />* how to propogate role/roles along graph nodes<br /><br />In terms of Domain-driven design the question could be: how to inject roles to agregate members?<br /><br />Thanks in advance.Pavel Mitinhttps://www.blogger.com/profile/03323256413368409095noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-1665949048582977852011-02-15T23:37:57.721+01:002011-02-15T23:37:57.721+01:00@nick
Yes, I see the problem now, thanks for the ...@nick<br /><br />Yes, I see the problem now, thanks for the explanation.<br /><br />Unfortunately, I don't know any solution to this problem. <br /><br />I wonder if in practice that makes a difference (apart from memory usage). Whenever a new request comes you inject a new role which should overwrite all the important methods, the ones that you want to use.Andrzej Krzywdahttps://www.blogger.com/profile/06399276063142826365noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-20787785755100847182011-02-15T16:07:21.542+01:002011-02-15T16:07:21.542+01:00@Andrzej: Yeah but if you do the extension like th...@Andrzej: Yeah but if you do the extension like that you push new methods to the User class which won't be removed after the actual user instance gets GCed - the new methods will persist in the class. For instance, in Rails production mode, the first time you extend the user instance (and you also push methods to its class) these class methods will be around in the following requests as well. Can you see the problem now?Unknownhttps://www.blogger.com/profile/10389579328050857517noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-74339005034401120262011-02-15T14:34:46.235+01:002011-02-15T14:34:46.235+01:00@nick
If I understand you correctly you would lik...@nick<br /><br />If I understand you correctly you would like your module to include also class methods, right?<br /><br />I use the module.extended method which is called whenever a module is extended in an object:<br /><br />module EventUser<br /> def self.extended(object)<br /> object.class.send(:has_many, :attendances)<br /> end<br /> <br /> (..)<br />endAndrzej Krzywdahttps://www.blogger.com/profile/06399276063142826365noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-21429770793668706862011-02-15T14:25:33.816+01:002011-02-15T14:25:33.816+01:00Hi Andrzej, thanks for that great post! In a gem I...Hi Andrzej, thanks for that great post! In a gem I'm currently designing I use that DCI approach (I didn't know it's called like this ;-) to mix a Representer role into a model that needs to be represented (talking about REST representations).<br /><br /><br />user.extend Xml::Representer<br />user.to_xml<br /><br /><br />This works great. However, I wonder how to do that on a class layer, as my models need factory class methods.<br /><br /><br />user = User.from_xml(..)<br /><br /><br />Staying DCI-ish, my class User shouldn't know the .from_xml per default. Nevertheless, if I'd mix that behaviour into User, I pollute the User class since the new methods will stay over the whole process.<br /><br />I'm thinking about anonymous subclasses for that<br /><br /><br />Class.new(User).extend Xml::Representer<br /><br /><br />but I can already see problems with this. Do you have any ideas about this?<br /><br />Thanks again,<br />NickUnknownhttps://www.blogger.com/profile/10389579328050857517noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-66451753841235604932011-02-12T18:19:03.876+01:002011-02-12T18:19:03.876+01:00@Alexander
Thanks for pointing the mixology gem. ...@Alexander<br /><br />Thanks for pointing the mixology gem. <br /><br />It's an interesting point whether we should unextend a role after the "use case". I didn't think about that, but maybe that's a good idea, especially when the role are is injected from a cell.<br /><br />Thanks!Andrzej Krzywdahttps://www.blogger.com/profile/06399276063142826365noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-68102528912609430252011-02-12T13:48:59.396+01:002011-02-12T13:48:59.396+01:00it's not defined how should you discard ole fr...it's not defined how should you discard ole from object (there is no .unextend method in ruby)...<br /><br />that reminds me mixolgy gem - it could mix/unmix mixins(modules)Alexander Shvetshttps://www.blogger.com/profile/03587543964238748674noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-50865170832999663932011-02-12T06:01:27.167+01:002011-02-12T06:01:27.167+01:00@Wes
As I mentioned earlier to provide accurate b...@Wes<br /><br />As I mentioned earlier to provide accurate benchmarks we would have to run them against more complex system.<br /><br />I don't undermine your benchmark. However in my opinion you tested <b>average case</b>. You can't really state how #extend affects method call performance. This is typical benchmark trap.<br /><br />For instance you don't measure GC at all which I suppose should have (positive) impact on performance in context of DCI.<br /><br />I've benchmarked <b>the worst case</b> <a href="https://gist.github.com/823457" rel="nofollow">here</a>. It is more DCI oriented so BlankUser singleton is slightly thiner than User object. <br />Here you can notice 800%-1200% #extend overhead. This is edge-case but in my opinion you should also note that in your blog post.<br /><br />I don't get why you question my results. I wrote that <i>Basing on my observations overall performance is unaffected</i>. I didn't provide benchmarks here because we would have to take some bigger system into account to get <b>accurate</b> results and show some numbers.<br /><br />Anyway that's cool you've provided some numbers. Thanks to that we have a bit wider look at how #extend performsUnknownhttps://www.blogger.com/profile/03361200848023752374noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-52081717434248284472011-02-11T20:21:51.871+01:002011-02-11T20:21:51.871+01:00I question where Michal got his benchmarks on usin...I question where Michal got his benchmarks on using an object's singleton class versus a method defined by the originating class? I <a href="http://exposinggotchas.blogspot.com/2011/01/premature-optimization-and-dynamic.html" rel="nofollow">blogged</a> about this recently finding the difference is negligible for most applications.Anonymoushttps://www.blogger.com/profile/06730699060835686773noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-36824426295703162672011-02-11T15:33:20.253+01:002011-02-11T15:33:20.253+01:00This looks amazing and definitely something I want...This looks amazing and definitely something I want to use.<br /><br />This could be a really handy Gem. <br /><br />dci generate role buyerNerianhttps://www.blogger.com/profile/12280944359753165682noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-51305794606354620022011-02-11T12:59:58.960+01:002011-02-11T12:59:58.960+01:00@Andrzej, @Karol
I've benchmarked #extend ind...@Andrzej, @Karol<br /><br />I've benchmarked #extend indeed. We have to take various aspects into account. No doubt already defined method call is way faster than extend + method call. Approximately 800-1200%. <br /><br />But we can't benchmark that way, that's true only for very thin classes. We have to look for overall application performance. Usually classes are fat and initialization process is more complex for 'monolithic' objects. <br /><br />Giving objects only needed capabilities significantly decreases initialization process thus we have some performance benefits.<br /><br />GC is even more important. Simpler objects = less memory consumption = less garbage collector. Average rails application wastes 20%-30% time in GC.<br /><br />In my opinion one can't straight said that using .extend is faster or not. It will be slower when application uses very simple objects and may be faster for very complex ones. <br /><br />Basing on my observations <b>overall performance</b> is unaffected and as Andrzej mentioned it may even perform better.Unknownhttps://www.blogger.com/profile/03361200848023752374noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-26854259076141359382011-02-11T11:31:05.571+01:002011-02-11T11:31:05.571+01:00@Karol
According to Michal's benchmarks it...@Karol<br /><br />According to Michal's benchmarks it's negligible. .extend is not an expensive operation. <br /><br />The fact that objects are thiner now can only make them perform faster.Andrzej Krzywdahttps://www.blogger.com/profile/06399276063142826365noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-9766309838822178582011-02-11T11:10:03.402+01:002011-02-11T11:10:03.402+01:00@Michal
1.
At the moment I keep them in app/mod...@Michal<br /><br />1. <br /><br />At the moment I keep them in app/models, however I think it's best to group them in feature-specific directories, like app/models/groups and this is the direction I will go with it.<br /><br />2. <br /><br />Reusability of roles is an awesome idea that I want to research more. I think it's not only possible in two objects in one app, but also in other apps. <br /><br />If you keep the role feature-specific and independent of other parts of your app, then it should be easy to reuse it in other apps that have similar features.Andrzej Krzywdahttps://www.blogger.com/profile/06399276063142826365noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-79644359203156132302011-02-11T11:06:00.232+01:002011-02-11T11:06:00.232+01:00Any performance problems ? (You call extend on eve...Any performance problems ? (You call extend on every request) or is it negligible ?Unknownhttps://www.blogger.com/profile/13049439491918866303noreply@blogger.comtag:blogger.com,1999:blog-7821856652257554779.post-56404601647384426882011-02-11T10:56:13.705+01:002011-02-11T10:56:13.705+01:00Really valuable post. DCI approach seems to be sur...Really valuable post. DCI approach seems to be surprisingly easy to understand and to use in our projects. DCI seems to perfectly fit into MVC model.<br /><br />2 questions come to my mind:<br /><br />1. How do you organize your modules on disk? Do you keep them in app/models or some other directory?<br /><br />2. Do you find it possible and reasonable to reuse modules/roles between between distinct objects? For instance having GroupMember role I would like to use it for both User and Conact.Michałhttp://mlomnicki.comnoreply@blogger.com