4

I'm a bit confused by some object-oriented analysis and design (OOA&D) concepts.

In OOA&D, what recommendations should be followed in order to produce a viable conceptual Domain Model?

How should classes be identified in that process? I've read about a number of varying English language analysis and refining processes which indicate nouns in the use cases as candidate classes and verbs as operations/responsibilities. Apparently there are varying manners of applying that refining in order to figure out the classes.

From there it is possible, for instance, to use CRC cards to find out responsibilities and collaborations, as well as more class candidates. But I suspect CRC cards are not very popular, so I'd like to hear about other methods (but feel free to endorse CRC cards if you want).

And regarding the implementation details (the more concrete and technical classes, not the conceptual ones), is there a process in OOA&D to determine them? How is that accomplished?

Feel free to treat OOA and OOD separately and clarify the steps involved in them while answering. I believe this will help clarify things to me regarding how those classes are found.

  • 6
    Designing classes is a Software Engineering activity. What you mostly need is design experience; it doesn't necessarily lend itself to cookie-cutter approaches. – Robert Harvey Dec 23 '19 at 23:34
  • 1
    However, in very general terms: you create a class when you need a specific bundle of code and behavior. More specifically, classes embody Uncle Bob Martin's notion of a responsibility. Over time, as you become familiar with architectures, it will become easier to identify classes, because your chosen architecture will provide a track to follow. – Robert Harvey Dec 23 '19 at 23:36
  • @RobertHarvey Thanks for commenting. I'm not sure what you mean by emphasizing it is a Software Engineering activity. I asked because I'm bad at designing (i.e. at learning from commited mistakes), so I need a lot of practice in order to acquire some little experience. So I guess it's either that or cookie-cutter approaches I can learn from. I'm aware of Robert Martin's notion of responsibility, but I'm curious how becoming familiar with architectures would help. – Piovezan Dec 23 '19 at 23:59
  • 3
    @Piovezan If you can't see a clear design, then you're better off focusing on just creating testable code with fairly complete automated test coverage. Design needs to be informed by requirements, but many software engineering projects don't start out with sufficient requirements to be able to make big, up-front decisions like that. A flawed or incorrect up-front design is often worse than just writing working code covered by automated tests. Regardless of your design(or lack-of), automated tests tend to solve a lot of problems without needing to worry too much about design anyway. – Ben Cottrell Dec 24 '19 at 10:08
  • @RobertHarvey Hopefully I didn't sound too clueless. Would you mind expanding on your comments? You sounded like I should grab a SE book and read it besides acquiring experience in projects. Also, would it be possible to provide an example of a non-obvious class in a given domain I could find under that orientation? – Piovezan Dec 25 '19 at 21:57
5

In OOA&D, what recommendations should be followed in order to produce an accurate conceptual Domain Model?

I'd recommend grabbing a copy of Domain-Driven Design by Eric Evans, it's an excellent book that walks through the process of talking to domain experts and distilling ideas into a software model. One of the central ideas in the book is to develop a ubiquitous language for your system that both stakeholders and programmers can understand: if there is a "thing" that people talk about all the time, then it should probably be a class in your code.

And regarding the implementation details (the more concrete and technical classes, not the conceptual ones), is there a process in OOA&D to determine them?

Generally speaking, if you've got the right domain concepts and interfaces, the "technical" classes will fall into place fairly easily. Details such as databases, web services and IoC containers exist only to connect your domain model to the outside world, so just pick the simplest solution that makes the rest of your software work.

| improve this answer | |
  • I have to admit, I haven't read the book - perhaps it is mentioned in there. But for me, the whole story of "OOP" falls apart when I have to model things beside the business domain and end up with stupid things like "a logger". There is no "logger" in any business domain (besides software), though in every codebase. No customer wants to speak about that. So to answer the question of "Do I need a logger class?" this approach gives no answer. Doing Java the answer may be "Classes are everywhere". Doing Python, the answer may be "print is in your case enough". – Thomas Junk Dec 25 '19 at 7:18
  • 1
    @ThomasJunk: Cross-cutting concerns such as logging aren't a problem specific to OOP. The good news is that there are plenty of libraries to do these things for you so you're rarely designing your own classes for these (which is what the OP's question was about). – casablanca Dec 25 '19 at 19:02
  • Of course there are libraries and established patterns to deal with that. It was an example of a thing which isn't a straight forward domain object where it is easy to agree upon. And especially in multiparadigm languages objects aren't always the answer. – Thomas Junk Dec 26 '19 at 2:00
  • 1
    @ThomasJunk but you still can apply the DDD principles to these cross-cutting concerns. It just happens that your "domain" changes. For a while it was modelling a petshop, latter you focus on a very different domain "logging things", but the modelling strategies or the rules are still valid for the new domain. In OOP almost everything belong to "a domain". – Laiv Dec 26 '19 at 18:50
2

Short answer: No. There is no unified mechanical process which produces a good object-model. Modelling is a creative and social process, it usually involves talking to-, and understanding other people, during which you come up with different ways to decompose a problem.

Just to be clear, it is not even close. Even judging the outcome is completely subjective, which is surprising considering most people believe software engineering is, well, some form of "engineering".

For example, I usually try to fulfill following constraints:

  • Any valid sentences in my model (i.e. any syntactically valid code using my objects) should be semantically valid too. So, if the code compiles it must have some "business" meaning.
  • All identifiers should come from the domain, or reference something from the problem domain. No technical classes.
  • No objects should ever publish their internal state.

A lot of people would disagree with the above. Most people are completely fine with "anemic" objects, i.e. records and structs, which the above isn't.

What I'm trying to say is, we didn't even agree how object-orientation should look like. Sure, there's lots of books and rules and best practices out there, but a lot of them are conflicting or depend on your personal interpretation. You have to make your own way basically.

| improve this answer | |
1

Fundamentally, we want to design abstractions that are useful to their consumers (often us, ourselves).

I generally advocate thinking more about how these abstractions are going to be used (rather than, say, about their implementation details).  Good abstractions are easy to use.

Let's also speak to the many different kinds of abstractions we can create in most OO languages:

  • functions
  • classes
  • interfaces + classes, and/or base classes + subclasses
  • namespaces

Each of these bundles more things together.  A function bundles a capability with inputs & outputs.  A class bundles multiple capabilities (aka methods) together with encapsulated state.  An interface (or base class) creates a capability over multiple varied implementations.  And a namespace defines a forest of classes that interact together or are otherwise related.

Good abstractions are complete.  If you can navigate from one to another then perhaps vice versa as well.  The consuming client should not have to manage two or more items when a single abstraction can do the job (e.g. separate x & y vs. vs. bundled together as a coordinate; an encode & decode pair of separate functions vs. bundled together as an interface).

Beyond thinking in terms of classes alone, we should more broadly model abstractions needed for a domain: to identify concepts and their relationships, to support navigation (traversal/search/query), to support behaviors for making changes (commands), all to make things easy for the consuming client programmer so they can work as much as possible directly in terms of the modeled domain.

Software is evolvable, so we don't need to get it perfect from the start.  We can start with a design and see how useful it is to consuming clients.  If, for example, the client has to manage multiple objects as a pair or set, that is indicative of a missing abstraction that perhaps should be modeled.

| improve this answer | |
1

From my POV there are two approaches which I would call analytical and synthetical (coming from 18th century philosophy) or perhaps more modern: top-down and bottom up. I find the former terms more describing because they indicate what you are doing: Analyzing things vs. putting things together.

I) The Analytical Way

When you enter your domain you have some understanding of what is going on. Say you are doing e-commerce you are dealing with Customers, Orders, Products etc.

what recommendations should be followed in order to produce an accurate conceptual Domain Model?

Coming down this road, the answer is

Getting to know your business domain

This is called analytical for just that reason of analyzing first and code second.

II) The Synthetical Way

If you have the luck I have and use a language which supports multiple paradigms (like Python) in my case, you could leverage that in order to avoid the question about objects (and modules etc.) at first. This way you build from the bottom up bit by bit - or as it is called you synthesize (group things together and group the groups) etc.

Generally speaking OOP is about data and behavior and grouping data and according behavior together (there are the three pillars which from my perspective come later).

But when starting the project most of the time you do not know how to group your data. Of course - as mentioned above - there are the "easy parts" of having an order.

Languages like Python allow you to postpone the question of what classes are needed and how they should look like to a later point. You start with the basic builtins and write some functions and group them later to modules which may become eventually classes. But sometimes you only see that you need a function.

The longer you work on the project, you realize which data "attracts" which behaviour so to say. If you have a bunch of functions every dealing with the same kind of data: Think of a class and clean up your code.

what recommendations should be followed in order to produce an accurate conceptual Domain Model?

The answer here is:

Start without any notion of objects at all and look for "attraction" of data and behaviour during the project.

I prefer the latter one. It let's me starting my work earlier.

But to do both ways in a reasonable way, you have to have (built up) experience.


Besides: I would substitute the term accurate with viable. You should model something which works. That may be inaccurate but accurate enough for the moment.

| improve this answer | |
  • So it's either the analytic way ("get to know your domain better") or the synthetic ("identify things to encapsulate"). Unfortunately I'm not as lucky as you, I work with Java (if necessary I'll add that information to the question). I've accepted your suggestion to replace "accurate" with "viable", thanks. – Piovezan Dec 25 '19 at 22:19
  • I would say it's more of a mode you are working in. Perhaps you start with the easy ones the analytical way and switch modes to the more exploratory mode of "just coding" and looking for threads and attraction patterns later and refactor accordingly. And yes this kind of "start small" is not directly possible with Java (up to version 8/9 it was my language of the job I worked in at the time) but nevertheless you could work with throwaway architecture and remodel during the project. The point is then to write code which is cheap to replace. – Thomas Junk Dec 26 '19 at 2:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.