Дублювання коду «здорової людини»: коли це виправдано

Привіт, я Ігор Левченко, працюю в IT з 2015 року, зараз Senior .NET/Sitecore Developer у DataArt. У межах менторської програми DataArt працюю з менш досвідченими колегами як ментор, що допомагає систематизувати професійні знання та готує до відповідей на спірні запитання.

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

❗️ ВАЖЛИВО: маю попередити вас, що бездумне дотримання подальших рекомендацій з цієї статті може зашкодити так само, як і бездумне дотримання будь-якого іншого принципу чи шаблону. Пам’ятайте приказку Парацельса: «Отрута є в усьому, і жодна річ не буває без отрути. Дозування робить її або отрутою, або ліками». Тож, нумо занурюватись.

Табу

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

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

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

І ця стаття має на меті спонукнути вас поглянути на проблеми дублювання під іншим кутом.

Що таке дублювання

Давайте розглянемо, про що йтиметься у статті.

Типи дублювання, які я розглядаю (цілком або частково):

  • Буквальне дублювання: назва говорить сама за себе — буквальне копіювання частин коду, структур та/або вмісту. Це може стосуватися одного рядка або цілих методів чи класів.
  • Семантичне дублювання: реалізація різна, але суть ідентична.
  • Структурне дублювання: копіювання загальної структури або організації класів/методів/модулів.
  • Ненавмисне дублювання: моє улюблене. Відбувається випадково через недостатню обізнаність або неуважність, коли різні розробники незалежно один від одного пишуть подібний функціонал, не усвідомлюючи цього.

Дублювання, яке я не розглядаю:

  • Дублювання конфігурації: дублювання налаштувань чи будь-яких інших змінних у конфігурації, у різних частинах кодової бази, як-от «connection strings», спеціальні значення для конфігурації застосунку тощо.
  • Дублювання від генераторів коду: ця тема занадто широка, щоб охопити її в цій статті. Кількість таких генераторів настільки значна й вони можуть працювати настільки по-різному, що я змушений залишити це вам як домашку.
  • Будь-який інший тип, який ви можете запропонувати: крім того, я не розповідаю про проєкти з відкритим вихідним кодом або утилітарні. Тут лише про бізнес і ентерпрайз.

Насамперед

Давайте нагадаємо собі, чому ми маємо уникати проблеми, що обговорюється.

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

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

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

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

Розмір кодової бази. Якщо ситуація заходить занадто далеко, це може вплинути на час компіляції чи навіть на час виконання.

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

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

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

Бізнес є бізнес

«Життя як корова, воно буває різним,» — українське прислів’я

Робочий процес звичайного програміста виглядає так: отримання вимог -> написання коду -> тестування (ви повинні протестувати, агов!) -> ... -> ПРОФІТ (отримання грошей).

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

Ще одна важлива річ. Припустімо, що нам знадобиться продублювати код або використати будь-яке інше сумнівне розв’язання проблеми. У такому випадку я наполягаю на повідомленні бізнесу про цю ситуацію з чітко вказаними причинами. Клієнт має розглянути ризики, що можуть з’явитися в середньо-/довгостроковій перспективі, та те, скільки ресурсів може піти на написання коду «належним» чином. Зрештою, саме бізнес володіє кодовою базою.

Коли ви можете перетнути межу

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

Термінова необхідність показати перші результати

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

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

Я був у ситуації, коли власник продукту хотів простий застосунок на 2–3 сценарії з 3–4 кроками в кожному. Але після першого демо керівництво вирішило його ускладнити. На той час ми вже мали архітектуру для простого плаского вебзастосунку, тому нам довелося витрачати час на її зміну для набуття більшої придатності для складніших сценаріїв, водночас розробляючи новий функціонал.

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

Термінові виправлення

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

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

Зміна вимог або процесу

Це пов’язано з пунктами, згаданими раніше. Ви можете іноді використовувати дублювання під час масштабної зміни вимог і обмеження в часі. Знову ж таки, швидша імплементація і тестування вимог, а рефакторинг пізніше можуть бути не найгіршим варіантом. Особливо якщо ваша команда велика і вам для початку ще треба зрозуміти, що саме потрібно рефакторити.

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

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

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

Завеликий вплив на легасі

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

Пам’ятаю кілька випадків, коли моїй команді не дозволяли змінювати застарілий код через потребу у зворотній сумісності. Водночас необхідні нові функції вимагали архітектурних змін. Застарілий код був реалізований і протестований давно (та ще й, мабуть, у далекій-далекій галактиці).

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

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

Незнання будь-якої хорошої практики

Може здатися смішним, але що бачите, те й отримуєте. Це все, що я можу сказати у разі недостатньо кваліфікованої команди.

Особисто я брав участь лише в одному проєкті з такою ситуацією (з метою мінімізації витрат). Вони мали підтримувати існуючий продукт. Їхній менеджер попросив мене приєднатися до команди, щоб зменшити технічний борг проєкту.

Чудовий час, коли я міг організовувати роботу, як захочу!

Проєкти, що закінчуються або є короткотривалими

«Après moi, le déluge» — «Після нас хоч потоп». Якщо ваш проєкт наближається до завершення, а час є обмеженим, можливо, варто зосередитися на стабільності та продуктивності, а не на чистоті та ідеальному стилі.

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

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

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

Додам, що коли у вас одночасно 9 проєктів на підтримці та 2 в активній стадії розробки, ви завжди будете молитися за людей, які зробили їх зрозумілими та не покинули на останній фазі життєвого циклу.

Індульгенція від розробника

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

У будь-якому разі пам’ятайте: ця частина не про те, що можна писати дурню, а про ситуації, коли вас можуть «зрозуміти і пробачити». Звісно, це не що інше, як моя особиста думка.

Керування версіями

Уявіть, що вам потрібно підтримувати кілька версій Web API. Усі вони можуть мати аналогічні функції, але різні механізми авторизації, обмеження, валідації, формати відповідей тощо.

Дублювання коду дозволяє налаштовувати кожен API з повторним використанням спільної бізнес-логіки.

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

Інтеграція

Візьмемо для прикладу програму, яка інтегрується з кількома зовнішніми службами чи системами. Вона може мати варіації у протоколах, форматах (як-от дата), механізмах автентифікації тощо.

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

Я працював з багатьма сторонніми сервісами, але більшість мали численні відмінності. На щастя, мені не довелося застосовувати цей пункт — все було згідно SOLID.

Локалізація ПЗ

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

У моєму досвіді були багатомовні проєкти, але нам не довелося кидати виклик загальним принципам, щоб керувати цим функціоналом, тому дуже багато про це не скажу.

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

Специфічний код для платформи

Мультиплатформовий UI може вимагати дублювання, щоб задовольнити специфічний дизайн кожної платформи та моделі взаємодії.

Ви можете генералізувати основну логіку, але може знадобитися й дублювати деякий код для UI для відповідності унікальним вимогам кожної.

Я майже не працював зі специфічним для різних платформ кодом. Втім, колись у мене було кілька дружніх розмов з людьми, які використовували Xamarin Forms, — вони скаржилися на різні колекції графічних контролів для певних платформ.

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

Конкретні оптимізації

  • Розгортання циклу та однорядкові розширення (Loop unrolling & inline expansion): передбачає заміну викликів функцій фактичним кодом функції, може покращити чутливу до продуктивності частину програми.
  • Спеціальна оптимізація архітектури може знадобитися при оптимізації низького рівня, специфічної для певної архітектури чи апаратної платформи.
  • Зменшення витрат на виклики функцій. Виклики функцій зазвичай призводять до певних додаткових витрат через влаштування стеку, передачу параметрів і керування адресами повернення. У сценаріях, чутливих до продуктивності, дублювання коду, замість узагальнення/ інкапсуляції його у функції, може змінити час виконання.

DTO

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

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

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

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

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

Ефект доміно

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

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

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

«Переінженерування»

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

Немає честі в самозадоволенні від рефакторингу, який нічого не покращує.

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

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

N.B.

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

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

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

Ніхто, крім вас і вашої команди, не може вирішувати, які методи, практики, стандарти чи шаблони застосовувати до вашої кодової бази — інструменти мають служити людям, а не навпаки.

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

👍ПодобаєтьсяСподобалось10
До обраногоВ обраному4
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

Процитую одного із президентів України: “Це ж було вже”

Sandi Metz “The wrong abstraction”
Dan Abramov “The wet codebase”
Kent C. Dodds “AHA programming”

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

Імхо, просто треба завжди задавати собі питання: Чи буде код від того легше читатися і розумітися? А також інколи: Чи зможе інша людина то підтримувати? Бо іноді перфекціоністи роблять все згідно патернів і практик, але воно від того тільки складніше стає. Якщо прочитав щось прикольне в книжчі, то не зажди треба намагатись його застосувати за будь-яку ціну. Ну і часто забуваємо, що то все для бізнесу, а не для красивого коду.

Води тут більше, ніж у Тихому океані

Кляте глобальне потепління!

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

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

Але, якщо зробити копіпасту в ситуації коли розвиток буде йти синхронно, то це призводить до того, що кожну багу треба фіксити двічі, кожний імпрувмент робити два рази, ще й не забувати про це. Звісно, тут краще спільний метод.

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

погоджуюсь
а потім, коли приходить час рефакторингу, треба тиждень, щоб декомпозувати того монстра на 2-4 простих зрозумілих методи. Тож повністю підтримую ідею дублювання на самому початку 👍
А ще просто феєрія, коли треба змінювати того монстра, деякі його дублюють з перевантаженням з різницею у 1-2 if’и.

Тому я постійно просуваю ідею періодичного виділення хоча б одного розробника, скажімо, на 0.5-1 спринт кожні пару місяців тупо щоб рефакторити. На жаль, це рідко коли спрацьовує, бо нові фічі приносять дохід, а рефакторинг — ні 😥 (хоча насправді він теж, але у довгостроковій перспективі)

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

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

В першому випадку треба дублювати, тоді загальна складність впаде і підтримка буде простіше (наприклад коли треба змінити тільки одну систему, а іншу не чіпати, чи додати третю, чи взагалі одну з них видалити)

В другому випадку, треба абстрагувати, бо буде нудно додавати зміни в кожну задубльовану підсистему

Для цього треба розуміти що таке сутність взагалі, а що не є сутнистью, а тільки частина чогось більшого.

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

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

Можу порекомендувати Data and Reality: A Timeless Perspective on Perceiving and Managing Information in Our Imprecise World з прекрасного курсу Teach Yourself CS

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

Я думаю, у цьому й є ментальна проблема — щоб люди не подумали, раз ти дублюєш, то це 100% ознака дурості. Саме тому мав за мету розвіяти цей міф у статті

якщо людина новачок, то буває навпаки, вона робить абстрактні речи (тому що синдром самозванця, чи щось таке), та потім це важко розуміти розширювати та підтримувати.

дуже прикро буває, коли решта команди ігнорують рев’ю та мерджать такі ПРи 😢

Настане той день, коли люди, а швидше вже АІ, почне дублювати код там, де потрібно.
Але зараз будемо писати 100500 мільйонів лейерів абстракції, щоб один раз не дай боже не зробити копіпаст. Молодці (джавісти) :)

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

У великому бізнесі із зоопарком систем цілі системи і навіть відділи та проекти можуть дублюватись (так от працюють дві окремі команди над одним і тим же і навіть не підозрюють про існування один одного та і топи не підозрюють про їх існування).
Головна проблема — у розмірах. З великими розмірами кодової бази, проектів, команд це завжди стається. Погано чи це ні з системної точки зору cкладно сказати і треба дивитись на кожен такий кейс окремо.

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

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

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

А ще якщо працювати як підрядник над спільним проектом з командою замовника ця фішка може бути використана як привід звинуватити підрядника у зриві дедлайнів і накладнанні штрафів. Досить ризикована штука

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

У мене така фігня була (причому я був в команді замовника :-) )
Кожна із сторін намагається спихнути один на одного як умога більше роботи. Причому за одну фітчу де роботи на годину разом із тестуванням та деплоєм можуть сратися тижнями.
Якщо щось ламається то менеджери перевдягаюються в костюми рембо і холодна війна перетворюється у горячий військовий конфлікт, який навіть може доходити до топів з обох сторій які із фразою «Ви що оху***» моментально гасився.

ну, в мене було трохи по-іншому: дві команди працювали над різними задачами, тому таких срачів, як у вас, не було. Зате через це нам не складно було доводити, що винні не ми 🤭
В решті решт, від тої команди таки позбавились, а ми красавчики у очах замовника 😁

Якщо у команді є вигоряння, це вже більша проблема ніж дублювання коду, треба спочатку бороти її

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