Essa abstração é excessiva? (E há um nome para isso?)

5

Eu trabalho em um grande aplicativo Django que usa o CouchDB como um banco de dados e o couchdbkit para mapear documentos do CouchDB para objetos em Python, similar ao ORM padrão do Django. Tem dezenas de classes de modelo e cem ou duas visualizações do CouchDB.

O aplicativo permite que os usuários registrem um "domínio", que fornece a eles um URL exclusivo contendo o nome de domínio que lhes dá acesso a um projeto cujos dados não se sobrepõem aos dados de outros domínios. Cada documento que faz parte de um domínio tem sua propriedade domain definida para o nome desse domínio.

No que diz respeito aos relacionamentos entre os documentos, todos os domínios são efetivamente subconjuntos mutuamente exclusivos dos dados, exceto alguns casos de borda (alguns usuários podem ser membros de mais de um domínio e há alguns relatórios administrativos que incluem todos os domínios, etc.).

O código está cheio de referências explícitas ao nome do domínio, e eu estou querendo saber se valeria a complexidade adicional para abstrair isso. Eu também gostaria de saber se há um nome para o tipo de abordagem de propriedade vinculada que estou tomando aqui.

Basicamente, tenho algo assim em mente:

Antes

em models.py

class User(Document):
    domain = StringProperty()


class Group(Document):
    domain = StringProperty()
    name = StringProperty()
    user_ids = StringListProperty()

    # method that returns related document set
    def users(self):
        return [User.get(id) for id in self.user_ids]

    # method that queries a couch view optimized for a specific lookup
    @classmethod
    def by_name(cls, domain, name):
        # the view method is provided by couchdbkit and handles
        # wrapping json CouchDB results as Python objects, and 
        # can take various parameters modifying behavior
        return cls.view('groups/by_name', key=[domain, name])

    # method that creates a related document
    def get_new_user(self):
        user = User(domain=self.domain)
        user.save()
        self.user_ids.append(user._id)
        return user

em views.py:

from models import User, Group

# there are tons of views like this, (request, domain, ...)
def create_new_user_in_group(request, domain, group_name):
    group = Group.by_name(domain, group_name)[0]
    user = User(domain=domain)
    user.save()
    group.user_ids.append(user._id)
    group.save()

no grupo / by_name / map.js:

function (doc) {
    if (doc.doc_type == "Group") {
        emit([doc.domain, doc.name], null);
    }
}

Depois de

models.py

class DomainDocument(Document):
    domain = StringProperty()

    @classmethod
    def domain_view(cls, *args, **kwargs):
        kwargs['key'] = [cls.domain.default] + kwargs['key']
        return super(DomainDocument, cls).view(*args, **kwargs)

    @classmethod
    def get(cls, *args, **kwargs, validate_domain=True):
        ret = super(DomainDocument, cls).get(*args, **kwargs)

        if validate_domain and ret.domain != cls.domain.default:
            raise Exception()

        return ret

    def models(self):
        # a mapping of all models in the application. accessing one returns the equivalent of

        class BoundUser(User):
            domain = StringProperty(default=self.domain)


class User(DomainDocument):
    pass

class Group(DomainDocument):
    name = StringProperty()
    user_ids = StringListProperty()

    def users(self):
        return [self.models.User.get(id) for id in self.user_ids]

    @classmethod
    def by_name(cls, name):
        return cls.domain_view('groups/by_name', key=[name])

    def get_new_user(self):
        user = self.models.User()
        user.save()

views.py

@domain_view  # decorator that sets request.models to the same sort of object that is returned by DomainDocument.models and removes the domain argument from the URL router
def create_new_user_in_group(request, group_name):
    group = request.models.Group.by_name(group_name)
    user = request.models.User()
    user.save()
    group.user_ids.append(user._id)
    group.save()

(Pode ser melhor deixar a abstração vazada aqui para evitar ter que lidar com um estilo couchapp //! include de um wrapper para emitir que preenche doc.domain à chave ou alguma outra solução semelhante.)

function (doc) {
    if (doc.doc_type == "Group") {
        emit([doc.name], null);
    }
}

Prós e Contras

Então, quais são os prós e contras disso?

Prós:

  • DRYer
  • evita que você crie documentos relacionados, mas esquece de definir o domínio.
  • impede que você grave acidentalmente uma visualização do django - > caminho de execução da visualização do sofá que leva a uma violação de segurança
  • não impede que você acesse o self.domain subjacente e o método Document.view () normal
  • potencialmente elimina a necessidade de muitas verificações de integridade, verificando se dois documentos cujos domínios esperamos ser iguais são.

Contras:

  • adiciona alguma complexidade
  • oculta o que realmente está acontecendo
  • não requer módulos de modelo para ter classes com o mesmo nome, ou você precisaria adicionar subatributos a self.models para módulos. No entanto, a exigência de nomes de classe exclusivos para todos os modelos deve, na verdade, ser adequada, pois eles correspondem à propriedade doc_type que o couchdbkit usa para decidir a qual classe instanciá-los, o que deve ser exclusivo.
  • remove a documentação de dependência explícita (do grupo group.models import)
por mwhite 24.04.2013 / 03:56
fonte

1 resposta

1

Esta é realmente uma questão que só você pode responder, a abstração excessiva está no olho do espectador. O abaixo é a minha humilde opinião.

Para mim, o domínio é uma entidade . É uma entidade porque tem identidade que é fundamental para o ciclo de vida do conceito de domínio. Assim, abstraí-lo de outros contextos é exatamente o que fazer, mas como seu próprio objeto de primeira classe, e não como parte de outra classe que você ainda transmite. Além disso, à primeira vista, parece-me que o domínio é uma entidade agregada.

O documento, na minha opinião, existe no mesmo contexto limitado que o Domínio, mas é um agregado separado que será referenciado apenas por ID, por ex. um documento deve estar associado a um domínio, mas como não há necessidade de consistência transacional entre os dois, não há problema em tê-los como agregados separados.

    
por 25.06.2013 / 19:39
fonte