Zope.interface is useful for practicing Hexagonal Architecture

Postscript: 2017-02-12

In fact, my project hasn't used this method lately. It is a loose idea that the domain layer model and the infrastructure layer implementation do not necessarily have to be inherited as long as they are linked by inject and the required methods are defined (duck typing).

Also, in my recent project, instead of putting the infrastructure layer, I have defined modules for port and adapter. For adapter, it's like writing an implementation of an interface defined by a domain layer or port. The concept in the domain model is placed in the domain layer, and the interface with the external systom is placed in the port.

I will write another article when I have time.

Overview

If you apply Hexagonal Architecture to Domain Driven Development, you will put the interface for repositories and domain events at the domain layer, but [zope.interface](http: //: // By leveraging docs.zope.org/zope.interface/), you can write easy-to-understand code that avoids multiple inheritance.

Domain layer

from abc import ABCMeta
from zope.interface import Interface


class Entity(object):
    """ Base class for Entity """
    __metaclass__ = ABCMeta


class IRepository(Interface):
    """ Interafce for Repository """


class IDomainService(Interface):
    """ Interface for Domain Service """


class Blog(Entity):
    def __init__(self, identity, title):
        self._identity = identity
        self._title = title


class IBlogRepository(IRepository):
    """ Blog repository Interface """

    def add_entity(blog):
        """ add blog """

    def get_by(identity):
        """ get blog by identity """


class IBlogProvisioningService(IDomainService):
    """ Blog provisioning service interface """

    def provision_blog(title):
        """ provision blog with title. returns Blog object """

Infrastructure layer

import uuid
from abc import ABCMeta
from zope.interface import implementer
from domain import Blog, IBlogRepository, IBlogProvisioningService


class MySQLRepository(object):
    """ MySQL based repository """
    __metaclass__ = ABCMeta


class MemoryRepository(object):
    """ memory based repository """
    __metaclass__ = ABCMeta


@implementer(IBlogRepository)
class BlogRepository(MySQLRepository):

    def add_entity(self, blog):
        # do some stuff
        pass

    def get_by(self, identity):
        # do some stuff
        return Blog(identity, "some stored title")


@implementer(IBlogRepository)
class BlogMemoryRepository(MemoryRepository):

    def add_entity(self, blog):
        # do some stuff
        pass

    def get_by(self, identity):
        # do some stuff
        return Blog(identity, "some stored title")


@implementer(IBlogProvisioningService)
class BlogProvisioningService(object):

    def __init__(self, repo):
        self._repo = repo

    def provision_blog(self, title):
        entity = Blog(uuid.uuid4().hex, title)
        self._repo.add_entity(entity)

test

import pytest
from zope.interface.verify import verifyClass
from domain import Blog, IBlogRepository, IBlogProvisioningService
from infra import BlogRepository, BlogMemoryRepository, BlogProvisioningService


def test_class_interface():
    assert verifyClass(IBlogRepository, BlogRepository)
    assert verifyClass(IBlogRepository, BlogMemoryRepository)
    assert verifyClass(IBlogProvisioningService, BlogProvisioningService)

Domain Driven Development Series

Recommended Posts

Zope.interface is useful for practicing Hexagonal Architecture
Python-dotfiles is useful for managing dotfiles
Watchdog is quite useful for file monitoring
Import-linter was useful for layered architecture in Python
A scene where GPU is useful for deep learning?
What is Linux for?