Code Monkey home page Code Monkey logo

Comments (10)

phalt avatar phalt commented on July 27, 2024 3

Hey @SHxKM this is a really well thought out comment and I appreciate the feedback.

First off, I am assuming the second code example has a mistake and it should be artists/interfaces.py and not albums/interfaces.py. Because a domain's interface to itself is redundant. I'll go on the basis that this is wrong for the rest of my reply 😄

So you're right - those two examples are identical, and in this instance the are violating the DRY principle. If this was as far as we were going to take this project, that redundancy could be refactored. One of the core principles of DADs (I need a better acronym) is to make it easier for future developers to come in and expand features in place. I think perhaps the example given is not a real-world case. Let me explain.

Let's evolve with the example you gave: Artists and Users both want to communicate with Albums. We create the initial state:

# user/interfaces.py
from album.apis import AlbumAPI

def get_latest_albums():
    AlbumAPI.get_latest()
# artists/interfaces.py
from album.apis import AlbumAPI

def get_latest_albums():
    AlbumAPI.get_latest()

Awesome. We're violating DRY here, so maybe a developer will choose to not do this and refactor. That's probably okay for that requirement and it'll pass code review (even mine). If we didn't go any further with this, interfaces is redundant. We don't really need DADs.

But thi is a real-world evolving project, so we've suddenly got a new requirement:

  • Artists want only the following fields from albums: album title, listens, and sales.
  • Users want only the following fields from albums: album titles, and publishing dates. What's more, we want to decorate the album title with some weird string formatting because it's a millennial-esque website and we like fancy things.
  • They both want slightly different attribute names for each domain.

Now it should become clear why two interfaces is not redundant. The needs for Artists and Users from Albums is different:

# user/interfaces.py
from album.apis import AlbumAPI

def transform_albums(*, albums):
    return [
        {'title': f'*~-_-~{a.title}~-_-~', 'published_date': a.publish_date} 
        for a in albums
    ]

def get_latest_albums():
    albums = AlbumAPI.get_latest()
    return transform_albums(albums=albums)
# album/interfaces.py
from album.apis import AlbumAPI

def transform_albums(*, albums):
    return [
        {'title': a.title, 'listens': a.listen_count, 'sales': a.sales} 
        for a in albums
    ]

def get_latest_albums():
    albums = AlbumAPI.get_latest()
    return transform_albums(albums=albums)

What is the alternative here? We could develop these requirements inside the Albums domain, but then that domain will start having business logic for other domains within it. From my experience too, this breeds a "your problem" culture, especially when you own Albums, I own Users, and I don't want to have to maintain your stuff.

DDD talks about responsibilities and separating concerns. With DADs, the interfaces layer is that transformation layer that allows domains to remain pure, and the interfaces between them handling any required transformations.

Does this help clear up the reason behind them?

from django-api-domains.

phalt avatar phalt commented on July 27, 2024 2

I've pinned this discussion because I think it is useful for others who are keen on the guide but don't know what to do!

from django-api-domains.

SHxKM avatar SHxKM commented on July 27, 2024 1

@phalt Thanks for the detailed clarification. I have a follow-up question:

so maybe a developer will choose to not do this and refactor. That's probably okay for that requirement and it'll pass code review (even mine). If we didn't go any further with this, interfaces is redundant. We don't really need DADs.

But thi is a real-world evolving project, so we've suddenly got a new requirement:

But what if there really isn't a new requirement? What if this get_albums() func is really needed as is in say, 3 places? My question then is, where do you (or would you) place it?

Thanks again for this refreshing methodology.

from django-api-domains.

phalt avatar phalt commented on July 27, 2024 1

No probs. I'm just keen to have people interested in a thing I developed from all my hard work 😆

It sounds like the interfaces could be promoted into it's own domain, sort out like a gateway or orchestration layer. I mentioned that some domains can just have services, and their only job is to co-ordinate or abstract other domains beneath it. Perhaps that could fulfill the same requirements we have here?

from django-api-domains.

phalt avatar phalt commented on July 27, 2024 1

Sounds like a good suggestion :)

from django-api-domains.

phalt avatar phalt commented on July 27, 2024

But what if there really isn't a new requirement?

If it's not proving useful then it might be overengineering. I'd clean it up. There isn't anything wrong with anticipating future changes and then, when you get to the future, discover there isn't any. Software is fluid and changes. We'll just adapt to what makes sense for the situation currently. If we discover we need to add it, we just put it back in. This is what the "pragmatism" bit means at the start of the guide.

Thanks for your comments, it's helped me challenge my assumptions!

from django-api-domains.

SHxKM avatar SHxKM commented on July 27, 2024

Thanks @phalt. Your positive attitude is quite refreshing.

I wasn’t trying to challenge your assumptions per se, more like trying to pick your brain. So if you do have a general rule of thumb regarding this question, I’d be glad to hear your thoughts:

My question then is, where do you (or would you) place it?

from django-api-domains.

SHxKM avatar SHxKM commented on July 27, 2024

Perhaps that could fulfill the same requirements we have here?

I'm a little hesitant to make a concrete suggestion as I have very little experience with DDD or DADs, but perhaps a reluctantly populated common module can be introduced in cases where a coordinating layer doesn't really fit in one of the domains in the project? common/interfaces.py?

from django-api-domains.

SHxKM avatar SHxKM commented on July 27, 2024

Great. Thanks for your responsiveness. Feel free to close this :)

I’m happy to contribute to the docs if you feel that should go somewhere in there but I do feel this is an edge-case, as you noted.

from django-api-domains.

phalt avatar phalt commented on July 27, 2024

Hey @RTS340 yes I have had issues like that in the past. This isn't a problem with Django API Domains per say - you can end up with them in many ways. Usually circular imports are usually due to design choices in the past create circular dependencies.

I have two suggestions, one easy, one more complex:

  1. Easy option - put your imports at the top of functions instead of a file - then the import will only be evaluated when ran, and this usually avoids circular dependency issues.
  2. Refactor and redesign your components to have a 3rd "parent" domain that co-ordinates both.

The first way is easy but inevitably feels hacky, and that's because it is a little bit.

The second way is a much better approach, but costs time and effort - which understandably we don't always have!

from django-api-domains.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.