Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AI組織でのアプリケーション開発の裏側 - Django × DDDでの開発プラクティス

AI組織でのアプリケーション開発の裏側 - Django × DDDでの開発プラクティス

2022年11月16日(水)開催、エンタープライズAIとモダンアプリケーション開発の実践~ISID✕Microsoft~ #2の 「AI組織でのアプリケーション開発の裏側 - Django × DDDでの開発プラクティス​」セッションでの発表スライドです。

AITC - DENTSU SOKEN

November 17, 2022
Tweet

More Decks by AITC - DENTSU SOKEN

Other Decks in Technology

Transcript

  1. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. 私たちが取り組んでいる開発スタイル、プラクティスについてを紹介 • 私たちはどんなチームか︖ • チームの特徴や抱えていた課題感の共有

    • どのようにDDDのプラクティスを実践しているか︖ • ドメイン分析プロセスの流れ • Djangoを使ったプロジェクトで、ドメイン分析の結果をコードに反映させる⽅法 今⽇お話すること 3
  2. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. アジャイルソフトウェア開発宣⾔ 7 私たちは、ソフトウェア開発の実践あるいは実践を⼿助けをする活動を通じて、よりよい開発⽅法を⾒つけだそうとしている。 この活動を通して、私たちは以下の価値に⾄った。 プロセスやツールよりも個⼈と対話を、

    包括的なドキュメントよりも動くソフトウェアを、 契約交渉よりも顧客との協調を、 計画に従うことよりも変化への対応を、 価値とする。すなわち、左記のことがらに価値があることを認めながらも、私たちは右記のことがらにより価値をおく。 Kent Beck Mike Beedle Arie van Bennekum Alistair Cockburn Ward Cunningham Martin Fowler James Grenning Jim Highsmith Andrew Hunt Ron Jeffries Jon Kern Brian Marick Robert C. Martin Steve Mellor Ken Schwaber Jeff Sutherland Dave Thomas ˜ ্هͷஶऀͨͪ ͜ͷએݴ͸ɺ͜ͷ஫ҙॻ͖΋ؚΊͨܗͰશจΛؚΊΔ͜ͱΛ৚݅ʹࣗ༝ʹίϐʔͯ͠Α͍ɻ https://agilemanifesto.org/iso/ja/manifesto.html
  3. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. ソフトウェア開発の難しさ • 顧客業務・要求の理解 • データ分析と異なり、書いたコードは中⻑期的に動作する

    • 継続的に⼿を加え続けられる必要がある 抱えていた課題 10 Djangoの難しさ • ⾮常に強⼒なフレームワークだが、使いこなせていない感 • Djangoモデルが秩序なく利⽤される
  4. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. ソフトウェア開発の難しさ • 顧客業務・要求の理解 • データ分析と異なり、書いたコードは中⻑期的に動作する

    • 継続的に⼿を加え続けられる必要がある ドメイン分析プロセスで⽴ち向かう課題 15 Djangoの難しさ • ⾮常に強⼒なフレームワークだが、使いこなせていない感 • Djangoモデルが秩序なく利⽤される
  5. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. アプリケーション開発を始める際に初期から⾮常に具体的な要求があるわけでは無い ⾼レベルな要求から整理しよう 18 AIを使って、アンケートの分析を楽にしたい ü

    アンケートの回答データを登録して、集計・分析したい ü 回答データから不適切なデータは取り除きたい ü 似たような回答をしている回答者をまとめたい ü センシティブなアンケートも扱うので、権限管理をして欲しい ü etc … 実務担当者
  6. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. ドメインモデルの和名と英名を整理する ※ 意味はその時点での理解が整理できればよい ドメインモデリングを実践する 22

    和名 英名 意味 アンケート Survey アンケート アンケート設定 Survey Setting アンケートの開始⽇や終了⽇などの設定 質問 Question アンケートに含まれる質問 回答結果 Survey Result アンケート終了後の回答結果全体 回答 Answer 回答結果全体に含まれる各回答 単⼀回答(SA) Single Answer 回答の中で単⼀選択の質問に対する回答 複数回答(MA) Multi Answer 回答の中で複数選択の質問に対する回答 ⾃由回答(FA) Free Answer 回答の中で⾃由記述の質問に対する回答 分析 Analysis 分析者が実施する分析業務の単位 分析結果 Analysis Result 分析結果
  7. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. ソフトウェア開発の難しさ • 顧客業務・要求の理解 • データ分析と異なり、書いたコードは中⻑期的に動作する

    • 継続的に⼿を加え続けられる必要がある ドメイン分析プロセスで⽴ち向かう課題 23 Djangoの難しさ • ⾮常に強⼒なフレームワークだが、使いこなせていない感 • Djangoモデルが秩序なく利⽤される
  8. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. ソフトウェア開発の難しさ • 顧客業務・要求の理解 • データ分析と異なり、書いたコードは中⻑期的に動作する

    • 継続的に⼿を加え続けられる必要がある ドメイン分析の結果をコードに反映させるで⽴ち向かう課題 25 Djangoの難しさ • ⾮常に強⼒なフレームワークだが、使いこなせていない感 • Djangoモデルが秩序なく利⽤される
  9. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. DDDの実装パターン 29 リポジトリ (Repository) 値オブジェクト

    (Value Object) 集約 (Aggregate) エンティティ (Entity) Application Service Domain Service サービス (Service)
  10. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. DDDの実装パターン 30 リポジトリ (Repository) 値オブジェクト

    (Value Object) 集約 (Aggregate) エンティティ (Entity) Application Service Domain Service サービス (Service)
  11. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. エンティティ・値オブジェクト・集約 31 値オブジェクト (Value Object)

    集約 (Aggregate) エンティティ (Entity) Application Service Domain Service サービス (Service) リポジトリ (Repository)
  12. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. エンティティ・値オブジェクト・集約 32 リポジトリ (Repository) “エンティティ”

    時間経過に関係なく保持される ⼀意のIDを持つオブジェクト “値オブジェクト” IDを持たず属性の値でのみ定義 されるオブジェクト 値オブジェクトは不変である “集約” 1つ以上のエンティティを含み、 ⼀貫性の境界を提供する概念 値オブジェクト (Value Object) 集約 (Aggregate) エンティティ (Entity) Application Service Domain Service サービス (Service)
  13. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. リポジトリ 33 リポジトリ (Repository) 値オブジェクト

    (Value Object) 集約 (Aggregate) エンティティ (Entity) Application Service Domain Service サービス (Service)
  14. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. リポジトリ 34 リポジトリ (Repository) 値オブジェクト

    (Value Object) 集約 (Aggregate) エンティティ (Entity) Application Service Domain Service サービス (Service) “リポジトリ” インフラストラクチャを隠蔽し、ドメイン オブジェクトの永続化と再構築する リポジトリの作成単位は集約とする
  15. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. ドメインモデルの実装パターン 38 リポジトリ (Repository) “エンティティ”

    時間経過に関係なく保持される ⼀意のIDを持つオブジェクト “値オブジェクト” IDを持たず属性の値でのみ定義 されるオブジェクト 値オブジェクトは不変である “集約” 1つ以上のエンティティを含み、 ⼀貫性の境界を提供する概念 値オブジェクト (Value Object) 集約 (Aggregate) エンティティ (Entity)
  16. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. pydanticを利⽤したAnalysisクラスの実装 Pythonでドメインモデルを表現するには 40 from typing

    import List from pydantic import BaseModel class Analysis(BaseModel): """分析クラス""" id: int name: str answers: List[FreeAnswer]
  17. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. pydanticを利⽤したFreeAnswerクラスの実装 Pythonでドメインモデルを表現するには 41 from typing

    import List from pydantic import BaseModel class FreeAnswer(BaseModel): """⾃由回答クラス""" id: int value: str tokens: List[Token]
  18. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. 1. 型ヒント( Type Hint )の恩恵を受けやすい

    2. ⼊⼒値検証(Validation)がしやすい 3. pydanticが提供する豊富な型(EmaiStrやHttpUrlなど)を利⽤できる 4. dict()メソッドによる辞書型への変換が容易 ドメインモデルに pydantic を使うメリット 43 Python 標準だけで実装するならば @dataclass を活⽤しましょう
  19. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Analysisクラスがフィールドに持つクラスもすべて永続化する 集約に対して Repository を実装する 44

    リポジトリ (Repository) “リポジトリ” インフラストラクチャを隠蔽し、ドメイン オブジェクトの永続化と再構築する リポジトリの作成単位は集約とする
  20. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Repositoryではインタフェースライクに抽象基底クラスを利⽤する Analysis Repository の抽象基底クラス 46

    from abc import ABC, abstractmethod from fa_analysis.domains.analysis import Analysis class AbstractAnalysisRepository(ABC): @abstractmethod def save(self, analysis: Analysis) -> Analysis: """Domain層のAnalysisを永続化するメソッド Args: analysis (Analysis): Domain層のAnalysisオブジェクト Returns: Analysis: 保存済みのAnalysisオブジェクト。別のインスタンスとして返す """ ...
  21. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Repositoryではインタフェースライクに抽象基底クラスを利⽤する Analysis Repository の抽象基底クラス 47

    from abc import ABC, abstractmethod from fa_analysis.domains.analysis import Analysis class AbstractAnalysisRepository(ABC): @abstractmethod def save(self, analysis: Analysis) -> Analysis: """Domain層のAnalysisを永続化するメソッド Args: analysis (Analysis): Domain層のAnalysisオブジェクト Returns: Analysis: 保存済みのAnalysisオブジェクト。別のインスタンスとして返す """ ...
  22. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Repositoryではインタフェースライクに抽象基底クラスを利⽤する Analysis Repository の抽象基底クラス 48

    from abc import ABC, abstractmethod from fa_analysis.domains.analysis import Analysis class AbstractAnalysisRepository(ABC): @abstractmethod def save(self, analysis: Analysis) -> Analysis: """Domain層のAnalysisを永続化するメソッド Args: analysis (Analysis): Domain層のAnalysisオブジェクト Returns: Analysis: 保存済みのAnalysisオブジェクト。別のインスタンスとして返す """ ...
  23. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Repositoryではインタフェースライクに抽象基底クラスを利⽤する Analysis Repository の抽象基底クラス 49

    from abc import ABC, abstractmethod from fa_analysis.domains.analysis import Analysis class AbstractAnalysisRepository(ABC): @abstractmethod def save(self, analysis: Analysis) -> Analysis: """Domain層のAnalysisを永続化するメソッド Args: analysis (Analysis): Domain層のAnalysisオブジェクト Returns: Analysis: 保存済みのAnalysisオブジェクト。別のインスタンスとして返す """ ... Repositoryのインターフェース設計では引数と返り値の 型をドメインオブジェクトとする
  24. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Repository の実装コード 52 from fa_analysis.domains

    import Analysis as DomainAnalysis from fa_analysis.models.analysis import Analysis, FreeAnswer, Token class AnalysisRepository(AbstractAnalysisRepository): """AnalysisRepositoryの実装""" def save(self, analysis: DomainAnalysis) -> DomainAnalysis: db_analysis = Analysis.from_domain(obj=analysis) db_answers = [] db_tokens = [] for answer in analysis.answers: db_answers.append(FreeAnswer.from_domain(obj=answer, analysis_id=analysis.id)) for token in answer.tokens: db_tokens.append(Token.from_domain(obj=token, answer_id=answer.id)) db_analysis.save() FAAnswer.objects.bulk_create(db_answers) Token.objects.bulk_create(db_tokens) return db_analysis.to_domain()
  25. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Repository の実装コード – 抽象クラスの継承 53

    from fa_analysis.domains import Analysis as DomainAnalysis from fa_analysis.models.analysis import Analysis, FreeAnswer, Token class AnalysisRepository(AbstractAnalysisRepository): """AnalysisRepositoryの実装""" def save(self, analysis: DomainAnalysis) -> DomainAnalysis: db_analysis = Analysis.from_domain(obj=analysis) db_answers = [] db_tokens = [] for answer in analysis.answers: db_answers.append(FreeAnswer.from_domain(obj=answer, analysis_id=analysis.id)) for token in answer.tokens: db_tokens.append(Token.from_domain(obj=token, answer_id=answer.id)) db_analysis.save() FAAnswer.objects.bulk_create(db_answers) Token.objects.bulk_create(db_tokens) return db_analysis.to_domain() as による別名インポート 抽象クラスの継承 実装メソッド
  26. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Repository の実装コード – Djangoモデル 54

    from fa_analysis.domains import Analysis as DomainAnalysis from fa_analysis.models.analysis import Analysis, FreeAnswer, Token class AnalysisRepository(AbstractAnalysisRepository): """AnalysisRepositoryの実装""" def save(self, analysis: DomainAnalysis) -> DomainAnalysis: db_analysis = Analysis.from_domain(obj=analysis) db_answers = [] db_tokens = [] for answer in analysis.answers: db_answers.append(FreeAnswer.from_domain(obj=answer, analysis_id=analysis.id)) for token in answer.tokens: db_tokens.append(Token.from_domain(obj=token, answer_id=answer.id)) db_analysis.save() FAAnswer.objects.bulk_create(db_answers) Token.objects.bulk_create(db_tokens) return db_analysis.to_domain() Djangoモデル ファクトリメソッドで Djangoモデルにマッピング
  27. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Repository の実装コード – Djangoモデル 55

    from fa_analysis.domains import Analysis as DomainAnalysis from fa_analysis.models.analysis import Analysis, FreeAnswer, Token class AnalysisRepository(AbstractAnalysisRepository): """AnalysisRepositoryの実装""" def save(self, analysis: DomainAnalysis) -> DomainAnalysis: db_analysis = Analysis.from_domain(obj=analysis) db_answers = [] db_tokens = [] for answer in analysis.answers: db_answers.append(FreeAnswer.from_domain(obj=answer, analysis_id=analysis.id)) for token in answer.tokens: db_tokens.append(Token.from_domain(obj=token, answer_id=answer.id)) db_analysis.save() FAAnswer.objects.bulk_create(db_answers) Token.objects.bulk_create(db_tokens) return db_analysis.to_domain() Djangoモデルの save()やbulk_create() を利⽤してRDBへ永続化
  28. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Repository の実装コード – 返り値 56

    from fa_analysis.domains import Analysis as DomainAnalysis from fa_analysis.models.analysis import Analysis, FreeAnswer, Token class AnalysisRepository(AbstractAnalysisRepository): """AnalysisRepositoryの実装""" def save(self, analysis: DomainAnalysis) -> DomainAnalysis: db_analysis = Analysis.from_domain(obj=analysis) db_answers = [] db_tokens = [] for answer in analysis.answers: db_answers.append(FreeAnswer.from_domain(obj=answer, analysis_id=analysis.id)) for token in answer.tokens: db_tokens.append(Token.from_domain(obj=token, answer_id=answer.id)) db_analysis.save() FAAnswer.objects.bulk_create(db_answers) Token.objects.bulk_create(db_tokens) return db_analysis.to_domain() Djangoモデルをドメインモデルに変換して返す
  29. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Repository の実装コード 57 from fa_analysis.domains

    import Analysis as DomainAnalysis from fa_analysis.models.analysis import Analysis, FreeAnswer, Token class AnalysisRepository(AbstractAnalysisRepository): """AnalysisRepositoryの実装""" def save(self, analysis: DomainAnalysis) -> DomainAnalysis: db_analysis = Analysis.from_domain(obj=analysis) db_answers = [] db_tokens = [] for answer in analysis.answers: db_answers.append(FreeAnswer.from_domain(obj=answer, analysis_id=analysis.id)) for token in answer.tokens: db_tokens.append(Token.from_domain(obj=token, answer_id=answer.id)) db_analysis.save() FAAnswer.objects.bulk_create(db_answers) Token.objects.bulk_create(db_tokens) return db_analysis.to_domain()
  30. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Django モデルの実装コード - Analysis 58

    from django.db import models from fa_analysis.domains.analysis import Analysis as DomainAnalysis class Analysis(models.Model): """Domain層のAnalysisとマッピングされるDjangoモデル""" id = models.IntegerField(primary_key=True) name = models.CharField(max_length=256) @classmethod def from_domain(cls, obj: DomainAnalysis) -> "Analysis": """ドメインモデルからのファクトリメソッド""" return cls(id=obj.id, name=obj.name) def to_domain(self) -> DomainAnalysis: """Djangoモデルからドメインモデルに変換するメソッド""" return DomainAnalysis( id=self.id, name=self.name, answers=[a.to_domain() for a in FreeAnswer.objects.filter(analysis=self)], )
  31. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Django モデルの実装コード - Analysis 59

    from django.db import models from fa_analysis.domains.analysis import Analysis as DomainAnalysis class Analysis(models.Model): """Domain層のAnalysisとマッピングされるDjangoモデル""" id = models.IntegerField(primary_key=True) name = models.CharField(max_length=256) @classmethod def from_domain(cls, obj: DomainAnalysis) -> "Analysis": """ドメインモデルからのファクトリメソッド""" return cls(id=obj.id, name=obj.name) def to_domain(self) -> DomainAnalysis: """Djangoモデルからドメインモデルに変換するメソッド""" return DomainAnalysis( id=self.id, name=self.name, answers=[a.to_domain() for a in FreeAnswer.objects.filter(analysis=self)], ) ドメインモデルからのファクトリメソッドの実装
  32. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Django モデルの実装コード - Analysis 60

    from django.db import models from fa_analysis.domains.analysis import Analysis as DomainAnalysis class Analysis(models.Model): """Domain層のAnalysisとマッピングされるDjangoモデル""" id = models.IntegerField(primary_key=True) name = models.CharField(max_length=256) @classmethod def from_domain(cls, obj: DomainAnalysis) -> "Analysis": """ドメインモデルからのファクトリメソッド""" return cls(id=obj.id, name=obj.name) def to_domain(self) -> DomainAnalysis: """Djangoモデルからドメインモデルに変換するメソッド""" return DomainAnalysis( id=self.id, name=self.name, answers=[a.to_domain() for a in FreeAnswer.objects.filter(analysis=self)], ) Djangoモデルからドメインモデルへの変換メソッド to_domain() で統⼀する
  33. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Django モデルの実装コード – FreeAnswer 61

    class FreeAnswer(models.Model): """Domain層のFAAnswerとマッピングされるDjangoモデル""" # フィールドは省略 @classmethod def from_domain(cls, obj: DomainFreeAnswer, analysis_id: int) -> "FreeAnswer": """ドメインモデルからのファクトリメソッド""" return cls( id=obj.id, value=obj.value, analysis=Analysis(id=analysis_id), ) def to_domain(self) -> DomainFreeAnswer: return DomainFreeAnswer( id=self.id, value=self.value, tokens=[t.to_domain() for t in Token.objects.filter(free_answer=self)], )
  34. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Django モデルの実装コード – FreeAnswer 62

    class FreeAnswer(models.Model): """Domain層のFAAnswerとマッピングされるDjangoモデル""" # フィールドは省略 @classmethod def from_domain(cls, obj: DomainFreeAnswer, analysis_id: int) -> "FreeAnswer": """ドメインモデルからのファクトリメソッド""" return cls( id=obj.id, value=obj.value, analysis=Analysis(id=analysis_id), ) def to_domain(self) -> DomainFreeAnswer: return DomainFreeAnswer( id=self.id, value=self.value, tokens=[t.to_domain() for t in Token.objects.filter(free_answer=self)], )
  35. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Django モデルの実装コード - Token 63

    class Token(models.Model): """Domain層のTokenとマッピングされるDjangoモデル""" # フィールドは省略 @classmethod def from_domain(cls, obj: DomainToken, answer_id: int) -> "Token": """ドメインモデルからのファクトリメソッド""" return cls(value=obj.value, free_answer=FreeAnswer(id=answer_id)) def to_domain(self) -> DomainToken: return DomainToken(value=self.value)
  36. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Django モデルの実装コード - Token 64

    class Token(models.Model): """Domain層のTokenとマッピングされるDjangoモデル""" # フィールドは省略 @classmethod def from_domain(cls, obj: DomainToken, answer_id: int) -> "Token": """ドメインモデルからのファクトリメソッド""" return cls(value=obj.value, free_answer=FreeAnswer(id=answer_id)) def to_domain(self) -> DomainToken: return DomainToken(value=self.value)
  37. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Django モデルの実装コード - Token 65

    class Token(models.Model): """Domain層のTokenとマッピングされるDjangoモデル""" # フィールドは省略 @classmethod def from_domain(cls, obj: DomainToken, answer_id: int) -> "Token": """ドメインモデルからのファクトリメソッド""" return cls(value=obj.value, free_answer=FreeAnswer(id=answer_id)) def to_domain(self) -> DomainToken: return DomainToken(value=self.value) Djangoの難しさ • ⾮常に強⼒なフレームワークだが、使いこなせていない感 • Djangoモデルが秩序なく利⽤される
  38. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. Repositoryのテストコード 66 class TestAnalysisRepository: @pytest.fixture

    def init_test(self) -> None: self.repository = AnalysisRepository() @pytest.mark.django_db def test_save(self, init_test: str) -> None: tokens = [ Token(value="すもも"), Token(value="も"), Token(value="もも"), Token(value="も"), Token(value="もも"), Token(value="の"), Token(value="うち"), ] answers = [FreeAnswer(id=1, value="すもももももももものうち", tokens=tokens)] analysis = Analysis(id=1, name="分析サンプル", answers=answers) result = self.repository.save(analysis=analysis) assert result == analysis
  39. COPYRIGHT INFORMATION SERVICES INTERNATIONAL-DENTSU, LTD. ソフトウェア開発の難しさ 今⽇お話したこと 69 Djangoの難しさ ドメイン分析

    パターンを適⽤し、 コードに反映 DDD(ドメイン駆動設計) ü 顧客業務・要求の理解促進 ü 実装におけるDjangoの役割を明確化し、よりクリーンなコードへ
  40. ISID AITCでは新しい仲間を募集しています また、右側の職種への応募⽤ページからご応募頂いても⼤丈夫です。 コンサルティング系 AIコンサルタント https://groupcareers.isid. co.jp/pgisid/u/job.phtml? job_code=591&company _code=1 AIビジネスプロジェクトマネージャー

    https://groupcareers.isid. co.jp/pgisid/u/sp/job.pht ml?job_code=532 製品開発系 AIエンジニア(製品開発) https://groupcareers.isid. co.jp/pgisid/u/job.phtml? job_code=647&company _code=1 AIプロダクトマネージャー https://groupcareers.isid. co.jp/pgisid/u/job.phtml? job_code=693&company _code=1 職種ごと応募ページ