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

Contract First или страх и ненависть в королевс...

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →

Contract First или страх и ненависть в королевстве CodeGen

Часто для решения одной бизнес задачи требуется коммуникация и совместная разработка нескольких команд. В микросервисной архитектуре задача упрощается, ведь сервисы имеют разную кодовую базу и взаимодействуют друг с другом по API. А значит требуется лишь договориться об общем API в начале разработки. Но так ли все просто и как автоматизировать этот процесс рассмотрим в нашем докладе.

Romanov Alexey

November 02, 2026

Transcript

36 slides
  1. СОДЕРЖАНИЕ + Коммуникация между командами разработки при совместной работе над

    одной задачей. + Что такое контракт? OpenAPI. + Contract First vs. Code First. Плюсы и минусы подходов. + Рассматриваем что умеет проект OpenAPI Generator. + Генерируем код по контракту на клиенте и сервере, разбираем что получилось. + Убираем лишние файлы. + Используем свои шаблоны генерации кода по OpenAPI. + Вместо выводов: как поддержать баланс между чувством прекрасного и сгенерированным кодом?
  2. О СПИКЕРЕ • В индустрии более 13 лет • Основная

    специализация – Java / Kotlin • Работаю в Иннотехе в роли Software Архитектора уже 3.5 года • Мы с вами встречались на других конференциях 🙂 3
  3. КОММУНИКАЦИЯ МЕЖДУ КОМАНДАМИ ПРИ СОВМЕСТНОЙ РАБОТЕ НАД ЗАДАЧЕЙ В Микросервисной

    Архитектуре практически любая задача требует взаимодействия нескольких сервисов, а значит для ее выполнения требуется параллельно вести разработку в нескольких командах. 4
  4. ЧТО ТАКОЕ КОНТРАКТ? Контракт – это соглашение о том, как

    будет выглядеть наше API, и какие параметры оно будет принимать. Спецификация OpenAPI определяет стандарт независимого от языка описания API, который позволяет понимать возможности службы без доступа к исходному коду. По сути, OpenAPI — это описание методов API, для которых описываются заголовки, входные и выходные параметры. 5
  5. OPENAPI 1. openapi: 3.0.1 2. info: 3. title: Servers API

    4. version: v1 5. servers: 6. - url: http://localhost:8080 7. paths: 8. /api/v1/servers: 9. get: 10. tags: 11. - server 12. summary: Find all servers 13. operationId: all 14. responses: 15. '200': 16. description: OK 17. content: 18. application/json: 19. schema: 20. $ref: '#/components/schemas/ServersResponse' 6
  6. CODE FIRST Code First – сначала пишем код, по нему

    генерируем контакт. + В коде не все можно описать, следовательно, мы можем получить невалидный или неполный OpenAPI. + Требуется время для написания кода, следовательно, другие команды вынуждены нас ждать. + Есть проблемы при генерации методов со сходной сигнатурой (/api/v1/users и /api/v1/users?login={{login}}) – они сливаются в один метод. 9
  7. CONTRACT FIRST Contract First – мы сначала согласовываем OpenAPI контракт,

    а потом по нему пишем или генерируем код. 10
  8. CONTRACT FIRST Contract First – у нас есть согласованный со

    всеми сторонами контакт, по нему мы генерируем код. + Сгенерированный код рабочий, но проблема в том, что он выглядит очень плохо и работать с ним зачастую неудобно. + В команде есть Code Style, соглашения о названиях классов и т.п., а значит нужно, чтобы весь код в проекте удовлетворял этим критериям. 11
  9. OPENAPI GENERATOR Для генерации кода возьмем самое распространенное решение –

    проект OpenAPI Generator. + Генерация клиентского и серверного кода для всем популярных языков и фреймворков (Java, Kotlin, Go, C#, JavaScript и т.п.). + Валидация OpenAPI. + Возможность кастомизации шаблонов. https://openapi-generator.tech/ 12
  10. OPENAPI 1. openapi: 3.0.1 2. info: 3. title: Servers API

    4. version: v1 5. servers: 6. - url: http://localhost:8080 7. paths: 8. /api/v1/servers: 9. get: 10. tags: 11. - server 12. summary: Find all servers 13. operationId: all 14. responses: 15. '200': 16. description: OK 17. content: 18. application/json: 19. schema: 20. $ref: '#/components/schemas/ServersResponse' 14
  11. ГЕНЕРИРУЕМ КОД КЛИЕНТА $ openapi-generator-cli generate \ -g kotlin \

    --api-package ru.romanow.openapi.client.rest \ --model-package ru.romanow.openapi.client.models \ --additional-properties=enumPropertyNaming=UPPERCASE \ -o client/build/generated \ -i openapi/servers.yml 15
  12. ГЕНЕРИРУЕМ КОД КЛИЕНТА 1. /** 2. * Please note: 3.

    * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). 4. * Do not edit this file manually. 5. */ 6. @file:Suppress("ArrayInDataClass", "EnumEntryName", "UnusedImport") 7. package ru.romanow.openapi.client.models 8. 9. import ru.romanow.openapi.client.models.Purpose 10.import ru.romanow.openapi.client.models.StateInfo 11.import com.fasterxml.jackson.annotation.JsonProperty 12. 13.data class ServerResponse ( 14. @get:JsonProperty("id") val id: kotlin.Int, 15. @get:JsonProperty("purpose") val purpose: Purpose, 16. @get:JsonProperty("latency") val latency: kotlin.Int, 17. @get:JsonProperty("bandwidth") val bandwidth: kotlin.Int, 18. @get:JsonProperty("state") val state: StateInfo 19.) 17
  13. УБИРАЕМ ЛИШНИЕ ФАЙЛЫ В сгенерированном коде мы получаем большое количество

    лишних файлов: + build.gradle, settings.gradle, gradlew, gradlew.bat, gradle/*; + README.md, docs/*; + файлы в пакете /org/.../infrastructure/**. 18
  14. УБИРАЕМ ЛИШНИЕ ФАЙЛЫ Опишем эти исключения в файле .openapi-generator-ignore: +

    **/*.gradle + **/gradlew* + **/README.md + **/docs/*.md + **/gradle/ + **/.openapi-generator-ignore + **/org/openapitools/client/infrastructure/*.kt + **/ru/romanow/openapi/client/rest/*.kt 19
  15. УБИРАЕМ ЛИШНИЕ ФАЙЛЫ $ openapi-generator-cli generate \ -g kotlin \

    --config openapi/client/config.yml \ --ignore-file client/.openapi-generator-ignore \ -o client/build/generated \ -i openapi/servers.yml 20
  16. СТРУКТУРА ШАБЛОНА В качестве движка шаблонизации используется Mustache. Выгрузим шаблон

    для Kotlin: $ openapi-generator-cli author \ template -g kotlin \ --library jvm-spring-webclient \ -o openapi/templates 22
  17. СТРУКТУРА ШАБЛОНА Есть 5 входных типов файлов, а остальные просто

    являются частью других шаблонов: + API – клиент или сервер; + APIDocs – markdown описание API; + Model – модели; + ModelDocs – markdown описание моделей; + SupportingFiles – дополнительные файлы. 24
  18. МОДИФИЦИРУЕМ ШАБЛОН { "importPath": "ru...models.CreateServerRequest", "model": { "name": "CreateServerRequest", "classname":

    "CreateServerRequest", "isPrimitiveType": false, "vars": [ { "openApiType": "string", "dataType": "kotlin.String", "name": "purpose", "required": true, "isPrimitiveType": true, "isString": true, "isNumeric": false, "isNullable": false, "vars": [], "hasValidation": false, } ] } 1. data class {{classname}} ( 2. {{#vars}} 3. var {{name}}: {{{dataType}}}? = null 4. {{/vars}} 5. ) } 25
  19. МОДИФИЦИРУЕМ ШАБЛОН 1. 2. 3. 4. 5. 6. 7. 8.

    9. {{>licenseInfo}} package {{package}}; {{#models}} {{#model}} {{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{>pojo}}{{/isEnum}} {{/model}} {{/models}} 26
  20. МОДИФИЦИРУЕМ ШАБЛОН + {{>...}} – подключение шаблона. + {{ …

    }} – обращение к значению переменной; + {{#...}} .... {{\...}} – обращение к переменной (так же используется для обхода списка). 27
  21. МОДИФИЦИРУЕМ ШАБЛОН $ openapi-generator generate \ -g kotlin \ --config

    openapi/client/config.yml \ --ignore-file client/.openapi-generator-ignore \ --template-dir openapi/client/templates \ -o client/build/generated \ -i openapi/servers.yml 29
  22. МОДИФИЦИРУЕМ ШАБЛОН + Если нам не требуется модифицировать шаблон, то

    мы просто его не меняем и он создается на основе базовых шаблонов. + Если требуется убрать сгенерированные файлы, то просто описываем их в .openapi-generator-ignore. 31
  23. ВЫВОДЫ + Если разработка идет в одной команде, то возможно

    Code First вам подойдет, т.к. для него не требуется никаких особенных настроек. + Возможность генерировать модели и клиента по OpenAPI позволяет нам быстрее реагировать на изменения в реализации. + OpenAPI generator сгенерирует за вас весь boilerplate. + OpenAPI generator позволяет кастомизировать шаблоны, следовательно, вы можете сгенерировать код, удовлетворяющий Code Style и вашему чувству прекрасного. 32

More Decks by Romanov Alexey

Other Decks in Programming