This should probably go off list if you wish to continue as it is spam given the topic.
Really? So DDD doesn't say you should add BL code to your entities?
I am talking more about your "method" of adding the BL code. What you are essentially doing is trying to work around serious design problems, the problem is that you in the process make the code that much more difficult to work with and harder to maintain.
I see AOP as a technique to inject code into a class. You apparently see
AOP as a way to do software design. AOP does not just "inject" code into a class, there is a part which can do similar things called "Inner Type Members" aka "mixins" but this concept is not unique to AOP (You can do it quite easily through aggregation) and it carries with it many of its own problems. I am not going to copy and paste your customer example but it is a PERFECT example of where one would want to use a specification/strategy pattern. But first let's look at the "just adding it to the class" example. As you said someone "could" just add these items to the class directly and then they will have a problem when it came time to deal with the second domain .. Too bad ... poor design leads to maintenance problems. I could also put it into a shared module that in turn started a lisp interpreter and used Console redirection to write a lisp program to get back the results .. Of course I am sure even you would concede that to be a bad design. Your suggestion then I presume is to use an inner type member to produce a IsGoldCustomer property on the Customer object. This seems fine in thought but is a complete nightmare .. So I create my customer object (without a IsGoldCustomer proeprty). public class Customer { public int Sales; } I then create a mixin which has the IsGold Customer code in it. public class IsGoldCustomerMixin : IProxyAware { //note we have to use the IProxyAware type interface so the generated proxy will know that it needs to let us know who our proxy is Customer m_Customer; public bool IsGoldCustomer() { return ((Customer) m_Customer).Sales > 1000 } public void SetProxy(object _Customer) { m_Customer = _Customer; } } Great! We have now "seperated" in an AOP based way right? This might work great if we had full language support but instead in .NET we tend to use dynamically generated proxies. If you remember I said this might be more feasable if we were dealing with an aspect aware language. So now we end up with a run time generated class something similar to the following public class CustomerProxy : Customer { private IsGoldCustomerMixin m_Mixin; public bool IsGoldCustomer() { return m_Mixin.IsGoldCustomer(); } } Note that I am leaving out alot of magic that has to happen here dealing with constructors etc. We still have a MAJOR problem though .. although we have this wonderful new IsGoldCustomer method on our CustomerProxy class .. we can't actually USE it unless we revert to a dynamic call .. We see the object as a customer, the customer does not have a IsGoldCustomer method. This also applies to intellisense as we will no longer have intellisense .. So to work around this we now have to create an IHasIsGoldCustomer interface... public interface IHasIsGoldCustomer { bool IsGoldCustomer(); } now we would have to add that to our generated proxy .. public class CustomerProxy : Customer, IHasIsGoldCustomer { private IsGoldCustomerMixin m_Mixin; public bool IsGoldCustomer() { return m_Mixin.IsGoldCustomer(); } } Now in order to actually use our method .. Customer c = CustomerRepository.FetchById(1); //do stuff with c IHasIsGoldCustomer tmp = c as IHasIsGoldCustomer; if(tmp != null) { //someone could have removed the interface by accident bool isgoldcustomer = tmp.IsGoldCustomer(); } So now we finally have it working as an aspect. We still have intellisense support and normal calling conventions but we now have code all over the place that may just start failing (i.e. if you were to forget to add the aspect to the object, the code would just blow up at runtime .. there is no way of checking this). We still have all other sorts of issues to deal with but many AOP frameworks handle them pretty (you know small things like serialization, or remoting this object?). I won't even get into the situation that comes up if you have a mixin that needs to talk to another mixin that may or may not be there and you won't know until run-time. Of course the biggest problem here is that the next place I go may not know or care what a "gold" customer is .. I will however still care about the concept of a CustomerLevel which is the domain concept a specification/strategy pattern would support. This code is significantly more complex than simply adding a specification for the object and we have completely lost the concept of the operation from our ubiquitous language. With a specification we would probably have something along the lines of a GoldCustomerSpecification .. sounds nice right? Using the specification methodology not only are we saving tons of code, we are also coming up with a nice extensible model.
" If you can simply have a set of entities (generated for example)
and inject the BL code at runtime, what's against that? I don't see it." The simple fact of the matter is that is not what AOP gives you. Issues with types, serialization, etc make it a tricky task.
" Isn't that definition-voodoo? I mean, 'it's not a domain concept,
so it must be bad'. How can a BL rule not be a domain concept? You just use AOP to inject it in the class." It most certainly is not an explicit domain concept .. you have created a mixin class/interface pair that can be applied to ANY domain object while I have abstracted the concept of giving customers levels .. Customers having levels based upon a specification is a domain concept .. the mixin is not. I can re-use the domain completely at another place who does Platinum/VIP/normal customers simply by changing my specifications. I maintain that as you use more apps (with dependency injection) your refactorring becomes less and less providing you are dealing with different logic withint he same domain. Eventually you hit a point where moving the domain to an identical model with a new set of logic is as simple as writing a series of strategies and specifications for the particular domain because you have previously abstracted them. The power of AOP is the exact same reason why it is a poor choice. The mixin is something that can be applied to _ANY_ object. While this is hugely successful when it comes to cross cutting concerns this is not good for a domain concept.
Closing the eyes for that just because it's not compliant with the
definition of AOP is IMHO erm... limiting yourself. :) I don't care if its "compliant" with AOP .. I am closing my eyes because it creates a brittle solution while adding high amounts of complexity to the domain when there is a simpler, better solution that better abstracts my domain while not putting in the knowledge overhead of an AOP framework
Perfectly fine by me. Because others use DDD, I got this idea of using AOP
for bl in >those contexts.
There are other techniques, I use these as well, though that doesn't make
using AOP for it 'wrong'. There's no such thing as 'wrong' As I gave in an example earlier .. I could shell out to a consolt to lisp interpreter and have it do some of this logic for me .. thats not wrong either just not a good path to building maintainable software.
ps: did you like the article, book?
I question the appropriateness of the article in a DDD based book although it is in an interesting counter point to have included with the book, but I tend to design systems that reused with multiple datasources that I do not control so data driven doesn't work for me. The problem is 20 pages or so really isn't enough to actually discuss all of the differences between a data driven and a domain driven approach (in fact I would say 200 pages would not be enough). With 20 pages you can't even discuss the repercussions of model driven design vs data driven. As for the book you can see my comments on the praise page On 6/4/06, Frans Bouma <[EMAIL PROTECTED]> wrote:
> * No on the contrary. If you want to do true DDD, and > you want to > re-use your entities but in a different context / app, you > will run into the problem of having to alter the BL code > inside the entities. With AOP you can avoid that. That was my > point. So 1/ntier development style. > * > > Frans, > > I would love to see you post that to the DDD mailing as a > best practice. I think you would have better luck selling > tickets to a bull fight at a PETA rally. Really? So DDD doesn't say you should add BL code to your entities?
I am curious as to how many times you have actually tried > this, I have read about such possibilities in academia (all > of which were using languages with aspect support btw) but I > have never seen someone try to actually implement it ... let > alone implement it in a language such as C# which does not > have language based aspect support (yes you could use > something like EOS but at this point we enter into completely > obscurity). Well, let's not get ahead of ourselves. AOP is quite 'new' compared to other techniques, and as I'm not in the Java camp, it's more or less a new territory for me as it is for most of us here. I see AOP as a technique to inject code into a class. You apparently see AOP as a way to do software design. That's fine but I don't care. The thing is that if someone cooks up a definition, I don't see why I should follow that definition and use the technique solely in that context. > The general goal of AOP is not to move the core concern out > of an object, it is to modularize cross cutting concerns. > This modularization has huge immediate gains in the form of > reducing coupling and simplyfying the domain allowing objects > to deal with their core concerns (a perfect example is > caching the return value from a service). If you are not > actually reusing your aspects in multiple places you have > added a significant level of complexity to your system with > almost nothing to show for it. Let me give you an example. You have an entity class Customer. You have 2 apps to write. There's this concept of a gold customer. You have to validate if a customer is a gold customer. Both apps have different rules for that. It appears to me that you could use AOP to inject this rule code into the customer entity. You could also write the rule into a validator object and add that to the customer and use a strategy pattern. You can also write it hardcoded into the entity class and keep two codebases. Now, it seems to me that AOP can be used for this, right? It's a way to extend the class with logic without adding the code to the class. Now, you might say "Noo! that's against the goal of AOP", but why should I care about that? If I don't use mock objects, am I then violating some TDD contract as well? The core question is: why do you limit yourself by not using a technique (!) for some aspect (pun intended) in your program? You've to know that I don't care about definitions. So if someone says "That's not AOP, so you shouldn't call it AOP", fine, I can understand that, but if I get a nickle for every time someone says ORM for O/R mapping, I'd be very rich, so let's leave that out of the discussion, ok? :) Now, back to my example. Of course you can write a validator, or BL object and add that to the customer object at runtime, using a strategy pattern. In fact, llblgen pro uses that pattern for validators and concurrency filter factories. But that doesn't mean it has to be done that way. Some people want to add the code inside the entity classes. For example through partial classes. That's cool, but it mitigates the fact that if they want to re-use the entity classes in another app, the BL logic might be outdated and they have to alter it inside the code, creating 2 codebases. Not that great. I'm not saying it's ideal, but it IS a way some people will write software. If you can simply have a set of entities (generated for example) and inject the BL code at runtime, what's against that? I don't see it. [...] > The concept of domain driven design is about expressiveness > before it is about reuse. A well distilled domain that > actually is a good model will by its definition be able to be > reused at another location that shares the space. If it is > not able to be re-used one should be questioning the > original model and looking for ways to make it more > expressive, not simply throwing decorations on it for the new model. Nice in theory, but it won't work in a lot of cases in practise. THe core reason for this is that it's very very hard to create the perfect model. In theory, it's logical to create the perfect model. In practise the model always has flaws and needs refactoring. If it's re-used in multiple apps, refactoring gets more and more expensive. > The biggest place that these definitions would hurt a domain > is in the concept of an ubiquitous language. > Specifications/Strategies compliment the ubiquitous language > where as aspects (for business logic) would confuse it as the > aspects themselves would not be domain concepts. Isn't that definition-voodoo? I mean, 'it's not a domain concept, so it must be bad'. How can a BL rule not be a domain concept? You just use AOP to inject it in the class. > Just so that I am clear, I believe in using aspects at the > domain layer (I personally use them heavily). I do not > however believe that they should be used for non-cross > cutting concerns as you are gaining little in their use. > If the aspects are providing modularization then I am all for > them, if they are simply 1-1 relations with business logic I > think someone completely missed the real power of both concepts. How can I miss some power if I utilize the power of the concept to make something work which didn't work before? > My challenge to you is to come up with a hypothetical > situation where you have a non-cross cutting business rule > that the existing constructs offer a less revealing solution for. I'm not in school anymore, Greg, so I won't do assignments. It's also not about 'existing constructs which offer a less releavling solution'. It's about how people tend to write software. As an O/R mapper vendor I know how many different ways there apparently are how people want to work with entities, trust me on that. Telling everyone that there's just 1 way to do it is stupid as it also depends on the context of the project, the skills of the developer and frankly, most of these 'methodologies' have great things but also sucky things, so a developer is IMHO better of picking the best things of various methods and work out a good method for him/herself. I hopefully don't have to come up with an example how for example TDD zealots try to force you every little aspect of their methodology on you, even if you just like 50% of it. For example a math library is better written in a procedural language. Yet OO languages also have a math library. Not ideal, but hey, it's OO so let's write the methods in a big static class. For some OO fetisjists this is incredibly bad. For others it's simply using the tools at hand, do their thing and move on. I'm not sure who's better of at the end of the day. > Also, from everything I have heard/read you completely > disagree with the very root concept of domain driven design > so I am curious where this opinion/advice comes from. I think > the title of your paper in ADDDP "The Database Model Is the > Domain Model" really summarizes your position well. > Given that you completely disagree with the very root concept > of domain driven design, how can you profess strategies for > implementing domain driven design? Well, perhaps I'm not as closed minded as some people on this list, eh? ;) What *I* think about DDD and how people should write software doesn't make it *THE* way to write software. It also doesn't imply DDD or other methods suck so much you should avoid them. I just disagree with some root concepts. I also know others disagree with me and think the opposite. Perfectly fine by me. Because others use DDD, I got this idea of using AOP for bl in those contexts. There are other techniques, I use these as well, though that doesn't make using AOP for it 'wrong'. There's no such thing as 'wrong' in software engineering (no not even in the context of stored procedures ;)), some things have just more cons than pros in a given context, so it might be not the wisest choice, that's all. As we're all at the start of an era where software is more and more generated, where BL rules are more and more applied to objects at runtime through workflow systems and BL engines, it might be AOP has a place in that spectrum because it has the techniques on board to make that happen. Closing the eyes for that just because it's not compliant with the definition of AOP is IMHO erm... limiting yourself. :) FB ps: did you like the article, book? =================================== This list is hosted by DevelopMentor(r) http://www.develop.com View archives and manage your subscription(s) at http://discuss.develop.com
-- If knowledge can create problems, it is not through ignorance that we can solve them. Isaac Asimov =================================== This list is hosted by DevelopMentorĀ® http://www.develop.com View archives and manage your subscription(s) at http://discuss.develop.com