Настроил презентацию
This commit is contained in:
parent
66308fe472
commit
3e4f36f972
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,7 @@
|
|||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
.idea
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
/node_modules
|
/node_modules
|
||||||
/.pnp
|
/.pnp
|
||||||
|
4
Makefile
Normal file
4
Makefile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
build:
|
||||||
|
yarn export
|
||||||
|
deploy:
|
||||||
|
scp -r ./out/* rinsvent@188.225.77.88:/home/rinsvent/dev/gateway_data/static/tbd
|
@ -2,6 +2,17 @@
|
|||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
swcMinify: true,
|
swcMinify: true,
|
||||||
|
images: {
|
||||||
|
loader: "imgix",
|
||||||
|
path: "https://tbd.rinsvent.ru/",
|
||||||
|
},
|
||||||
|
webpack(config) {
|
||||||
|
config.module.rules.push({
|
||||||
|
test: /\.svg$/,
|
||||||
|
use: ["@svgr/webpack"]
|
||||||
|
});
|
||||||
|
return config;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = nextConfig
|
module.exports = nextConfig
|
||||||
|
@ -6,11 +6,17 @@
|
|||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint"
|
"lint": "next lint",
|
||||||
|
"export": "next build && next export"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@emotion/react": "^11.10.4",
|
||||||
|
"@emotion/styled": "^11.10.4",
|
||||||
|
"@fontsource/roboto": "^4.5.8",
|
||||||
|
"@mui/material": "^5.10.11",
|
||||||
"next": "12.3.1",
|
"next": "12.3.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
"react-code-blocks": "^0.0.9-0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
461
pages/index.tsx
461
pages/index.tsx
@ -1,69 +1,432 @@
|
|||||||
import type { NextPage } from 'next'
|
import type {NextPage} from 'next'
|
||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import styles from '../styles/Home.module.css'
|
import styles from '../styles/Home.module.css'
|
||||||
|
import '@fontsource/roboto/300.css';
|
||||||
|
import '@fontsource/roboto/400.css';
|
||||||
|
import '@fontsource/roboto/500.css';
|
||||||
|
import '@fontsource/roboto/700.css';
|
||||||
|
import {CopyBlock, github} from "react-code-blocks";
|
||||||
|
import {Table, TableBody, TableRow, TableCell, TableHead} from '@mui/material';
|
||||||
|
|
||||||
const Home: NextPage = () => {
|
const Home: NextPage = () => {
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Create Next App</title>
|
<title>Create Next App</title>
|
||||||
<meta name="description" content="Generated by create next app" />
|
<meta name="description" content="Generated by create next app"/>
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico"/>
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<main className={styles.main}>
|
<main className={styles.main}>
|
||||||
<h1 className={styles.title}>
|
<h1>Trunk-Based Development</h1>
|
||||||
Welcome to <a href="https://nextjs.org">Next.js!</a>
|
<section>
|
||||||
</h1>
|
Модель ветвления в системе контроля версий, в которой разработчики работают над кодом в единственной
|
||||||
|
ветке под названием ‘trunk’. Эта модель позволяет не создавать другие долгоживущие ветки и описывает
|
||||||
|
технику как именно это делать. Разработчики избегают merge конфликтов при слиянии кода, не ломают
|
||||||
|
сборку, и живут долго и счастливо
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>Базовые принципы</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Любые коммиты в trunk не должны ломать сборку</li>
|
||||||
|
<li>Любые коммиты в trunk должны быть маленькими настолько, чтобы review нового кода не занимало
|
||||||
|
более 10 минут
|
||||||
|
</li>
|
||||||
|
<li>Релиз выпускается только на основе trunk</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
<p className={styles.description}>
|
<section>
|
||||||
Get started by editing{' '}
|
<h2>GIT flow VS TBD</h2>
|
||||||
<code className={styles.code}>pages/index.tsx</code>
|
<h3>Конфликты</h3>
|
||||||
</p>
|
<Table>
|
||||||
|
<TableBody>
|
||||||
<div className={styles.grid}>
|
<TableRow>
|
||||||
<a href="https://nextjs.org/docs" className={styles.card}>
|
<TableCell></TableCell>
|
||||||
<h2>Documentation →</h2>
|
<TableCell>GIT</TableCell>
|
||||||
<p>Find in-depth information about Next.js features and API.</p>
|
<TableCell>TBD</TableCell>
|
||||||
</a>
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
<a href="https://nextjs.org/learn" className={styles.card}>
|
<TableCell>Auto merge</TableCell>
|
||||||
<h2>Learn →</h2>
|
<TableCell>Yes</TableCell>
|
||||||
<p>Learn about Next.js in an interactive course with quizzes!</p>
|
<TableCell>Yes</TableCell>
|
||||||
</a>
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
<a
|
<TableCell>Manual merge</TableCell>
|
||||||
href="https://github.com/vercel/next.js/tree/canary/examples"
|
<TableCell>Yes</TableCell>
|
||||||
className={styles.card}
|
<TableCell>Yes</TableCell>
|
||||||
>
|
</TableRow>
|
||||||
<h2>Examples →</h2>
|
<TableRow>
|
||||||
<p>Discover and deploy boilerplate example Next.js projects.</p>
|
<TableCell>Manual merge (интеграция задачи в измененный код)</TableCell>
|
||||||
</a>
|
<TableCell>Yes</TableCell>
|
||||||
|
<TableCell>No</TableCell>
|
||||||
<a
|
</TableRow>
|
||||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
</TableBody>
|
||||||
className={styles.card}
|
</Table>
|
||||||
>
|
</section>
|
||||||
<h2>Deploy →</h2>
|
<section>
|
||||||
|
<h2>Долгоживущие ветки</h2>
|
||||||
|
Проблемы:
|
||||||
|
<ul>
|
||||||
|
<li>Накапливаются конфликты</li>
|
||||||
|
<li>Код из ветки недоступен для выполнения других задач</li>
|
||||||
|
<li>Параллельная разработка одного и того же механизма</li>
|
||||||
|
<li>Рассинхронизация логики кода в разных ветках</li>
|
||||||
|
<li>Ломается история GIT при конфликтах</li>
|
||||||
|
<li>Блокируется деплой готовой задачи, если вначале нужно задеплоить другую</li>
|
||||||
|
<li>Блокировка выполнения второстепенной задачи, если нужен код из другой задачи</li>
|
||||||
|
</ul>
|
||||||
<p>
|
<p>
|
||||||
Instantly deploy your Next.js site to a public URL with Vercel.
|
При GIT flow долгоживущие ветки - это норма. У нас в проекте были ветки возрастом более года.
|
||||||
|
Актуализация таких веток занимала несколько дней. А ведь эти ресурсы можно было использовать на разработку новых фич!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
При TBD если разработка идет непосредственно в master/trunk таких проблем нет - код актуализируется после первого pull запроса.
|
||||||
|
Разница с local state будет минимальна. В большинстве случаев получим fast forward.
|
||||||
|
При работе в feature ветке могут возникать проблемы описанные выше. Чтобы минимизировать проблемы, TBD
|
||||||
|
рекомендует ограничение жизнь ветки в 2 дня.
|
||||||
|
Это условный интервал, за который не должно накопиться много конфликтов.
|
||||||
|
Дополнительным положительным фактором является то, что основная часть команды продолжает писать в master, и этот код можно подливать в feature ветку
|
||||||
|
и тем самым уменьшать количество конфликтов, которые могут появиться в день X. Когда ветка вольется в master.
|
||||||
|
Важно соблюдать правило 2 дней!
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>Разный state БД</h2>
|
||||||
|
Это порождает ошибки разработки и деплоя.
|
||||||
|
<ul>
|
||||||
|
<li>Ошибка генерации миграции. Например, при добавлении новой колонки мы указываем после какой колонки надо добавить новое поле. Но этой колонки может не оказаться на момент деплоя.</li>
|
||||||
|
<li>Мы не можем просто так взять и добавить колонку с constraint not null так как в других ветках код не будет работать. Это порождает тех. долг, мусорный код и ошибки, которые могут быть спровоцированы не законченным кодом.</li>
|
||||||
|
<li>Ошибки doctrine. Если добавить новый тип данных doctrine, но код не распространить по всем веткам, то там где его нет, будут ошибки во время калькуляции метаданных.</li>
|
||||||
|
</ul>
|
||||||
|
<p>При GIT flow различное состояние бд - это норма</p>
|
||||||
|
<p>
|
||||||
|
При следовании TBD эти проблемы исключаются. Изменение структуры бд всегда происходит в мастер.
|
||||||
|
Разработчикам остается актуализировать ветку и проблема решена.
|
||||||
</p>
|
</p>
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Разработка</h2>
|
||||||
|
<h3>GIT flow</h3>
|
||||||
|
При GIT flow нужно работать над задачей в отдельной ветке
|
||||||
|
Задач много, следовательно веток много.
|
||||||
|
Все ветки различаются. Различается набор сервисов. Различается структура бд.
|
||||||
|
Для начала разработки нужно переключиться на ветку
|
||||||
|
Обычно приходится почистить кеш. Применить миграции. Для тестов переинициализировать бд.
|
||||||
|
Без регламента на мелкие commit`ы, провоцируются ситуации когда вся задача складывается в один commit, что делает историю менее читаемой.
|
||||||
|
Так же при таком подходе могут накапливаться изменения файлов при разработке.
|
||||||
|
Когда возникает необходимость переключиться на другую задачу, то нужно спрятать незакомиченные правки (при возвращении к задаче нужно будет снова накатить патч изменений). Этот процесс занимает время и отвлекает от задачи, уменьшает желание уходить с ветки.
|
||||||
|
|
||||||
|
<h3>TBD</h3>
|
||||||
|
При TBD нужно работать мелкими правками. Большую часть времени работаем в мастер.
|
||||||
|
У всех приблизительно одинаковый набор сервисов, состояние БД.
|
||||||
|
Небольшие различия в коде, вероятно, даже не повлияют на работоспособность окружения.
|
||||||
|
Если возникает необходимость переключиться на другую задачу. Нет необходимости уходить в другую ветку и пересобирать окружение. Задачу можно сделать здесь на месте. Закомитить правку и продолжить основную задачу.
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Release ready</h2>
|
||||||
|
<h3>GIT</h3>
|
||||||
|
Состояние Release ready достигается путем слияния feature ветки в staging и проверке на dev стенде.
|
||||||
|
По факту мы тестируем измененный код. Отличающийся от master и production.
|
||||||
|
Что может спровоцировать ряд ошибок.
|
||||||
|
<h3>TBD</h3>
|
||||||
|
Состояние Release ready достигается за счет создания release ветки и проверке на dev стенде.
|
||||||
|
Как и в случае с GIT flow. Мы создаем отдельную ветку и тестируем.
|
||||||
|
Различия в том что в случае GIT на дев стенде одновременно находится ряд задач в финальной стадии реализации, нуждающиеся в мелких правках.
|
||||||
|
При TBD на дев стенде будут находиться сразу все задачи принятые в работу в разных состояниях готовности.
|
||||||
|
В данном случае тестируется ровно тот же код что окажется в production, с теми же feature flags. Это позволяет избежать ряда ошибок и гарантировать что эту ошибку возможно воспроизвести локально, а не искать ветку в рамках которой появилась ошибка.
|
||||||
|
|
||||||
|
Есть ряд правил которые минимизируют количество ошибок на дев стенде
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<b>Маленькие атомарные комиты.</b>
|
||||||
|
Позволяют легче воспринимать изменения и снижают риск ошибки.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<b>Continuous review</b>
|
||||||
|
Теперь код не спрятан в отдельной ветке, а доступен всем.
|
||||||
|
Правки прилетают небольшие и каждый может их изучить.
|
||||||
|
Тем самым будет происходить слежение за развитием продукта и понимание что меняется
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<b>Автотесты</b>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<b>Парное программирование</b>
|
||||||
|
Позволяет снизить риск, того что будет допущена ошибка и спроектировать качественное архитектурное решение по задаче
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<b>Feature flags</b>
|
||||||
|
Весь не готовый код должен быть скрыт за флагом
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Сложные задачи по прежнему можно делать в отдельных ветках
|
||||||
|
Важно <b>декомпозировать</b> задачу так, чтобы работы по ней длились не более 2 дней.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<b>Частые деплои.</b>
|
||||||
|
Уменьшает количество правок которое должно уйти в production. Следовательно и риски что-то поломать.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Схема работы по TBD</h2>
|
||||||
|
<div className={styles.imageWrapper}>
|
||||||
|
<Image src={`/trunk.png`} layout={`fill`}/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>TBD</h2>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Приемущества</TableCell>
|
||||||
|
<TableCell>Недостатки</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Частые интеграции</TableCell>
|
||||||
|
<TableCell>Сложность. Нужно понимать SOLID. Увеличивается порог входа в проект</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Постепенное изменение кода</TableCell>
|
||||||
|
<TableCell>Нужно делать абстракции вокруг кода который меняется</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Возможность быстро переключиться на другую задачу</TableCell>
|
||||||
|
<TableCell>Нужно написать сервисный слой для работы по TBD. Например: как использовать feature flags</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Всегда актуальный код</TableCell>
|
||||||
|
<TableCell>Нужно закрывать незаконченный код через флаги, что увеличивает количество кода.</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Нет конфликтов</TableCell>
|
||||||
|
<TableCell>Более качественная итоговая архитектура механизма</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Всегда одна структура бд</TableCell>
|
||||||
|
<TableCell>Есть вероятность, что в проекте будут оставаться “мертвые” ветки кода.</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Уменьшение тех. долга, за счет работы с актуальной версией кода.</TableCell>
|
||||||
|
<TableCell>Нужно убирать использование флагов когда код ушел в прод</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Нужно покрывать код тестами, легче вносить изменения.</TableCell>
|
||||||
|
<TableCell>Нужно покрывать код тестами, чтобы гарантировать работоспособность.</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell></TableCell>
|
||||||
|
<TableCell>Чаще будем встречать push reject</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Branch by Abstraction</h2>
|
||||||
|
Можно выделить следующие этапы:
|
||||||
|
<ul>
|
||||||
|
<li>Выделить интерфейс для заменяемой функциональности.</li>
|
||||||
|
<li>Заменить прямой вызов реализации в клиенте на обращение к интерфейсу.</li>
|
||||||
|
<li>Создать новую реализацию, которая реализует интерфейс.</li>
|
||||||
|
<li>Подменить старую реализацию на новую.</li>
|
||||||
|
<li>Удалить старую реализацию.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Пример, реализации задачи</h2>
|
||||||
|
<p>Имеем механизм отправки писем</p>
|
||||||
|
<div className={styles.code}>
|
||||||
|
<CopyBlock
|
||||||
|
text={`...
|
||||||
|
public function send(EmailSender $sender, array $data): void
|
||||||
|
{
|
||||||
|
$sender->send($data);
|
||||||
|
}
|
||||||
|
...`}
|
||||||
|
language={`php`}
|
||||||
|
showLineNumbers={false}
|
||||||
|
startingLineNumber={1}
|
||||||
|
theme={github}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p>Выделяем интерфейс</p>
|
||||||
|
<div className={styles.code}>
|
||||||
|
<CopyBlock
|
||||||
|
text={`interface SenderInterface {
|
||||||
|
public function send(array $data): void;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
language={`php`}
|
||||||
|
showLineNumbers={false}
|
||||||
|
startingLineNumber={1}
|
||||||
|
theme={github}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p>Интегрируем его в старый механизм</p>
|
||||||
|
<div className={styles.code}>
|
||||||
|
<CopyBlock
|
||||||
|
text={`EmailSender implements SenderInterface`}
|
||||||
|
language={`php`}
|
||||||
|
showLineNumbers={false}
|
||||||
|
startingLineNumber={1}
|
||||||
|
theme={github}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p>Заменяем прямой вызов на обращение через интерфейс</p>
|
||||||
|
<div className={styles.code}>
|
||||||
|
<CopyBlock
|
||||||
|
text={`public function send(SenderInterface $sender, array $data): void
|
||||||
|
{
|
||||||
|
$sender->send($data);
|
||||||
|
}`}
|
||||||
|
language={`php`}
|
||||||
|
showLineNumbers={false}
|
||||||
|
startingLineNumber={1}
|
||||||
|
theme={github}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p>Делаем новую реализацию</p>
|
||||||
|
<div className={styles.code}>
|
||||||
|
<CopyBlock
|
||||||
|
text={`SmsSender implements SenderInterface`}
|
||||||
|
language={`php`}
|
||||||
|
showLineNumbers={false}
|
||||||
|
startingLineNumber={1}
|
||||||
|
theme={github}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p>Заменяем вызов старого механизма на новый</p>
|
||||||
|
<div className={styles.code}>
|
||||||
|
<CopyBlock
|
||||||
|
text={`
|
||||||
|
public __construct(EmailSender $emailSender, SmsSender $smsSender) {
|
||||||
|
$this->emailSender = $emailSender;
|
||||||
|
$this->smsSender = $smsSender;
|
||||||
|
}
|
||||||
|
public function execute() {
|
||||||
|
feature(FeatureEnum::UseSmsSender)
|
||||||
|
? $this->send($this->smsSender, [])
|
||||||
|
: $this->send($this->emailSender, []);
|
||||||
|
}`}
|
||||||
|
language={`php`}
|
||||||
|
showLineNumbers={false}
|
||||||
|
startingLineNumber={1}
|
||||||
|
theme={github}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p>либо сразу через DI</p>
|
||||||
|
<div className={styles.code}>
|
||||||
|
<CopyBlock
|
||||||
|
text={`
|
||||||
|
services:
|
||||||
|
--- App\\Service\\SenderInterface: '@App\\Service\\EmailSender'
|
||||||
|
+++ App\\Service\\SenderInterface: '@App\\Service\\SmsSender'
|
||||||
|
`}
|
||||||
|
language={`yaml`}
|
||||||
|
showLineNumbers={false}
|
||||||
|
startingLineNumber={1}
|
||||||
|
theme={github}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p>и в коде будет так</p>
|
||||||
|
<div className={styles.code}>
|
||||||
|
<CopyBlock
|
||||||
|
text={`
|
||||||
|
public __construct(
|
||||||
|
private EmailSender $sender
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute() {
|
||||||
|
$this->send($this->sender, [])
|
||||||
|
}`}
|
||||||
|
language={`php`}
|
||||||
|
showLineNumbers={false}
|
||||||
|
startingLineNumber={1}
|
||||||
|
theme={github}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Feature Flags</h2>
|
||||||
|
<p>Суть подхода в том чтобы обернуть код в if с проверкой пред. установленной опции.
|
||||||
|
Например,</p>
|
||||||
|
<div className={styles.code}>
|
||||||
|
<CopyBlock
|
||||||
|
text={`if (feature(FeatureEnum::UseClickhouse)) {
|
||||||
|
// код
|
||||||
|
}`}
|
||||||
|
language={`php`}
|
||||||
|
showLineNumbers={false}
|
||||||
|
startingLineNumber={1}
|
||||||
|
theme={github}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p>или</p>
|
||||||
|
<div className={styles.code}>
|
||||||
|
<CopyBlock
|
||||||
|
text={`feature(FeatureEnum::UseClickhouse)
|
||||||
|
? // новая логика
|
||||||
|
: // старая логика
|
||||||
|
`}
|
||||||
|
language={`php`}
|
||||||
|
showLineNumbers={false}
|
||||||
|
startingLineNumber={1}
|
||||||
|
theme={github}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
Все флаги описываются в enum, что позволяет быстро отследить все места в проекте где флаг используется.
|
||||||
|
Для применения флагов на проекте, было реализовано следующее решение:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Сначала берутся значения из .env файлов</li>
|
||||||
|
<li>Далее проверяются значения в переменных окружения, например: если явно передать значение в docker</li>
|
||||||
|
<li>В конце проверяется значение в сессии, что позволяет быстро включить/выключить флаг и проверить функционал.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Для удобного управления флагами и мониторинга состояния активности флага, на коленке была собрана служебная страница</p>
|
||||||
|
<div className={styles.imageWrapper}>
|
||||||
|
<Image src={`/feature_flags_page.png`} layout={`fill`}/>
|
||||||
|
</div>
|
||||||
|
<p>Правил с флагами будет два:</p>
|
||||||
|
<ul>
|
||||||
|
<li>После того, как функциональность полностью протестирована и стабильно работает, флаг нужно удалить.</li>
|
||||||
|
<li>Мест в коде, где идет ветвление по одному и тому же feature флагу, должно быть минимальное количество.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>Декомпозиция задач и Short-lived ветки </h2>
|
||||||
|
Все ветки кода, кроме главной, должны иметь короткий срок жизни, максимум – несколько дней.
|
||||||
|
Этого можно добиться за счет мелкой декомпозиции: ветка будет небольшой, если она решает небольшую задачу.
|
||||||
|
Правильная постановка задач на этапе планирования играет очень важную роль.
|
||||||
|
Можно, например, придерживаемся принципа декомпозиции задач INVEST.
|
||||||
|
|
||||||
|
Декомпозиция по INVEST определяет, каким должен быть пользовательский сценарий (user story):
|
||||||
|
<ul>
|
||||||
|
<li>Independent — независимый</li>
|
||||||
|
<li>Negotiable — написанный понятным языком</li>
|
||||||
|
<li>Valuable — несущий ценность</li>
|
||||||
|
<li>Estimable — поддающийся оценке</li>
|
||||||
|
<li>Small — компактный, не более 40 часов разработки</li>
|
||||||
|
<li>Testable — тестируемый в широком смысле</li>
|
||||||
|
</ul>
|
||||||
|
Каждую из планируемых задач нужно «прогнать» по всем этим пунктам. Если по результатам выпадает хотя бы один из них, задачу нужно декомпозировать заново.
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
<footer className={styles.footer}>
|
<footer className={styles.footer}>
|
||||||
<a
|
Powered by <b>Rinsvent</b>
|
||||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
Powered by{' '}
|
|
||||||
<span className={styles.logo}>
|
|
||||||
<Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
BIN
public/feature_flags_page.png
Normal file
BIN
public/feature_flags_page.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
public/trunk.png
Normal file
BIN
public/trunk.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
@ -1,5 +1,11 @@
|
|||||||
.container {
|
.container {
|
||||||
padding: 0 2rem;
|
padding: 0 5rem;
|
||||||
|
font-size: 20px;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container section {
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
@ -15,7 +21,7 @@
|
|||||||
.footer {
|
.footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 2rem 0;
|
padding: 1rem 0;
|
||||||
border-top: 1px solid #eaeaea;
|
border-top: 1px solid #eaeaea;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -57,12 +63,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.code {
|
.code {
|
||||||
background: #fafafa;
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 0.75rem;
|
width: 100%;
|
||||||
font-size: 1.1rem;
|
border: #edeef0 solid 1px;
|
||||||
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
|
}
|
||||||
Bitstream Vera Sans Mono, Courier New, monospace;
|
|
||||||
|
.imageWrapper {
|
||||||
|
position: relative;
|
||||||
|
width: auto;
|
||||||
|
height: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid {
|
.grid {
|
||||||
|
Loading…
Reference in New Issue
Block a user