Створюємо Proof of Concept, що зекономить час і ресурси: етапи та реалізація

💡 Усі статті, обговорення, новини про Front-end — в одному місці. Приєднуйтесь до Front-end спільноти!

Привіт! Я — Артем, Head of Front-end в OBRIO, продуктовій компанії з екосистеми Genesis. Наша команда розвиває продукт Nebula — найбільший бренд та № 1 за кількістю завантажень і бізнес-показниками у своїй ніші.

Коли стейкхолдери приходять з новою задачею, можна одразу переходити до планування і реалізації базового рішення. Або переконати бізнес спершу створити Proof of Concept — тестову реалізацію для перевірки ідеї. Хоча цей підхід потребує більше часу на початку, він допоможе суттєво зекономити його надалі, а також побудувати архітектуру, яка не розвалиться від першої ж зміни вимог. У цій статті ми підемо другим шляхом, і я розповім, чому це того варте. Поділюся, як розбиваю завдання на етапи, організовую роботу та намагаюся мінімізувати ризики для подальшого масштабування проєкту. Тож почнемо!

Задача

Створити сайт-опитувальник — quiz. У ньому користувач може переходити на наступний екран після цільової дії. У кінці опитування всі відповіді мають відправлятися на сервер.

Так виглядає спрощений дизайн (показано тільки три екрани, загалом їх більше):

Проста реалізація

  1. Стартуємо новий проєкт.
  2. Обираємо стек технологій. SPA або Next впораються з цією задачею. Не буду розпочинати холівар, що краще — це тема для окремої колонки. В межах цієї статті буде використовуватись SPA + React.
  3. Створюємо або використовуємо наявну бібліотеку компонентів.
  4. Верстаємо сторінки, додаємо роутинг та контент.
  5. Додаємо бізнес-логіку.
  6. Деплой.

Рішення створити верстку зі статичним контентом та одразу задеплоїти може здатися надто простим чи наївним. Проте, як любив повторювати один мудрий папуга, який вивчив одну фразу та відразу виріс до ліда, «It depends».

Спершу розглянемо переваги:

  • простота — можна реалізувати без складної архітектури;
  • швидкість — проєкт буде готовий у короткий термін, бізнес зможе швидко провалідувати ідею;
  • команда — для цього проєкту не обов’язково залучати фахівця з великим досвідом.

Недоліки:

  • гнучкість і масштабування — без чіткої архітектури додавати новий функціонал з часом стане дуже складно;
  • copy-paste — щоби зробити такий самий опитувальник, але «трішки інакший», потрібно буде скопіювати весь quiz;
  • технічний борг — через акцент на швидкість можливі недопрацювання, які з часом виллються у техборг;
  • обмежена адаптивність — зміна вимог бізнесу потребуватиме значних правок у коді, що забере додатковий час і ресурси.

Якщо недоліків багато, може здатися нелогічним навіть розглядати простий варіант. Але правда в тому, що іноді це рішення диктується обставинами. Наприклад, коли потрібно зробити щось терміново, буквально «на вчора», або коли команді не вистачає ресурсів чи часу для більш комплексного підходу, чи це може бути тимчасове рішення для валідації ідеї. У таких ситуаціях ми беремо і робимо, навіть розуміючи обмеження обраного шляху.

Але, щоб це рішення не виглядало спонтанним або необґрунтованим, зазвичай створюємо розширений список плюсів і мінусів за прикладом вище. Такий документ дає змогу аргументувати свою позицію перед бізнесом: показати, чого ми можемо досягти в короткостроковій перспективі, і водночас чесно попередити про обмеження, які виникнуть у майбутньому.

Уточнення вимог та PoC

За декілька днів з’явилися нові вимоги. Серед них — досить амбітний і водночас зрозумілий запит: «Хочемо змінювати контент через адмінку. ЇЇ поки немає, але треба закласти цю можливість і зробити усе так само швидко, як при простому підході». Запит зрозумілий, та він вносить фундаментальні зміни.

Для подібних задач я завжди пропоную рішення, яке за роки роботи себе виправдало — Proof of Concept (PoC). Це невеликий, тестовий проєкт, який дозволяє оцінити життєздатність ідеї, зрозуміти, як вона працюватиме на практиці, та визначити ризики. PoC допомагає трохи зазирнути у майбутнє нашого рішення.

Це все добре, але як це пояснити бізнесу? Відповідь проста: по-доброму, з повагою до їхніх очікувань. Я акцентую, що PoC — це не затримка, а інвестиція. Вона дозволяє вже на початковому етапі показати базовий функціонал, побачити ідею в дії та зменшити ризики у подальшій розробці. Це своєрідний тест-драйв, який економить час і нерви всім: і розробникам, і замовникам.

І, знаєте, коли стейкхолдери розуміють, що PoC допомагає уникнути хаотичних змін у майбутньому, час на його створення завжди знаходиться. Бо у підсумку всі виграють: ми отримуємо якісний фундамент для роботи, а бізнес — впевненість у тому, що проєкт буде розвиватися без зайвих збоїв.

Закладаємо основу архітектури

Підходів до розв’язання задачі адмінки більше за один, але зосереджусь на двох найпопулярніших:

  • використати Strapi, WordPress, інше стороннє рішення — більшість адмінок іде із коробки;
  • написати щось своє під потреби бізнесу.

Можливість змінювати контент була ключовою вимогою, тому важливо не просто розв’язати задачу, а відразу закласти гнучке та масштабоване рішення. Тому ідея написати власну адмінку виявилася оптимальною під ці вимоги.

Для цього потрібно створити конфігураційний файл, що зберігатиме дані у форматі JSON. Цей конфіг стане основою всього застосунку, своєрідним «скелетом», навколо якого можна буде будувати інші частини системи. Маючи конфіг, ми зможемо динамічно будувати quiz, а з часом додамо інструменти для його редагування, і core-функціонал майбутньої адмін-панелі буде готовий.

З планом вирішили. Рухаємось далі до створення концепту.

Етапи розробки Proof of Concept

Перший етап (quiz):

  1. Розпочати проєкт. Стек: Vite + React + TypeScript + React Router + MUI.
  2. Винести в окремий шар дані, на основі яких будуватиметься quiz. Вони повинні зберігатися в JSON-форматі.
    • Додати типізацію для даних, щоб запобігти додаванню невалідних значень в JSON.
    • Закласти логіку для переходів між екранами.
  3. Верстка: підготувати необхідні компоненти для UI.
  4. Перевірити функціональність: quiz повинен працювати коректно, враховуючи логіку переходів та збереження відповідей.

Другий етап (адмінка):

  1. Додати можливість змінювати контент за допомогою JSON.
  2. Додати можливість змінювати контент за допомогою UI.
  3. Рішення повинно масштабуватись і не потребувати додаткової розробки при додаванні нових екранів.

Для наочності я залишив тільки три екрани та прибрав всю «зайву» логіку, яка не впливає на прийняття архітектурних рішень. Деталі завжди можна доробити, головне — закласти фундаментально цю можливість.

Реалізація quiz

Основні концепції:

  • JSON config — дані для побудови опитувальника, які приходять із сервера. Кожен екран має type, за яким роутер направляє на потрібний степ.
  • WelcomeScreen — реалізація екрана, який вміє відображати передані в нього дані та переходити до наступного кроку.
  • Quiz — root-компонент для відображення будь-якого екрана згідно з активним роутом, який наповнюється даними із JSON config.
  • Validation config — схема валідації JSON. Важлива буде далі, коли потрібно буде редагувати JSON config.

JSON config:

{
  "steps": [
    {
      "path": "welcome", // Current step path - will be https://some-quiz.com/welcome
      "pathNext": "birth-date", // Next step path - will be  https://some-quiz.com/birth-date
      "type": "WELCOME", // Depends on type router understand which data can be past 
      "content": { // Any content for this screen with type WELCOME
        "header": "Ready to Discover Yourself?",
        "text": "<div style='font-size: 64px'>✨</div>

 <br> Hi there! Welcome to the exciting Zodiac quiz! Are you curious to find out what the stars say about you?",
        "backgroundImage": {
          "src": "

<https://plus.unsplash.com/premium_photo-1699967193418-e9a5db57559d?q=80&w=3174&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D>",
          "alt": "Constellations"
        },
        "footer": {
          "buttonNext": "Let’s Go!" // Button next label
        }
      }
    },
    ...
  ]
}

Welcome Screen:

interface Props {
  data: WelcomeStep;
}

export const WelcomeScreen: React.FC<Props> = ({ data }) => {
  const navigate = useNavigate();

  return (
    <Layout
      header={data.content.header}
      backgroundImage={data.content.backgroundImage}
      buttonNext={
        <ButtonNext 
	        label={data.content.footer?.buttonNext} 
	        onNext={() => navigate(`/${data.pathNext}`)} />
      }
    >
      <Typography 
	      variant="h6" 
	      align="center" 
	      dangerouslySetInnerHTML={{ __html: data.content.text }} />
    </Layout>
  );
};

Quiz разом iз роутером:

interface Props {
  data: string;
  setData: React.Dispatch<React.SetStateAction<string>>;
}

export const Quiz: React.FC<Props> = ({ data, setData }) => {
 const parsedData = JSON.parse(data) as QuizType;

 const dynamicRoutes = parsedData.steps?.map((step) => {
   switch (step.type) {
     case 'WELCOME':
       return (
         <Route key={step.path} path={step.path} element={<WelcomeScreen data={step as WelcomeStep} />} />
       );
     // ...
     default:
       return <Navigate replace to="/" />

;
   }
 });

 const router = createBrowserRouter(
   createRoutesFromElements(
     <Route
       element={
         <AnswersProvider>
           <EditorsContainer data={data} setData={setData} />
         </AnswersProvider>
       }
     >
       {dynamicRoutes}
       <Route path="*" element={<Navigate to="/welcome" replace />} />
     </Route>,
   ),
   { basename: import.meta.env.BASE_URL },
 );

 return <RouterProvider router={router} />;
};

Validation config:

import { z } from 'zod';

export enum StepType {
  DATE = 'DATE',
  WELCOME = 'WELCOME',
  ZODIAC_SIGN = 'ZODIAC_SIGN',
}

const StepTypeEnum = z.nativeEnum(StepType);

const BackgroundImageSchema = z.object({
  src: z.string().url(),
  alt: z.string(),
});

const FooterSchema = z.object({
  buttonNext: z.string().optional(),
});

const BaseStepSchema = z.object({
  path: z.string(),
  pathNext: z.string(),
  type: StepTypeEnum,
});

export const WelcomeStepSchema = BaseStepSchema.extend({
  type: z.literal(StepType.WELCOME),
  content: z.object({
    header: z.string(),
    text: z.string(),
    backgroundImage: BackgroundImageSchema,
    footer: FooterSchema.optional(),
  }),
});

Якщо потрібен новий екран, додаємо в JSON config → оновлюємо схему валідації → створюємо екран → додаємо в роутинг. Профіт! Все інше — деталі реалізації. Повне рішення можна подивитися на GitHub, робочий прототип тут.

Редагування контенту (адмінка)

Додаємо можливість редагувати контент. Для PoC абсолютно нормально прям поруч із quiz побудувати «мініадмінку». Надалі це буде окремий проєкт.

JSON Editor

Для цього використаємо Monaco Editor: передали data.json, пару рядків кода — і локальний Visual Code готовий до роботи.

import { Editor as MonacoEditor, EditorProps } from '@monaco-editor/react';

interface Props {
  data: string;
  onChange: EditorProps['onChange'];
}

export const JsonEditor: React.FC<Props> = ({ data, onChange }) => {
  return (
    <MonacoEditor
      height="100%"
      width="100%"
      theme="vs-dark"
      defaultLanguage="json"
      defaultValue={data}
      onChange={onChange}
    />
  );
};

UI editor

Нагадаю початкові умови:

  1. Рішення повинно масштабуватись і не потребувати додаткової розробки при створенні нових екранів.
  2. Ми не повинні писати код для форми редагування після того, як додали новий екран.

Для цього використаємо react-jsonschema-form. Це пакет, який вміє будувати UI-форму на базі JSON schema. Це значить, що можна будувати UI «безкоштовно» на базі форм валідації, які ми й так пишемо для проєкту.

У нас немає JSON schema, але є validation config (вище в тексті), створений за допомогою Zod. Тож спочатку потрібно конвертувати Zod schema в JSON schema. Для цього є пакет zod-to-json-schema.

Для наочності видалив зайвий код. Що тут важливо:

  • Знаходимо дані (поточний екран): currentStepSchema.
  • Додаємо ці дані у From: formData={currentStepData}.
  • Додаємо схему валідації цього екрана: currentStepSchema.
  • На кожен change оновлюємо значення JSON config: live preview + editor із коробки ❤️
interface Props {
  data: string;
  onChange: (data: string) => void;
}

export const FormEditor: React.FC<Props> = ({ data, onChange }) => {
	// ...
  const currentStepSchema = getJsonSchemaByType(currentStepData?.type || '');

  if (!currentStepData || !currentStepSchema) return null;

  const handleChange = (value: IChangeEvent) => {
    const updatedStepData = value.formData;

    const steps = quiz.steps.map((step) => {
      if (step.type === updatedStepData.type) {
        return updatedStepData;
      }

      return step;
    });

    onChange(JSON.stringify({ steps }));
  };

  return (
    <Form
      liveValidate
      schema={currentStepSchema}
      uiSchema={uiSchema}
      formData={currentStepData}
      validator={validator}
      onChange={handleChange}
    />
  );
};

Висновки

На цьому етапі PoC готовий для презентації команді. Далі після обговорення і покращень починається етап реалізації, але це вже зовсім інша історія зі своїми челенджами та додатковими PoC, які можуть виникнути в ході розробки.

Отже, підхід з використанням Proof of Concept допоміг досягти кількох важливих цілей одночасно:

  1. Швидко створити робочий прототип, продемонструвати концепцію та отримати зворотний зв’язок.
  2. Закласти міцний фундамент для подальшого розвитку проєкту. Він складається з двох ключових компонентів:
    • Структуровані дані, на базі яких будується quiz.
    • Гнучкий UI для редагування, легкого налаштування та модифікації опитувальника.
  3. Створити архітектуру, яка підтримує масштабування та адаптацію до нових вимог без необхідності повного переписування коду.

Цей підхід яскраво демонструє, як інвестиція часу в продуману архітектуру на початковому етапі окупається значною гнучкістю та економією ресурсів у довгостроковій перспективі. Завдяки цьому ми отримали не просто прототип, а повноцінну основу для подальшого розвитку продукту, яка може легко адаптуватися до нових потреб бізнесу.

Лінки:

👍ПодобаєтьсяСподобалось11
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Поправте мене, якщо я не правий.
POC повинен бути просто демо-версією, яка потрібна щоб зробити пітч ідеї для інвестора\замовника. Потім вона летить у смітник, і далі починаються хотєлкі-свістєлкі, якщо замовник зацікавився.
MVP версія зазвичай схожа на POC «як свиня на коня»

Чудова робота 👏

Дякую! Цікава і дуже корисна стаття🔥

Був клієнт, американець, хотів POC такий щоб вже як MVP, щоб його потім напільничком трошки вжух — і в продакшен. Було ніяково пояснювати, що це — профанація, і так не працює. Тому я малодушно з’єб*вся в закат.
Хотів я тоді замість себе підставити товариша, який на той час задовбався на якомусь тупому сапорті, але я стримався, не став йому казати про той проект. Але хрєн там, той товариш сам забіг на той стартапчик (я навіть і не натякав йому, він сам знайшов, бо на галері як в селі).
Згодом, зайшов до нього в гості глянути як він... вигляд в нього був як у того оператора РЛС з серіалу «Круте піке».

«PoC: Мистецтво зникати, поки друг не став оператором РЛС» 😄

Ну, він сам шукав щось таке, хотів.
А я чесно, без нажиму, дав зрозуміти, що не хочу підписуватись на той «стартап»

Клас! Дякую за статтю 🔥

Цікаво від тебе, щось почитати тепер. Впевнений, є чим поділитись ;)

Крута стаття, дякую! Добре, що хтось підіймає таку тему як важливість POC в циклах розробки, а то з тим як стихійно та «з наскоку» розвивається більшість проєктів, приємно знати, що ще є команди та компанії, які цінують свій час та ресурси і професійно та ґрунтовно підходять до розробки продукту

Створити сайт-опитувальник — quiz. У ньому користувач може переходити на наступний екран після цільової дії. У кінці опитування всі відповіді мають відправлятися на сервер.

Яку концепцію ви доводили? Що ви перевірили цим ПоК?

Хоча цей підхід потребує більше часу на початку, він допоможе суттєво зекономити його надалі, а також побудувати архітектуру, яка не розвалиться від першої ж зміни вимог

Теоретично певна частина правди в цьому твердженні є.
Але ПоК не є ні необхідною, ні достатньою умовою. Та і в цілому скоріше корелюється з правильним процесом прийняття рішень, і саме цей процес забезпечує якість архітектури.

Які альтернативи ви розглядали? Чому відкинули умовний surveyjs.io або відмовились від вбудованого рішення якогось сервейманкі?

Ми хотіли перевірити, чи зможемо створити гнучкий та кастомізований механізм для побудови квізів. PoC дозволив швидко перевірити ці базові ідеї без витрат на повноцінну розробку. Фактично, ми протестували, як наш стек технологій справляється з викликами (динамічна побудова форм, валідація, редагування, API-інтеграція, CI/CD), і підтвердили, що цей підхід працює і маштабується.

Через специфіку бізнес-вимог сторонні рішення дійсно могли пришвидшити старт. Однак на наступних етапах почали виникати обмеження та складнощі з більш глибокою кастомізацією. З огляду на наш досвід і розуміння вектора розвитку бізнесу, створення власного продукту стало природним і обґрунтованим вибором. Час показав, що це рішення було правильним і повністю себе виправдало.

Ми хотіли перевірити, чи зможемо створити гнучкий та кастомізований механізм для побудови квізів. PoC дозволив швидко перевірити ці базові ідеї без витрат на повноцінну розробку. Фактично, ми протестували, як наш стек технологій справляється з викликами (динамічна побудова форм, валідація, редагування, API-інтеграція, CI/CD),

Дякую. Ця відповідь (формулювання) чудово девонструє типові помилки при застосуванні ПоК :)
1) Зможете? Чи зможе конекретна команда? — це не архітектурне питання, а управлінське. Власне часто ПоК «продають» замовнику/бізнесу саме з метою навчання команди, а не підтримки архрішення.
Якщо ж гіпотеза була «Чи можливо створити», то тут ПоК не потрібен. Відповідь — можливо. І вона випливає або з досвіду, або з аналізу ринку.
2) Що значить гнучкий та кастомізований? Гугл форми — для когось достатньо гнучкий та кастомізований. Сурфейджс чим не підійшов? Власне він і демонструє, що це можливо.
3) Про стек — це знову ж про навчання. Будь-який більш менш популярний стек задовольняє тому, що ви написали.

З огляду на наш досвід і розуміння вектора розвитку бізнесу, створення власного продукту стало природним і обґрунтованим вибором. Час показав, що це рішення було правильним і повністю себе виправдало.

Цей текст винлядає як спроба загальними фразами спригнути з відповіді, що знову ж наводить на дуже неприємні думки про професіоналізм.
Власне чітка і проста відповідь на питання чому вирішили будувати, а не купувати дається у форматі: Ось така вимога не задовольняється тулом Т1, Т2 і тд.

Корисна стаття, дякую!

Підписатись на коментарі