Développement de framework avec Python

ordre du jour

  1. Auto-introduction
  2. Arrière plan
  3. Ce qui est écrit dans cet article
  4. Pensez au résumé
  5. Élaboration du cadre
  6. Résumé

Auto-introduction

Bonjour, je m'appelle Furuuchi et je suis ingénieur CTO / serveur chez Anyflow Co., Ltd.. Mon langage habituel est Python, et je travaille également avec le framework Django. Django écrit le code suivant. https://github.com/furuuchitakahiro/django_othello Anyflow travaille dans le domaine de l'iPaaS. iPaaS est une abréviation pour l'intégration Platform as a Service, et plus précisément, c'est une plate-forme pour l'intégration inter-SaaS telle que l'intégration de Slack et de feuilles de calcul.

Contexte

Chez Anyflow, la tâche principale des ingénieurs côté serveur est d'intégrer divers SaaS. Par exemple, implémentez du code qui envoie un message dans Slack ou lit une valeur dans une feuille de calcul. Cependant, Slack et les feuilles de calcul fonctionnent sur des systèmes complètement différents et vous devez implémenter le code de coordination pour chaque SaaS. Si vous creusez plus profondément, vous pouvez envoyer des messages, envoyer des fichiers, obtenir des informations utilisateur, etc. dans Slack, et il existe de nombreuses implémentations dans un même SaaS. Ce n'est pas tellement quand il s'agit de relier tout cela, mais avec Oreore Script, il n'est pas nécessaire d'attendre Death March. Pour résoudre ce problème, Anyflow a développé un framework d'intégration SaaS. Je vais résumer ce sur quoi j'ai travaillé.

Ce qui est écrit dans cet article

** J'essaie d'utiliser le contenu comme référence pour améliorer la capacité de montage. ** **

Dans cet article, nous démontrons la mise en œuvre du typage canard tout en capturant l'abstrait et le concret. Le contenu est expliqué dans l'ordre de commencer par ceux simples et faciles à comprendre et de les appliquer progressivement, en donnant des exemples. Même si vous ne développez pas de framework, vous pouvez obtenir un peu de compréhension du framework comme Django que vous utilisez habituellement.

Pensez abstrait

Avez-vous déjà travaillé ou pensé à ** "abstrait" **, tout d'un coup? Je n'ai pas trop réfléchi avant de créer Anyflow.

Tout d'abord, j'expliquerai ** humain ** en tant que sujet d'une manière facile à comprendre. "Taro Tanaka est un être humain." Si vous pensez que cela est abstrait et concret "** Taro Tanaka [spécifique] ** est ** humain [abstrait] **." Sera. Ce niveau est facile, non? Au fait, convertissons-le en Python.

class Human:
    def __init__(self, name: str):
        self.name = name


if __name__ == '__main__':
    taro = Human(name='Taro Tanaka')
    print(taro.name)
    # > 'Taro Tanaka'

C'est vraiment simple. Cela seul ne révèle pas les avantages de l'abstraction, nous allons donc y plonger. Si vous êtes un être humain, vous avez de l'âge en plus de votre nom, vous pouvez aussi vous saluer et vous avez une famille. Sur cette base, nous le convertirons à nouveau en Python.

from typing import Iterable, List


class Human:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age

    def greeting(self) -> str:
        return f'je{self.name}Mon nom est. L'âge est{self.age}Je suis vieux.'


class Family:
    def __init__(self, members: Iterable[Human]):
        self.members = list(members)

    def all_greeting(self) -> List[str]:
        return [member.greeting() for member in self.members]


if __name__ == '__main__':
    taro = Human(name='Ichiro Tanaka', age=20)
    jiro = Human(name='Jiro Tanaka', age=19)
    saburo = Human(name='Saburo Tanaka', age=18)
    tanaka_family = Family(members=[taro, jiro, saburo])
    print(tanaka_family.all_greeting())
    # > [
    #     'Je m'appelle Ichiro Tanaka. J'ai 20 ans.',
    #     'Je m'appelle Jiro Tanaka. J'ai 19 ans.',
    #     'Je m'appelle Saburo Tanaka. J'ai 18 ans.'
    # ]

Soudain, le code s'est allongé. Le point à regarder est la classe ** Famille **. La classe Family prend un tableau d'instances de classe Human dans son constructeur. La logique dans laquelle la méthode all_greeting fonctionne suppose que les membres sont une instance de classe Human dans la liste. D'un point de vue différent, ** les membres peuvent être considérés comme corrects si seule la condition **, qui est un tableau d'instances de classe Human, est satisfaite. (Soi-disant génériques) C'est le résultat de la combinaison de la classe humaine, qui est un concept abstrait qui résume l'humanité, et de la classe de la famille, qui est un concept abstrait qui est un groupe d'êtres humains. Histoire extrême Cette implémentation est ** n'importe quel nom et âge pour les humains, et même s'il y en a 100, elle fonctionnera comme une famille si elle est humaine **. Je n'ai abordé aucun détail, mais je me suis concentré sur les caractéristiques humaines et familiales.

Il est devenu clair que l'abstrait est la définition du dénominateur commun des choses.

image1.png

Développement du cadre

C'est le point important de l'élaboration du cadre. Ce que j'explique, c'est ce qu'on appelle le ** typage canard **. Sur Wikipedia ** [S'il marche comme un canard et sonne comme un canard, ce doit être un canard](https://ja.wikipedia.org/wiki/%E3%83%80%E3% 83% 83% E3% 82% AF% E3% 83% BB% E3% 82% BF% E3% 82% A4% E3% 83% 94% E3% 83% B3% E3% 82% B0) ** Ça a été.

Ce commentaire crée les fonctions suivantes basées sur quelque chose comme ** FaceBook ** qui se concentre sur votre ville natale.

Le concept est ** un type FaceBook ** avec un profil de ce qu'il pense de la spécialité de sa ville natale. Nous appellerons ce ** "Hometown FB" ** pour des raisons d'explication. Faisons maintenant du code Python. La configuration est la suivante.

--main.py (traitement principal) --mods (répertoire du module) --human.py --questions.py --prefectures.py (préfectures)

Tout d'abord, implémentez les questions dans questions.py.

from typing import ClassVar


class BaseQuestion:
    QUEASTION: ClassVar[str] = ''

    def __init__(self, answer: str):
        self.answer = answer

    @property
    def to_qa(self) -> str:
        return f'Q. {self.__class__.QUEASTION}\nA. {self.answer}'


class SeaQuestion(BaseQuestion):
    QUEASTION: ClassVar[str] = 'La mer de votre ville natale est-elle belle?'


class FujisanQuestion(BaseQuestion):
    QUEASTION: ClassVar[str] = 'Le mont Fuji est-il beau?'

BaseQuestion définit la question de la question. La ressemblance à une question signifie avoir le concept et la réponse d'une phrase de question. SeaQuestion et FujisanQuestion définissent des questions spécifiques pour cette BaseQuestion. L'important ici est que nous n'avons pas encore abordé la réponse. ** Une question est considérée comme une phrase de question et une phrase de réponse, et en plus de cela, il y a une phrase de question concrète et standard, et il y a plusieurs phrases de réponse à ce sujet **. Le fait est que si vous héritez de BaseQuestion, vous pouvez les traiter tous de la même manière comme des questions. Toutes les questions ont une fonction qui vous permet de cracher le texte de la question et de répondre ensemble sous forme de chaîne de caractères. (méthode to_qa) En d'autres termes, la classe BaseQuestion agit comme un cadre de questions. Ce sera le travail du FB local d'hériter de BaseQuestion et de poser de nombreuses questions.

Ensuite, implémentez l'état dans prefectures.py.

from typing import ClassVar, Tuple, Iterable
from . import questions


class BasePrefecture:
    NAME: ClassVar[str] = ''
    QUESTIONS: ClassVar[Tuple[questions.BaseQuestion, ...]] = tuple()

    def __init__(self, qa_list: Iterable[questions.BaseQuestion]):
        self.qa_list = list(qa_list)

    @classmethod
    def get_questions(cls) -> Tuple[str, ...]:
        return tuple(question.QUEASTION for question in cls.QUESTIONS)


class Tokyo(BasePrefecture):
    NAME: ClassVar[str] = 'Tokyo'
    QUESTIONS: ClassVar[Tuple[questions.BaseQuestion, ...]] = (
        questions.SeaQuestion
    )


class Sizuoka(BasePrefecture):
    NAME: ClassVar[str] = 'Shizuoka'
    QUESTIONS: ClassVar[Tuple[questions.BaseQuestion, ...]] = (
        questions.SeaQuestion,
        questions.FujisanQuestion
    )


class Yamanashi(BasePrefecture):
    NAME: ClassVar[str] = 'Yamanashi'
    QUESTIONS: ClassVar[Tuple[questions.BaseQuestion, ...]] = (
        questions.FujisanQuestion
    )

C'est la même structure que la question. La classe BasePrefecture définit uniquement que l'état a un nom et une question. Héritez de la classe BasePrefecture définie et définissez la classe Tokyo et ainsi de suite. À ce stade, définissez la classe Tokyo (nom et liste de questions). L'état le plus spécifique est l'état dans lequel vous avez un lieu d'origine et un ensemble de questions et réponses. La classe BasePrefecture agit comme un cadre préfectoral.

Enfin, human.py est une implémentation humaine.

from . import prefectures


class Human:
    def __init__(
        self, name: str, age: int, prefecture: prefectures.BasePrefecture
    ):
        self.name = name
        self.age = age
        self.prefecture = prefecture

    def greeting(self) -> str:
        qa_list_str = '\n'.join([qa.to_qa for qa in self.prefecture.qa_list])
        return (
            f'je{self.name}Mon nom est. L'âge est{self.age}Je suis vieux.'
            '\nQ&A'
            f'\n{qa_list_str}'
        )

La classe humaine est presque la même. Cela n'a pas beaucoup changé depuis [Penser l'abstrait](# Penser l'abstrait). Comme point supplémentaire, la préfecture est ajoutée au constructeur, et le message d'accueil (auto-introduction) est simplement ajouté à la question et à la réponse pour cette préfecture.

Cliquez ici pour la mise en œuvre main.py de la façon d'utiliser

from mods import questions, prefectures
from mods.human import Human


if __name__ == '__main__':
    tokyo = prefectures.Tokyo(qa_list=[
        questions.SeaQuestion(answer='C'est un peu sale.')
    ])
    taro = Human(name='Taro Tanaka', age=20, prefecture=tokyo)
    print(taro.greeting())
    # >Je m'appelle Taro Tanaka. J'ai 20 ans.
    # Q&A
    # Q.La mer de votre ville natale est-elle belle?
    # A.C'est un peu sale.

    shizuoka = prefectures.Sizuoka(qa_list=[
        questions.SeaQuestion(answer='Est beau.'),
        questions.FujisanQuestion(answer='c'est gros.')
    ])
    jiro = Human(name='Jiro Tanaka', age=22, prefecture=shizuoka)
    print(jiro.greeting())
    # >Je m'appelle Jiro Tanaka. J'ai 22 ans.
    # Q&A
    # Q.La mer de votre ville natale est-elle belle?
    # A.Est beau.
    # Q.Le mont Fuji est-il beau?
    # A.c'est gros.

    yamanashi = prefectures.Yamanashi(qa_list=[
        questions.FujisanQuestion(answer='c'est gros.')
    ])
    saburo = Human(name='Saburo Tanaka', age=24, prefecture=yamanashi)
    print(saburo.greeting())
    # >Je m'appelle Saburo Tanaka. J'ai 24 ans.
    # Q&A
    # Q.Le mont Fuji est-il beau?
    # A.c'est gros.

Résumé de la mise en œuvre

C'est peut-être trop minime pour ressembler à un cadre, mais je pense que cela touche à l'essentiel. La bonne chose à propos de la frappe de canard est que le code est facile à voir. En séparant correctement le grain de responsabilité (degré d'abstraction) de la classe, le problème à résoudre peut être clairement exprimé et l'évolutivité (diversité) peut être maintenue.

Il n'y a que trois codes de base pour ce FB de la ville natale: BaseQuestion, BasePrefecture et Human. Au fil du temps, le service FB de la ville natale sera étendu en héritant de BaseQuestion et BasePrefecture.

image2.png

Lorsque vous faites du développement Web, je pense que vous créez XX modèles en utilisant le framework. Bien sûr, à ce moment, vous avez hérité et déclaré la classe modèle du framework, non? La classe de modèle du framework définit uniquement le comportement de lecture, de création, de mise à jour et de suppression, et ne mentionne rien sur les colonnes. Je pense que les colonnes sont définies dans la classe de modèle XX que vous créez. La relation entre la classe de modèle du framework et le modèle 〇〇 que vous définissez est celle du typage canard.

Cette démonstration était un cadre spécifique à l'entreprise. L'implémentation de choses plus abstraites (contrôleur de vue de modèle) en fonction du contenu de cet article en fait un cadre général pour le développement d'applications Web.

Résumé

En fait, Python a beaucoup de contenu à dire lors du développement de plus de frameworks tels que ABC, docstring pour la documentation, les indices de type et DI, mais comme il s'agit d'une quantité de phrases qu'un livre peut écrire. Cette fois, j'ai fait une démonstration qui considère principalement l'abstraction et le concret et la met dans le typage creusé.

** Anyflow est 10 000 fois plus intense que le contenu de cet article! ** ** ** J'ai beaucoup de choses à discuter, comme l'historique de développement et Airflow! ** ** ** Si vous aimez ou êtes intéressé par la logique et le design, faites-le nous savoir! ** ** ** Pour ceux qui sont intéressés par le lancement de services ainsi que par l'ingénierie dans les startups! ** **

Anyflow a beaucoup d'élan! J'ai gagné le B Dash Camp! https://jp.techcrunch.com/2019/10/31/b-dash-camp-2019-fall-pitch-arena/ J'ai gagné le camp d'incubation! https://jp.techcrunch.com/2019/09/14/incubate-camp-12th/

Page de recrutement: https://open.talentio.com/1/c/anyflow/requisitions/detail/13828 Si vous êtes plus décontracté, veuillez envoyer un DM à https://www.facebook.com/takahiro.furuuchi.37!

Recommended Posts

Développement de framework avec Python
Environnement de développement en Python
Développement Slackbot en Python
Développement Python avec Visual Studio 2017
Développement Python avec Visual Studio
Quadtree en Python --2
CURL en Python
Métaprogrammation avec Python
Python 3.3 avec Anaconda
Géocodage en python
SendKeys en Python
Méta-analyse en Python
Unittest en Python
Discord en Python
DCI en Python
tri rapide en python
nCr en python
N-Gram en Python
Programmation avec Python
Plink en Python
Constante en Python
Sqlite en Python
Étape AIC en Python
LINE-Bot [0] en Python
CSV en Python
Assemblage inversé avec Python
Réflexion en Python
Constante en Python
nCr en Python.
format en python
Scons en Python 3
Puyopuyo en python
python dans virtualenv
PPAP en Python
Quad-tree en Python
Réflexion en Python
Chimie avec Python
Hashable en Python
DirectLiNGAM en Python
LiNGAM en Python
Aplatir en Python
Aplatir en python
Liste triée en Python
AtCoder # 36 quotidien avec Python
Texte de cluster en Python
AtCoder # 2 tous les jours avec Python
Daily AtCoder # 32 en Python
Daily AtCoder # 6 en Python
Modifier les polices en Python
Motif singleton en Python
Opérations sur les fichiers en Python
Lire DXF avec python
Daily AtCoder # 53 en Python
Séquence de touches en Python
Utilisez config.ini avec Python
Daily AtCoder # 33 en Python