Modern business applications rely heavily on rich domain classes, which in turn rely heavily on polymorphic execution, code reuse and similar concepts.
How can we extend rich domain classes to support complex requirements?
In this webinar, Zoran Horvat will show why an object composition approach is favored over class inheritance when it comes to code reuse and polymorphism.
Watch the webinar to learn:
- How class inheritance can lead to combinatorial explosion of classes
- What the limitations of object composition are
- What design patterns help consume composed objects
- Techniques for creating rich features on composed objects
Applying Object Composition to Build Rich Domain Models on Vimeo.
Download code samples.
Q: How to control if visitor always matches concrete object and there is no implicit conversion?
A: Visitor is designed to match concrete objects. If there is the need to support out-of-band objects, like objects from one hierarchy that can be converted to objects from a different hierarchy, then the compiler will have hard time trying to understand which method of the visitor to invoke.
Major selling point of the Visitor pattern is that it makes obvious to the compiler which method to invoke in every possible situation. The variation – which concrete implementation of a method to invoke – has been turned into an object, a visitor object. That makes it possible to reach enormous flexibility at run time, while remaining within premises of strong types all the time. Not so many designs can do that.
Q: What happened to simplicity? Seems like you are a making an alternative to LINQ-to-Objects to avoid having to deal with a solution, that you call ugly. It seems over-complicated.
A: There are no elegant solutions in complex domains, and certainly no simple ones. It’s only different places to hold complexity. The goal of the game is to make client code simple.
In Visitor pattern, concrete visitors will encapsulate complexity. Chaining calls approach has only saved the caller from having to know the visitor protocol.
One alternative was mentioned by a viewer: Make classes with no common base class implement common interfaces. This is a viable solution unless distinct classes come with different method dependencies and different calling protocols. At that moment, common interface idea is off.
Another alternative is Chain of Responsibility pattern, which I have applied to this same problem in the Tactical Design Patterns in .NET: Managing Responsibilities course on Pluralsight. It works nicely, but fails to differentiate subtle cases, like what happens if an object contains more than one component of requested type.
The worst options are bare hierarchy of classes and public composition (in which the object exposes its content). Class hierarchy promotes code duplication. Public composition prevents future maintenance of the composed class.
Q: Would it be possible for OfClassification<T> method to return an IEnumerable<T> instaled of IEnumerable<Animal>?
A: Classification objects do not reference their containing Animal – that was the design decision. It might be better to expect OfClassification<T> to return IEnumerable<Tuple<Animal, T>>, which then gives entire information to the consumer.
Another question here is how will this method behave if one animal object contains multiple classification objects of the same type – will it return multiple records then? That is one of the difficulties in approach I have shown in the webinar.
Q: Why not use dynamic to implement double dispatch instead of the visitor pattern?
A: Because you don’t know whether the dynamic object will even have the desired feature (like the Start() method which only exists on the Run class). Fundamental feature of double dispatch mechanism is that it lets two concrete objects meet each other.
Q: How to apply the Visitor pattern and composition altogether with dependency injection?
A: Visitor can be injected using common DI techniques. It boils down to selecting a concrete visitor, which is exactly what DI frameworks are good at. There are subtle issues here, though, but they are not hard to resolve. For example, I have requested target objects in all visitor constructors. That would have to be redesigned to fit DI, but as I said, it’s not too hard.
Composition does not fit the DI pattern since there is no object that implements certain type. It is rather an object which is constructed in certain way. We could argue that composite objects are closer to the Builder pattern which codifies the process of building a complex object. In that respect, IoC container (which implements DI) would rather resemble Abstract Factory, which is of lower complexity level compared to the Builder.
Q: How do you persist encapsulated domain entities to database without breaking encapsulation?
A: The persistence problem is not related to application of Visitor pattern, or object composition, as it exists in class hierarchies as well.
There are two levels at which we can attack it. One is to use ORM which can access private data members of a class. Entity Framework and Hibernate can both access private members. You can use that approach to some extent.
In really complex domains differences between OO model and relational model are significant. When you see that persistence is affecting domain model in adverse ways, it is probably time to separate domain model from persistence model. You can then apply a mapping framework to convert proper OO model into flat persistence model and vice versa.
Q: Can we call this pattern in borderlines of SOLID principles?
A: Depending on application, Visitor pattern may be seen as enforcement to SOLID principles, or as an adversary. Here are some guidelines on that:
S – Single responsibility – Each concrete visitor deals with only one feature. Visitor pattern enforces SRP more than the original hierarchy of classes which were doing more than one thing each.
O – Open for extension, closed for modification – If you have a fixed hierarchy, then you will never have to modify abstract visitor. That is the primary niche of the Visitor pattern. It is natively applicable to fixed hierarchies – like classes of animal species, or types of bank accounts, etc. It also supports easy extension, because extending the system boils down to implementing new concrete visitor.
L – Liskov substitution principle – Methods of original concrete classes are now moved to concrete visitors. LSP is violated if a derived class adds method preconditions. Therefore, if original classes had new preconditions added, then concrete visitors hill have to add them too. Conversely, Visitor pattern will violate LSP to exactly the same extent as original classes did.
I – Interface segregation – Original class can implement one interface per concrete operation. With Visitor pattern, each concrete visitor would represent one such interface. Segregation then boils down to selection of a visitor object, which is even more flexible than compile-time interface segregation. This means that concrete visitors will satisfy ISP at least to the same extent as original classes did.
D – Dependency inversion – Since each concrete visitor is a separate class, and all visitors share the same base type, it is possible to inject them as polymorphic dependencies. That is the premise of inversion of control principle. Also, this was the case with original classes which had the same feature. Therefore, DI is supported by both the class hierarchy and by the corresponding hierarchy of visitors.
Conclusion is that the only true difficulty with the Visitor pattern is when the hierarchy of classes is not stable. If we have to add new classes to the hierarchy, then we will have troubles implementing and maintaining the hierarchy of visitors.
Q: How will be the application performance with this approach when we need create several methods?
A: From source code perspective nothing will change. Solution will contain exactly the same number of methods, only they will be moved to different classes.
From run time performance point of view, there is only a negligent penalty. Where one virtual method used to be called, now we will have two virtual methods called. That does not give sufficient motivation to consider performance loss due to application of the Visitor pattern.
About the speaker, Zoran Horvat
After fifteen years in development and after leading a dozen of development teams, Zoran has turned to training, publishing and recording video courses for Pluralsight, eager to share practical experience with fellow programmers. Zoran is currently working as CEO and principal consultant at Coding Helmet Consultancy, a startup he has established to streamline in-house training and production of video courses. Zoran's blog.
Starting with the premise that "Performance is a Feature", Matt Warren will show you how to measure, what to measure and how to get the best performance from your .NET code.
We will look at real-world examples from the Roslyn code-base and StackOverflow (the product), including how the .NET Garbage Collector needs to be tamed!
Watch the webinar to learn:
- Why we should care about performance
- Pitfalls to avoid when measuring performance
- How the .NET Garbage Collector can hurt performance
- Real-world performance lessons from Open-source code
Performance is a Feature on Vimeo.
You can find the slide deck here: http://www.slideshare.net/sharpcrafters/adsa-69947835
Q: Does LINQ perfomance problem raise only in Roslyn or does it have a place with older .Net platforms?
A: With regards to LINQ, there are no major differences in the Roslyn compiler compared to the older one. So performance issues can exist in LINQ across all .NET compiler versions. The example was included because it was a change made to the Roslyn code base itself, not to the code it produces when compiling LINQ.
Q: What is the best setting for GC on Win Server 2012 R2 which hosts 250 ASP.NET MVC apps on IIS. I am talking about gcConcurrent and gcServer in aspnet.config file.
A: Generally, server mode is the best when you are running on a server, but you actually don’t need to do anything, because it’s the default mode in ASP.NET Apps, from https://msdn.microsoft.com/en-us/library/ee787088(v=vs.110).aspx
You can also specify server garbage collection with unmanaged hosting interfaces. Note that ASP.NET and SQL Server enable server garbage collection automatically if your application is hosted inside one of these environments.
Q: Do we get hints, how to measure or which tools are recommended to measure performance issues?
I really like PerfView, it takes a while to find your way around it, but it’s worth it. This post by Ben Watson will help you get started http://www.philosophicalgeek.com/2012/07/16/how-to-debug-gc-issues-using-perfview/, plus these tutorials https://channel9.msdn.com/Series/PerfView-Tutorial I’ve also used the JetBrains and RedGate profiling tools and they are all very good
Q: What other techniques can be applied for embedded dotnet, single use application, to avoid unpredicttable GC hesitation. Considering the embedded device is not memory constrained.
A: Cut down your unnecessary allocations, take a look with a tool like PerfView (or any other .NET profiler) to see what’s being allocated and if you can remove it. This post by Ben Watson will help you get started with PerfView http://www.philosophicalgeek.com/2012/07/16/how-to-debug-gc-issues-using-perfview/. PerfView will also tell you how long the GC pauses are, so you can confirm if they are really impacting your application or not.
Q: How is benchmarking different from finding the difference of timespan between start and end of a function?
A: BenchmarkDotNet does a few things to make its timings are accurate as they can be:
- Using Stopwatch rather than TimeSpan, as it’s more accurate and has less overhead.
- Call the [Benchmark] method once, outside the timer, so that the one-time effects of JITting the method are included in the timings.
- Call the [Benchmark] method several times, in a loop. Even Stopwatch has a limited granularity, so that has to be accounted for, when the methods only takes several nanoseconds to execute.
Q: This is not a question, but an answer for the question about examples for Unit tests not showing performance issues. We need to load data from Azure / SQL server in production, but in Unit tests we have a mock service that responses immediately
A: Thanks, that’s another great example, a mock service is going to perform much quicker than a real service!
Q: What measure could point me in the right direction to know that I could benefit from object pooling?
A: See Tip 3 and Tip 4 in this blog post by Ben Watson http://www.philosophicalgeek.com/2012/06/04/4-essential-tips-for-high-performance-garbage-collection-on-servers/ for a really great discussion on ‘object pooling'.
Q: How does benchmarking work on asynchronous code?
A: Currently we don’t do anything special in BenchmarkDotNet to help you benchmark asynchronous code. It’s actually a really hard thing to do accurately and so we are waiting till after the 1.0 release before we tackle it, sorry!
About the speaker, Matt Warren
Matt is a C# dev who loves nothing more than finding and fixing performance issues. He's worked with Azure, ASP.NET MVC and WinForms on projects such as a web-site for storing government weather data, medical monitoring devices and an inspection system that ensured kegs of beer didn't leak! He’s an Open Source contributor to BenchmarkDotNet and RavenDB. Matt currently works on the C# production profiler at ca and blogs at www.mattwarren.org.
How do you avoid the dreaded "this is not what we asked for" and ensure customer satisfaction when building a new system?
In this webinar, Dino Esposito demonstrates a top-down methodology, sometimes mistaken for plain common sense and often boldly ignored, called UX-Driven Design (UXDD).
UXDD means coming to a visual agreement with customers by using wireframing tools to iterate on sketches of the new system before building it. Then, rather than building the system from the data model, you proceed in a top-down fashion instead. The resulting system may be slow or even inefficient but it will never be the “wrong” system! In addition, UXDD leads to clarity on a few of today’s most popular patterns that are sometimes difficult to understand like CQRS and Event Sourcing.
Watch the webinar and learn:
- An introduction to Wireframing tools
- Proven ways to save on post-first deployment costs
- Insights into better customer relationships
- Better focus on development without 'analysis paralysis'
Building Better Architecture with UX-Driven Design on Vimeo.
You can find the slide deck here: https://www.slideshare.net/sharpcrafters/building-better-architecture-with-uxdriven-design
Q: Is UXDD aplicable for data driven apps such as most enterprise apps, like in banks?
A: It’s mostly about your interaction with users, whether consumers or corporate or whatever. I’ve seen UXDD similar things applied in a large (very large) pharma company. Missing link was that they simply split design of UX and design of code in two steps but design of code was done bottom-up. In general, I see benefits everywhere mostly because that helps taking a task-focused approach to the way you learn about the domain and processes. Particularly relevant I guess in enterprise business.
Q: What is the best system development process to use with UXDD - e.g. DSDM?
A: I see UXDD as two agile steps. And agile means what it usually means to you. But in some organizations distinct steps are problematic. In this case, I tend to see the first UXDD step (wireframes) as a sort of sprint zero. Possibly a repeated sprint zero not repeated for each sprint but more than once.
Q: How best to handle a situation where the cost to implement a screen is a very high? What if there is a better way to implement at a cheaper cost but at a sacrifice of usability.
A: As long as it keeps customers happy, any UX is fine. But users can appreciate MORE and MORE a UX that is super-simple, easy to understand, tailor-made to processes and friendly.
Q: I've heard a lot of from managers, that UI can be generated by data. So the data is essential and for hardcore enterprise it is tabular data. There are numbers of solutions for that approach. Devs modeling data, domain and then get UI for free - from the managers perspective. Any advice on how to convince those managers?
A: Unfortunately data is less and less simply tabular. And users are less and less willing to accept whatever UI a system can autogenerate. That’s precisely the mindset UXDD attempts to address. The simple answer (and most concrete) is that you save money after deployment. Money in terms of support work, fixing bugs, fixing logical bugs. If you don’t run into these problems, you’re probably OK as is.
Q: How is multiple UX Designs handled for a single data model? I mean if i have different UX for different devices rendering the same data how is that handled in UXDD?
A: Multiple frontends (like Web and mobile) talk to possibly different application layers and application layer is the topmost part of the backend. Under the application layer you find the reusable domain logic. Different UX may refer to different processes that orchestrate common pieces of business in different ways. Different frontend match possibly different application layers. (Application layer is one of the layers of DDD layered architecture. The place that orchestrate use-cases.)
Q: Can you please give an example of working with the top down UXDD approach and adjusting the business logic requirements. What is an example of adjusting the Business Logic to fit the User Interface? For example, if we learn that what users need is out of scope with project scope/timeline/resources, how can we affect the Business Logic?
A: The key fact I see behind UXDD is simply that everything starts from the top and only once you’re satisfied with the UX you start arranging the backend. How can you effectively design the BLL if you’re not sure about what users want? BLL is just the next step after UX or the part of UX that fits your scope/timeline/resources.
Q: When performance tuning comes into the place? During development or at late stages of development when you have UI defined completely?
A: UI and the backend share input and output and defining those things is the primary purpose of UXDD. At that point UI and backend can be optimized separately.
Q: Was UML to purpose this idea? And now MS removing it?
A: UXDD screens are essentially implementation of use-cases. And use-case diagrams are a foundation of UML. But in my opinion UML is too much and too cumbersome. Too many diagrams and formalism. But yes there’s some reasonable conceptual overlap.
Q: What's an example of an Event Store?
A: An event store is a database where you store the state of the system in the form of events (this is event sourcing, or having events as the data source of the application). Technically, an event store can be a NoSQL store (Mongo, DocumentDb, RavenDB) but it can be a JSON-friendly store (SQL Server 2016) or specific products like EventStore. Learning about Event Sourcing is helpful.
Q: What you think about "Advanced Prototyping" level with following workflow (e.g. we are working with ASP MVC):
- 1) First we implement prototype in ASP MVC Views with faked ViewModels.
- Use fake ViewModel Repositories, which in future we will replace to real.
- Not repositories of domain objects, but repositories of view models.
- At that time there is no domain objects and logic.
- 2) After some iterations we have working prototype and then we implement domain objects and logic. And connect domain model with view model.
About the speaker, Dino Esposito
Since 2003, Dino has been the voice of Microsoft Press to Web developers and the author of many popular books on ASP.NET and software architecture, including “Architecting Applications for the Enterprise” or "Modern Web Development" or upcoming "Programming ASP.NET Core". When not training on-site or online for Pluralsight, Dino serves as the CTO of Crionet—a fast growing firm that specializes in Web and mobile solutions for the world of professional sports.