[GO] Ich habe versucht, das Active Record-Framework von Python zu erweitern

Als ich zur Firma kam, war es Active Record

Im Sommer 2015 trat ich einem AI-Startup bei. Es war zum ersten Mal seit 5 Jahren eine anständige Entwicklung.

Ich verwende Python Django (später Pythons Google App Engine). Es ist ein Framework, das Rails sehr ähnlich ist. Ich habe Rails vor ungefähr 7 Jahren berührt. So konnte ich mit der Idee des Frameworks Schritt halten.

Inkompetenz ausbrechen, Anti-Muster ausbrechen

Der tatsächlich in Betrieb befindliche Code war jedoch schrecklich. Und der Code des Serveringenieurs, der vor etwa einem Monat in das Unternehmen eingetreten war, enthielt den Zauber von Medapani.

Unten finden Sie eine Liste der auffälligen Symptome.

Ich war verwirrt.

Warum ist das passiert

Ich dachte über die Ursache nach.

Ursache 1

Ich kann überhaupt nicht entwerfen und analysieren

――Es gibt überhaupt kein Dokument mit der Aufschrift "Weil es sich später ändern wird".

Ursache 2

Ich kenne keine Architekturmuster für Unternehmensanwendungen

Ursache 3

Der Manager ist ein Verkäufer und kennt die Herstellung und Herstellung von IT-Produkten zu wenig. Eines der Anti-Patterns für Startups besteht darin, dass Vertriebsleiter ohne ein gutes Verständnis des Technologiegeschäfts starten.

Gegenmaßnahmen

Ursache 1 versuchte eine Lernsitzung des ICONIX-Prozesses. Klicken Sie hier für das Nachschlagewerk.

Lassen Sie uns über die Lösung für Ursache 2 sprechen.

Zusätzliche Informationen zum Active Record-Muster

Es ist irreführend, aber das Active Record-Muster hat nicht mit Rails begonnen. Es ist in Fowlers Enterprise Application Architecture Pattern beschrieben.

Ich verstehe, dass die View- und DB-Tabellen 1: 1 und die View: Model: Table 1: 1: 1 sind, wenn Sie das Model dazwischen einfügen. Es wird übernommen, wenn einfache Konfiguration, einfacher Service und komplizierte Funktionen nicht hinzugefügt werden.

Wenn das System jedoch komplexer wird und die Tabellen und Modelle wachsen, wird es schwierig. Es ist leicht, durcheinander zu kommen.

Obwohl es sich mit den oben genannten Symptomen überschneidet, denke ich, dass das Problem auch in mehrere Muster eingeteilt werden kann. Die dem Problemmuster entsprechenden Inhalte werden nachfolgend beschrieben.

Problemmuster 1: Logik ist in die Präsentationsschicht eingebettet

Ich habe die Ansicht und die Stapelschnittstelle auf nur drei Dinge beschränkt.

Problemmuster 2: Es gibt einen Prozess, der mit anderen Modellen kombiniert werden kann

Einführung der Serviceschicht

Hier wird der Begriff serviceorientierte Architektur verwendet. So ein gewöhnlicher Typ.

ServiceLayerSketch.gif

Geändert, um Service-Layer-Methoden aus Ansichten und Batch-Schnittstellen auszuführen.

Vereinbarung von Begriffen

Der Anwendungscontroller ist im domänengesteuerten Design anwendbar. Beachten Sie, dass es sich von einem Dienst in einem domänengesteuerten Design unterscheidet (siehe Evans-Klassifizierung).

Es gibt auch ein Webpräsentationsmuster im Architekturmuster der Unternehmensanwendung, das auch einen Anwendungscontroller enthält.

Oh, es ist verwirrend.

Namensregeln

Bietet eine grobkörnige API für Ansichten. Die Namensregeln sind in die folgenden zwei Muster unterteilt.

--CRUD: XxxService mit nur einem Modell (Tabelle)

Singleton

Es ist auch sinnlos, jedes Mal eine Instanz zu erstellen, wenn Sie sie aus einer Ansicht aufrufen. Rezept, um Singleton mit Klassendekorateur zu machen wurde übernommen.

Angepasstes QuerySet

Wenn JOIN in der Stapelverarbeitung schneller ist, kann es in einem Modell, das mit einem kombinierten QuerySet erweitert wurde, frei verwendet werden. Beschreiben Sie den Fall, in dem der Fremdschlüssel angebracht ist.

Angenommenes ER-Diagramm

Manchmal habe ich später ein Modell mit zusätzlichen Informationen aus dem Artikel erstellt.

Untitled Diagram.png

Behandeln Sie diese JOIN-Daten wie ein Modell.

Grundmodell

Es sieht aus wie das.

models/item.py


class Item(models.Model):
    name = models.CharField(max_length=128, blank=True)
    description = models.CharField(max_length=1024, blank=True)
    image = mdoels.ImageField(upload_to='hoge', blank=True, null=True)

models/item_feature_1.py


class ItemFeature1(models.Model):
    item = models.ForeignKey(Item)
    feature_1 = models.TextField()

models/item_extra_info.py


class ItemExtraInfo(models.Model):
    item = models.ForeignKey(Item)
    info = models.TextField()

QuerySet, Manager, Modell für Join

QuerySet für den Beitritt sieht folgendermaßen aus. Angenommen, Sie verbinden sich mit select, wird nichts anderes berücksichtigt.

joined_query_set.py


class JoinedItemFeatureQuerySet(models.QuerySet):
    def __iter__(self):
        queryset = self.values(
            'id', 'name', 'description', 'image',
            'itemfeature1__feature_1',
            'itemextrainfo__info')

        results = list(queryset.iterator())

        instances = []
        for result in results:
            item_feature = self.model(
                result['id'],
                result['name'],
                result['description'],
                result['image']
            )
            item_feature.feature_1 = result['itemfeature1__feature_1']  #Modelleigenschaften hinzufügen / packen
            item_feature.info = result['itemextrainfo__info']

            instances.append(item_feature)

        return iter(instances)  #Zum Iteratorprotokoll umpacken

custom_manager.py


class JoinedItemFeatureManager(models.Manager):
    def get_queryset(self):
        queryset = JoinedItemFeatureQuerySet(self.model, using=self._db)
        queryset = queryset.filter(del_flg=False, itemfeature1__isnull=False, itemextrainfo__isnull=False)  #Sei nicht null
        return queryset

joined_item_domain.py


class JoinedItemFeatureDomain(Item):
    objects = JoinedItemFeatureManager()

    class Meta:
        proxy = True  #Erstellen Sie keine Tabelle.

Sie können die Daten frei mit join_item_features = JoinedItemFeatureDomain.objects.filter (...) verwenden. .. .. Haz.

Problemmuster 3: Die Modellverarbeitung ist zu komplex

Methoden, die wiederverwendet werden können, sind mäßig abstrahiert (maschinelles Lernsystem usw.)

Es kann als Strategie ausgeschnitten oder als reine Berechnungsklasse wiederverwendet werden.

――Für Dinge, die später wiederverwendet oder in die einzigartige Bibliothek eines Unternehmens umgewandelt werden können

Das Modell ist nur einer Tabelle zugeordnet, und die Verarbeitung wird in einer Unterklasse implementiert

In Django gibt es eine Methode namens Proxy-Modell, die ich in eine Unterklasse setze.

Unten finden Sie einen Auszug aus dem Code für mein persönliches Projekt.

intro/models/abstract_model.py


from django.contrib.auth.models import User
from django.db import models


class AbstractModel(models.Model):
    registered_at = models.DateTimeField(auto_created=True)
    registered_by = models.ForeignKey(User, related_name='%(class)s_registered_by')

    updated_at = models.DateTimeField(auto_now_add=True)
    updated_by = models.ForeignKey(User, related_name='%(class)s_updated_by')

    class Meta:
        abstract = True

intro/models/article.py



from django.contrib.auth.models import User
from intro.models.abstract_model import AbstractModel

class Article(AbstractModel):
    title = models.CharField(max_length=128)
    description = models.CharField(max_length=2048)
    author = models.ForeignKey(Author)  #Die Beschreibung der Author-Klasse wird weggelassen
    categories = models.ForeignKey(Category, null=True, blank=True)  #Kategorie Klassenbeschreibung weggelassen
    url = models.URLField()

intro/models/article_domain.py


from intro.models.article import Article
from intro.consts import DEFAULT_MECAB_PATH

class ArticleDomain(Article):
    class Meta:
        proxy = True

    def __init__(self, *args, **kwargs):
        # Do initialize...

    def __call__(self, mecab_path=None):
        if not mecab_path:
            self.mecab_path = DEFAULT_MECAB_PATH

    def parse_morpheme(self):
        # Do morpheme analysis

    @classmethod
    def train(cls, filter_params)
        authors = filter_params.get('author')
        articles = None
        if authors and articles:
            articles = Articles.objects.filter(authors__in=authors)
        # Do some extraction

        # Do training


    def predict(self, texts)
        # Do prediction

Einführung in den Testcode

Erstellen Sie beim Refactoring einen Komponententest mit from django.test import TestCase Offensichtlich sind die Aussichten für den Code durcheinander geraten

Implementierung von Unterklassen mit unterschiedlichen Datenextraktionsbedingungen (mit angepasstem QuerySet)

Die Datenextraktionsbedingung in get_queryset in der CustomManager-Klasse wurde so geändert, dass der CustomManager in der Proxy-Klasse enthalten ist.

Es funktionierte gut mit einem komplexen Domänenmodell für Stapel.

Die hexagonale Architektur wird für die Zusammenarbeit zwischen E-Mail-Übertragung und externen Diensten übernommen

Das Schreiben einer E-Mail-Sendeimplementierung im Modell oder das solide Zeichnen von urllib2 für die Verknüpfung mit externen Diensten ist umständlich.

2304.gif

Erstellt eine Gateway-Klasse für die externe Zusammenarbeit (in der obigen Abbildung als Adapter geschrieben) und erbt und verwendet die Gateway-Klasse in der Domänenmodellklasse oder Modellklasse (in der obigen Abbildung als Anwendung geschrieben). ..

Modellklassen verwenden normalerweise Convenience-Methoden, die von Superklassen geerbt wurden. Anschließend haben wir die Gateway-Klasse geerbt und praktische Methoden verwendet.

Schließlich

In Bezug auf Ursache 3 habe ich beschlossen, das Management aufzugeben und den Job zu wechseln (obwohl nur der CTO anständig ist).

Es wäre möglich gewesen, das Unternehmen zu verbessern, wenn wir uns die Zeit genommen hätten. Angesichts der Zeit, die Menschen brauchen, um sich zu verändern, der Geschwindigkeit, mit der die Technologie voranschreitet, und der Bedingungen anderer Unternehmen dachte ich jedoch, dass ich meine Zeit und mein Leben verschwenden würde, wenn ich bleiben würde. Ich bin nicht jung genug, um solche Abfälle zu tolerieren. Ich bin nicht jung genug, um mit den Erinnerungen anderer, die einsam sind, umzugehen.

Nicht nur für Startups, sondern auch für das Management als überaus wichtig.

Recommended Posts

Ich habe versucht, das Active Record-Framework von Python zu erweitern
Ich habe versucht, Pythons GUI-Bibliothek "PySimple GUI" zu berühren.
Ich habe versucht zu debuggen.
Ich habe versucht, PredNet zu lernen
Ich habe versucht, SVM zu organisieren.
Ich habe versucht, Linux wieder einzuführen
Ich habe versucht, Pylint vorzustellen
Ich habe versucht, SparseMatrix zusammenzufassen
jupyter ich habe es berührt
Ich habe versucht, StarGAN (1) zu implementieren.
Ich habe versucht, Deep VQE zu implementieren
Ich habe versucht, Python zu berühren (Installation)
Ich habe versucht, eine kontroverse Validierung zu implementieren
Ich habe versucht, Pytorchs Datensatz zu erklären
Ich habe Watson Voice Authentication (Speech to Text) ausprobiert.
Ich habe Teslas API berührt
Ich habe versucht, mich über MCMC zu organisieren.
Ich habe versucht, Realness GAN zu implementieren
Ich habe versucht, den Ball zu bewegen
Ich habe versucht, den Abschnitt zu schätzen.
Ich habe versucht, einen Linebot zu erstellen (Implementierung)
Ich habe versucht, die Behandlung von Python-Ausnahmen zusammenzufassen
Ich habe versucht, PLSA in Python zu implementieren
Ich habe versucht, Azure Speech to Text zu verwenden.
Ich habe versucht, Autoencoder mit TensorFlow zu implementieren
Ich habe versucht, den Befehl umask zusammenzufassen
Ich habe versucht, Permutation in Python zu implementieren
Ich habe versucht, einen Linebot zu erstellen (Vorbereitung)
Ich habe versucht, AutoEncoder mit TensorFlow zu visualisieren
Ich versuchte das Weckwort zu erkennen
Ich habe versucht, mit Hy anzufangen
Ich habe versucht, PLSA in Python 2 zu implementieren
Python3-Standardeingabe habe ich versucht zusammenzufassen
Ich habe versucht, Text mit TensorFlow zu klassifizieren
Ich habe versucht, die grafische Modellierung zusammenzufassen.
Ich habe versucht, der CPython-Implementierung ein Post-Inkrement hinzuzufügen
Ich habe versucht, ADALINE in Python zu implementieren
Ich habe versucht, Optuna die Nummer lösen zu lassen
Ich habe versucht, das Umfangsverhältnis π probabilistisch abzuschätzen
Ich habe versucht, die COTOHA-API zu berühren
Ich habe versucht, PPO in Python zu implementieren
Ich habe versucht, CVAE mit PyTorch zu implementieren
Ich habe eine Web-API erstellt
Ich habe versucht, TSP mit QAOA zu lösen
[Python] Ich habe versucht, TF-IDF stetig zu berechnen
Ich habe versucht, Python zu berühren (grundlegende Syntax)
Ich habe versucht, Pythons FizzBuzz nach und nach zu verkürzen
Ich habe versucht, das Webanwendungs-Framework zu vergleichen
Ich versuchte mein Bestes, um zu Lasso zurückzukehren
Ich habe versucht, Ansibles Module-Linux-Edition zusammenzufassen
Ich habe das Python Tornado Testing Framework ausprobiert
Ich habe ein Skript erstellt, das das aktive Fenster mit win32gui von Python aufzeichnet
Ich habe versucht, nächstes Jahr mit AI vorherzusagen
Ich habe versucht, die Blasensortierung nach Sprache zu programmieren
Ich habe Web Scraping versucht, um die Texte zu analysieren.
Ich habe versucht, das Lesen von Dataset mit PyTorch zu implementieren
Ich habe versucht, lightGBM, xg Boost mit Boruta zu verwenden