tag:blogger.com,1999:blog-1727031811590975354.comments2022-04-09T15:16:48.752+02:00Eventually InconsistentPiotr Wyczesanyhttp://www.blogger.com/profile/02381372089894674945noreply@blogger.comBlogger49125tag:blogger.com,1999:blog-1727031811590975354.post-8485096831747032642020-09-10T00:06:18.149+02:002020-09-10T00:06:18.149+02:00This comment has been removed by the author.Daneel Matthewhttps://www.blogger.com/profile/00176505697486928909noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-50325733300872502612017-09-27T16:08:45.155+02:002017-09-27T16:08:45.155+02:00nicenicebenzemahttps://www.blogger.com/profile/15988553096060514464noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-57460704120645993512016-10-16T19:41:50.327+02:002016-10-16T19:41:50.327+02:00Hi Weronika, thanks for the comment and sorry for ...Hi Weronika, thanks for the comment and sorry for the late response. ;)<br /><br />In some ways, the localization business is similar to the software business. People make mistakes, so the Translator needs Proofreader (just like we need code review). Automation makes sure, that valid Proofreader will get valid input from valid Translator - so that Project Manager does not have to do it manually. This is more important in bigger projects with many languages and many people with many skills involved.<br /><br />Also finances for the project can be automatically calculated based on many factors, like previous notes of given Translator. Project Manager just have to check if everything looks OK.<br /><br />Translators work with different tools, so the system has to be able to automatically send and receive data from them, so that everybody is up to date all the time.<br /><br />The goal is to minimize all the repetitive Project Manager's work, so that she can be more productive doing more valuable thigs and maintaining the pace.<br /><br />Does that answer your question? :)Piotr Wyczesanyhttps://www.blogger.com/profile/02381372089894674945noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-70423195359528977672016-09-15T15:41:44.380+02:002016-09-15T15:41:44.380+02:00Interesting post, and good to see you writing agai...Interesting post, and good to see you writing again!<br /><br />> so that she does not have to do anything, except for monitoring the progress<br /><br />Could you elaborate on that, e.g. give a specific example? Unless that's a trade secret ;)<br /><br />For example I wonder how can you automatically ensure the translation quality or manage deadlines with vendors, is that by e.g. setting automated reminders for vendors and other people, and updating progress when a monitored piece of work is finished?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-66291598548336969942014-08-05T12:40:53.981+02:002014-08-05T12:40:53.981+02:00Thanks for another good trick! :)
Moving is a grea...Thanks for another good trick! :)<br />Moving is a great idea - go for a walk and so on.<br /><br />Unfortunatelly in my case it didn't help, since I was stuck for couple of days... So I had to move - I don't like spending nights in the office. ;)<br />Nevertheless this is valuable insight!Piotr Wyczesanyhttps://www.blogger.com/profile/02381372089894674945noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-51416554599821951052014-08-05T12:31:14.975+02:002014-08-05T12:31:14.975+02:00"I was sitting in front of my laptop with a b..."I was sitting in front of my laptop with a bunch of paper cards scattered all around me" therefore...<br /><br />#9 Move your body<br />Cognitive processes flow differently depends on body is engaged or not. <br />So, stand up, step ahead, gesticulate, speak aloud.<br /><br />Tip #1 works better when you engage body as well. So put a domain object on the floor, stand on it and grab one book for each responsibility...Are you heavy- or lightweight? <br />And then name your self in the Indian style - you know long, long descriptive name.<br /><br />Then donate sb, with one of your books and name yourself again. Repeat until you reach English-style name; short one :)<br />Anonymoushttps://www.blogger.com/profile/03968505875451301931noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-44059388261264958312014-08-04T10:19:49.257+02:002014-08-04T10:19:49.257+02:00Thanks for the context and other valuable question...Thanks for the context and other valuable questions. :)Piotr Wyczesanyhttps://www.blogger.com/profile/02381372089894674945noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-61083530690186735212014-08-04T10:12:46.796+02:002014-08-04T10:12:46.796+02:00Great list :-)
To add a little context: it helps...Great list :-) <br /><br />To add a little context: it helps if you list the constraints explicitly on a whiteboard, collaborating with stakeholders. Constraints can be business rules, but also anything else (limited budget, performance, team members who don't know the technology or the architecture, the number of network calls, concurrency, cognitive overload for the end-user, maintenance costs...) There may be a lot of these hidden or implied constraints that block you from being truly creative. We all have internal filters that shoot down ideas before we even speak them out loud.<br /><br />Then ask questions such as: How would we model this if there was no database, and there was only one user, and we had unlimited time to build it, and the business didn't care about this specific rule? Your brain will be free to come up with great ideas. Then adding back a single constraint at a time, allows you solve each constraint as a single small problem, instead of a nested big one. <br /><br />You'll also discover that some of the constraints are in fact not important, or can easily be discarded.Anonymoushttps://www.blogger.com/profile/03944020719166045813noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-64342297460531270272014-06-22T06:09:32.918+02:002014-06-22T06:09:32.918+02:00Thanks Piotr, this is what I wanted. If you don...Thanks Piotr, this is what I wanted. If you don't have an inspiration for further post, this could be one :]Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-25039954552678157522014-06-19T15:58:59.395+02:002014-06-19T15:58:59.395+02:00But to be honest, I can not remember the last time...But to be honest, I can not remember the last time I created any stub... ;)Piotr Wyczesanyhttps://www.blogger.com/profile/02381372089894674945noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-49963803887482601762014-06-19T15:53:01.460+02:002014-06-19T15:53:01.460+02:00First of all - sorry for the late response.
And n...First of all - sorry for the late response.<br /><br />And now the answer: <br /><br />It all depends. :)<br /><br />I tend to inject all additional dependencies as closures to my methods - no IoC magic - in the model everything has to be as explicit as it can be.<br />If there are too many of them in one method, that is a smell, that the design may be broken.<br /><br />Sometimes I need some Value to be injected (calculated in different Aggregate, or in other system hidden behind Anti-Corruption Layer) - then in test I can just create that Value manually.<br /><br />Sometimes I need some Domain Service, or Function - then in the test I can just pass the concrete implementation from my domain, or create dumb-stupid stub implementing the interface of that Domain Service/Function.<br /><br />Does this answer your question?Piotr Wyczesanyhttps://www.blogger.com/profile/02381372089894674945noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-80743485882869109322014-06-12T06:35:20.410+02:002014-06-12T06:35:20.410+02:00Hi, Piotr,
Great post especially in this "TD...Hi, Piotr,<br /><br />Great post especially in this "TDD is dead" [Martin Fowler etc] time and fighting with mocking in TDD. <br />What's your approach to "not mock" ?<br /><br />You mentioned that all additional things should be injected to models. Do you inject concrete implementations while testing? Do you use IoC containers while testing or just inject dependencies manually (in constructor) ?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-18932701933416940102013-07-30T22:04:24.039+02:002013-07-30T22:04:24.039+02:00Thank you for your kind words. :)Thank you for your kind words. :)Piotr Wyczesanyhttps://www.blogger.com/profile/02381372089894674945noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-28798891403724199822013-07-30T20:21:08.349+02:002013-07-30T20:21:08.349+02:00Wonderful article summarizing the Axon framework! ...Wonderful article summarizing the Axon framework! I've been showing this to new developers who are getting acquainted with CQRS and Axon.Peter Davishttps://www.blogger.com/profile/10421999352110832388noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-13583955299087696732013-07-17T08:57:55.240+02:002013-07-17T08:57:55.240+02:00Nice to hear that, David. :)Nice to hear that, David. :)Piotr Wyczesanyhttps://www.blogger.com/profile/02381372089894674945noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-41321945299907323182013-07-16T19:59:31.869+02:002013-07-16T19:59:31.869+02:00Thanks this series has helped with my quest for le...Thanks this series has helped with my quest for learning CQRS and Domain Driven Design.Anonymoushttps://www.blogger.com/profile/12106468483360572726noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-81119055908286503692013-06-11T13:58:51.925+02:002013-06-11T13:58:51.925+02:00I see your point, but I think (for now), I will st...I see your point, but I think (for now), I will stick to protecting Entities. ;) Especially when things are not stabilized yet.<br /><br />When Entity's interface changes it is probably because language has changed. And therefore the conceptual "whole part", which Aggreagte represents, may also change. The argument with interface 'pollution' speaks to me a little, but then, maybe it is worth to concider, if Aggregate's boundaries are not too wide...<br /><br />I still consider direct accessing Entities as a smell - role interface, or VO may be something in the middle, that can do the trick.<br /><br />As you suggested, there is no right/wrong. I just added another option to protect Aggregate's structure, and to stop and think for a moment. ;)<br /><br />Greets,<br />PeterPiotr Wyczesanyhttps://www.blogger.com/profile/02381372089894674945noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-34965921117039042752013-06-11T12:51:14.605+02:002013-06-11T12:51:14.605+02:00Hi, Piotr,
Just a quick reply.
I could argue tha...Hi, Piotr,<br /><br />Just a quick reply.<br /><br />I could argue that changing the interface of the aggregate root each time the behavior of an entity changes (e.g. adding or removing methods, changing signatures and names) is violating that same principle. Direct entity access has gotten a bad rep over the years because it's associated with getters/setters galore and not thinking in terms of aggregates. That doesn't mean it's bad per sé. To me it's just another "flavor" of how you access entities within the aggregate. Basically you trade AR interface 'pollution' for entity coupling. At least, that is what I've learned over the last couple of years. It's still TDA, but with a query method to select the right entity/entities. From a language perspective it may even be clearer to do so (I'm alluding to the query method name here). With the "root only" way of accessing entities, the query criteria method arguments might get mixed with the command criteria method arguments and end up hurting readability of the code (although, in all honesty, some of this could be mitigated by using a bit of lambda magic).<br />The argument "but now you know the entities and how they are structured inside the aggregate", although a valid concern, really has to do with how likely that structure is/those entities are to change. If things have stabilized, I see no harm in using entities directly.<br /><br />With transient I was rather hinting at "transiently pass it to another aggregate that could do useful, side-effect free stuff with it", not particularly a UI. Both roles interfaces and value object could help complete that mission as well, sure.<br /><br />You see, I don't think either one of is right/wrong. It's about having options and being able to motivate why you'd go about it a certain way. Having a bunch of juniors accessing entities directly will probably end with a BBOM where the concept of an aggregate is only a distant memory ;-)<br />So for any future readers, take Piotr's advice to heart, practice, practice, and when you've gotten to the point you really "get it", you can experiment with direct entity access. Oh boy, unbuttoning my shirt, coz that just sounded like I'm an expert. I'm not, I just tend to play a lot with different approaches.<br /><br />Kind Regards,<br />Yves.yreynhouthttps://www.blogger.com/profile/14253275954206073248noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-85782408290556854992013-06-11T10:57:43.993+02:002013-06-11T10:57:43.993+02:00Thanks for Your valuable comment, Yves.
Sorry for ...Thanks for Your valuable comment, Yves.<br />Sorry for tha late response, but You made me think a little. :)<br /><br />I can clearly see, that You can fetch an entity from aggregate and perform some method on it from application layer. I can also agree, that this entity may have referrence to the Aggregate Root and perform some additional action to force AR to take some steps to maintain its invariants.<br /><br />But...<br />It seems to me, like a violation of the Single Responsibility Principle here... I may be wrong, but it just looks like a smell for me. <br />Entity has to do something, and then, totally in addition, has to go back to AR and take care of inforcing invariants, which may even not be aware of.<br />I much more prefer "Tell, Don't Ask", and I think, that You should tell AR to do something (react with it's graph internally).<br /><br />Regarding those interfaces. Suppose, that the domain really enforces us to expose entities to application layer, as You suggested. <br />Then, only those interfaces are public. Entity still should be protected, because You are dealing with the interface. :)<br /><br />If You want to use entity transiently (for UI?), You may always return some form of projection (Value Object) representing the state that You are interested in to show.<br /><br />As You said - it depends on Your environment - I agree with that one in 100%. :) On the tactical level, You may use whatever patterns You need.<br />Maybe sometimes You can violate the SRP, but You have to be extremely careful and You have to know what You are doing. Only big boys can play like that. :)<br />That's why I coined this rule of thumb - it is not an axiom. :)<br /><br />Again, thanks for Your input.Piotr Wyczesanyhttps://www.blogger.com/profile/02381372089894674945noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-75479304811522285292013-06-10T12:23:44.086+02:002013-06-10T12:23:44.086+02:00I "somewhat" agree. Let me explain: I do...I "somewhat" agree. Let me explain: I don't mind exposing entities if the intent is for application services to look them up in the aggregate and then invoke a method on the entity directly. Internally, the entity could have a reference to the aggregate's root which is still responsible for enforcing all invariants. I could also sprinkle one or more role interfaces onto the entity, exposing only allowed command or query methods (CQS). I don't mind exposing entities in general if the idea is to use them transiently. Protecting from developer stupidity may be a concern, but using code and access modifiers is the wrong way to go about it IMO. The reason I feel this way is because I strongly believe in collaboration between objects. I don't want to confine myself to "only use the root" school of thought. I might take a different stance when I'm using a language that promotes a functional and immutable style or when "all" interactions (even changes to related aggregates) are communicated using messaging (but then the coupling or "stuff you need to know how to use this aggregate" shifts towards messaging), especially when collaborators have state required for the given aggregate to protect one of its invariants. In the end, it boils down to making a choice about what works in your environment, so no disrespect. What you're describing seems like a perfect fit for "the only way you're gonna speak to this aggregate is by using a message (and I don't mean the OO interpretation of calling a method by that) and sending it to him", almost like an actor. So there you have it, my nuanced point of view :-)yreynhouthttps://www.blogger.com/profile/14253275954206073248noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-75315217381049910572013-04-16T09:24:48.360+02:002013-04-16T09:24:48.360+02:00:)
No problem - remember, that there were two sid...:)<br /><br />No problem - remember, that there were two sides of the coin - I did like majority of your talk. ;)Piotr Wyczesanyhttps://www.blogger.com/profile/02381372089894674945noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-90187228472253376382013-04-16T00:47:26.658+02:002013-04-16T00:47:26.658+02:00Ouch:) Thanks for the constructive feedback.Ouch:) Thanks for the constructive feedback.Anonymoushttps://www.blogger.com/profile/03968505875451301931noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-24157152022038227862013-01-05T12:21:56.717+01:002013-01-05T12:21:56.717+01:00Hello Banq.
I appreciate, that you like this prese...Hello Banq.<br />I appreciate, that you like this presentation and described it in chinesse on your webpage.<br /><br />I took a quick look into your implementation and it is interesting - it uses jdon as I see. <br /><br />However, in this code I can see, that Aggregate Root (Match) can return it's internal state. This state of course is immutable, but still... ;) The match example is extremely simple - what if some mutable entities were exposed in that way?<br /><br />In the end, I can imagine, that your implementation can be a valuable example for many people. <br /><br />Greets.Piotr Wyczesanyhttps://www.blogger.com/profile/02381372089894674945noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-47943389522701846332012-12-20T02:12:51.586+01:002012-12-20T02:12:51.586+01:00I have written the Match full souce code, in here:...I have written the Match full souce code, in here: https://github.com/banq/jdonframework/tree/master/example/cqrs%2BesAnonymoushttps://www.blogger.com/profile/15310360195309753222noreply@blogger.comtag:blogger.com,1999:blog-1727031811590975354.post-28840922558043728812012-05-21T09:36:37.079+02:002012-05-21T09:36:37.079+02:00Heh actually... I didn't thought about this. :...Heh actually... I didn't thought about this. :)<br />But You are completely right! Yet another similarity. :)Piotr Wyczesanyhttps://www.blogger.com/profile/02381372089894674945noreply@blogger.com