Лучший образец/практика выполнения многоэтапного процесса генерации кода

Лучший образец/практика выполнения многоэтапного процесса генерации кода
Лучший образец/практика выполнения многоэтапного процесса генерации кода - joelfilip @ Unsplash

Я работаю над проектом, который генерирует API с возможностью выполнения операций CRUD на основе высокоуровневого описания ресурсов, которые пользователь хотел бы иметь в приложении. В процессе генерации кода необходимо выполнить несколько шагов (для некоторого контекста, я генерирую код на Python из Python с помощью Jinja2):

  1. Генерация кода, который обрабатывает соединение с базой данных
  2. Генерация Docker-файлов
  3. Генерация моделей Pydantic для входных ресурсов
  4. Генерация классов, связывающих приложение с базой данных с помощью моделей SQLAlchemy
  5. Генерация методов, облегчающих CRUD-операции над таблицами базы данных
  6. Генерация кода API

Почти все операции зависят от ввода данных пользователем, но никак не связаны напрямую, поэтому могут выполняться даже параллельно.

Исследуя способы правильной обработки последовательных операций, я нашел паттерн "Цепочка ответственности", но он не совсем применим в моей ситуации, поскольку я должен выполнить все шаги независимо от ввода пользователя (если только это правильный ввод).

Я также думал о чем-то вроде паттерна Strategy для каждого процесса генерации, но мне трудно решить, подходит ли какой-либо из этих паттернов для моей ситуации.

В настоящее время я структурировал свой код следующим образом:

  1. Я получаю входные данные и проверяю выполнение нескольких условий (валидация).
  2. Я обрабатываю входные данные и изменяю их динамически, чтобы приспособить их для следующих шагов
  3. Я выполняю следующие шаги в процедурной манере, один за другим.
r = RelationshipHandler(Input(**res).resources)
r.execute()
resources = [resource.dict() for resource in r.resources]
generate_connection()
generate_db_create_code(resources)
generate_docker_compose()
generate_pydantic_models(resources)
generate_sqlalchemy_classes(resources)
generate_model_code(resources)
generate_fastapi_code(resources)

Все эти операции выполняются оркестрантом/хореографом - что, по сути, означает, что я использую, по крайней мере, чрезвычайно простую версию паттерна Choreography (более распространенного в контексте микросервисов).

Мой вопрос заключается в следующем: как подобные ситуации решаются в целом? Какие паттерны или лучшие практики позволят сделать код более чистым/читабельным/логичным и более легким в сопровождении?

Я понимаю, что может существовать множество способов обработки ситуаций, подобных описанной, я просто пытаюсь найти другие, более простые способы решения той же проблемы.

Нет ничего плохого в том, что оркестрант выполняет эти шаги один за другим

Когда вам нужен только этот фиксированный шаг последовательностей, не начинайте бросать в кодовую базу причудливые шаблоны, это только усложнит все без пользы.

Ключевым моментом, однако, является то, чтобы сделать вход и выход каждого из шагов явным, вместо того, чтобы использовать "глобальное состояние" для передачи данных.

Например:

conn=generate_connection()
my_code = generate_db_create_code(conn,resources)
generate_docker_compose(my_code)

(приведенные выше входные/выходные данные могут быть неверными, но, думаю, вы поняли идею).

Цели, стоящие за этим, следующие:

  • должно стать более понятным, что делает каждый шаг, и

  • каждый шаг должен быть изолирован с возможностью модульного тестирования, и

  • становится менее подверженным ошибкам, когда вам приходится добавлять или изменять порядок некоторых шагов.

Это типичные цели, которые вы должны иметь в виду при проектировании, а не какие-то шаблоны, о которых вы слышали.


LetsCodeIt, 27 декабря 2022 г., 07:09