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.
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.
Ich dachte über die Ursache nach.
Ich kann überhaupt nicht entwerfen und analysieren
――Es gibt überhaupt kein Dokument mit der Aufschrift "Weil es sich später ändern wird".
Ich kenne keine Architekturmuster für Unternehmensanwendungen
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.
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.
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.
Ich habe die Ansicht und die Stapelschnittstelle auf nur drei Dinge beschränkt.
Hier wird der Begriff serviceorientierte Architektur verwendet. So ein gewöhnlicher Typ.
Geändert, um Service-Layer-Methoden aus Ansichten und Batch-Schnittstellen auszuführen.
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.
Bietet eine grobkörnige API für Ansichten. Die Namensregeln sind in die folgenden zwei Muster unterteilt.
--CRUD: XxxService mit nur einem Modell (Tabelle)
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.
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.
Manchmal habe ich später ein Modell mit zusätzlichen Informationen aus dem Artikel erstellt.
Behandeln Sie diese JOIN-Daten wie ein Modell.
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 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.
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
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
Erstellen Sie beim Refactoring einen Komponententest mit from django.test import TestCase
Offensichtlich sind die Aussichten für den Code durcheinander geraten
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.
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.
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.
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