Чи розщеплення потенційно монолітного додатку на кілька менших допомагає запобігти помилкам? [зачинено]


48

Ще один спосіб запитати це; чому програми мають тенденцію бути монолітними?

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

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


9
If the animation and modelling capabilities were split into their own separate application and developed separately, with files being passed between them, would they not be easier to maintain?Не змішуйте простіший спосіб розширення з легшим у обслуговуванні модулем - не є без ускладнень та сумнівних конструкцій. Майя може бути пекло на землі, поки її плагіни не є. Або навпаки.
Лаїв

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

2
@DarthFennec Найкращі програми виглядають як один додаток для користувача, але використовують все необхідне під кришкою. Скільки мікросервісів живлять різні веб-сайти, які ви відвідуєте? Майже ніхто з них не є монолітами!
corsiKa

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

5
@corsiKa - Я б здогадався, що переважна кількість веб-сайтів, якими я користуюся, все ще є монолітами. Зрештою, більша частина Інтернету працює на Wordpress.
Давор Ждрало

Відповіді:


94

Так. Як правило, два менші менш складні програми набагато простіше в обслуговуванні, ніж одне велике.

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

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


6
Так, також є міркування щодо продуктивності, наприклад, вартість проходження вказівника порівняно з серіалізацією даних.
JimmyJames

65
"Зазвичай 2 менші менш складні програми набагато простіше в обслуговуванні, ніж одне велике." - це правда, за винятком випадків, коли його немає. В значній мірі залежить від того, де і як ці два програми мають взаємодіяти між собою.
Док Браун

10
"Зазвичай 2 менші менш складні програми набагато простіше в обслуговуванні, ніж одне велике." Думаю, я хочу ще трохи пояснення цьому. Чому саме процес генерації двох замість одного виконуваного з кодової бази магічно полегшить код? Те, що визначає, наскільки простий код міркувати, - це те, наскільки він щільно поєднаний і подібні речі. Але це логічне розмежування і не має нічого спільного з фізичним .
Voo

11
@Ew Фізичний поділ не примушує логічного роз'єднання, у цьому проблема. Я легко спроектую систему, де два окремих додатки тісно пов'язані між собою. Звичайно , є якась - то кореляція бере участь тут , так як люди , які проводять час , щоб відокремити додаток, швидше за все , досить компетентно розглядати ці речі, але є мало підстав вважати , будь-яку причинно - наслідковий зв'язок . За цією ж логікою я можу стверджувати, що використання останньої версії C # значно полегшує підтримку коду, оскільки команда, яка постійно в курсі своїх інструментів, ймовірно, також буде турбуватися про підтримку коду.
Ву

9
Я думаю, що обговорення тут можна узагальнити двома твердженнями: 1) Розщеплення додатка саме по собі не робить додаток більш рентабельним - навпаки, це дає ще один можливий момент відмови 2) Розщеплення програми змушує задуматися про те, де подіти це, що забезпечує перевагу порівняно з монолітом, коли цього ніколи не робилося.
Р. Шмітц

51

Розщеплення потенційно монолітного додатку на кілька менших допомагає запобігти появі помилок

Насправді речі рідко такі прості.

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

Однак,

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

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

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

Коротше кажучи, це часто компроміс, і ніщо там, де відповідь "так" чи "ні" взагалі правильна.

чому програми, як правило, є монолітними

Вони? Подивіться навколо, у світі є gazillions веб-додатків, які не дуже схожі на мене монолітними, навпаки. Існує також багато програм, які пропонують модель плагінів (AFAIK навіть програмне забезпечення Maya, яке ви згадали).

чи не було б їм простіше в обслуговуванні

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


4
останнє речення, закон Конвея говорить, що структура системи, як правило, імітує орг. структура: розробки / команди більш знайомі з деякими частинами, ніж інші, тому, хоча виправлення / вдосконалення повинні відбуватися в найбільш релевантній частині, може бути простішим розбивати розробника в "свої" частини, а не (а) дізнаватися, як це інша частина працює або (b) співпрацювати з кимось більш знайомим з цією частиною. Це пов’язано зі згадками @TKK про "шви", і наскільки важко знайти та застосувати "правильні" / прості.
Варбо

38

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

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

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

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


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

3
@TheGreatDuck Це здається, що це також усуне нетривіальну кількість користувачів, яким не подобається перемикатися між різними програмами. ;) Але так, усунення функцій, як правило, призведе до більш простого коду. Усуньте перевірку орфографії, і ви усунете можливість виникнення помилок перевірки орфографії. Це робиться рідко, тому що функція була додана тому, що хтось цього хотів.
Одалрік

1
@TheGreatDuck Безумовно, дизайн UX повинен бути перед будь-якими архітектурними рішеннями. Немає сенсу мати найкраще розроблену архітектуру, якщо ніхто не використовує вашу програму. Спочатку вирішіть, що ви хочете побудувати, і виходячи з вирішення технічних деталей. Якщо бажано дві окремі програми, перейдіть до цього. Ви все ще можете поділитися великим кодом за допомогою спільних бібліотек.
Ву

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

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

15

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


чудовий пост. я думаю, що класичним / канонічним прикладом того, про що ви говорите, є програма GUI. багато разів програма GUI є однією програмою, і бекенд / фронтенд є щільно пов'язаними. з часом виникають проблеми ... як би хтось інший повинен використовувати бекенд, але не може, тому що він прив’язаний до фронтенду. або обробка резервного інтерфейсу займає занадто багато часу і знижується по фронту. часто одна велика програма GUI поділяється на дві програми: одна - це інтерфейс інтерфейсу, а інший - бекенд.
Тревор Бойд Сміт

13

Важливо пам’ятати, що кореляція не є причиною.

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

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

Чому дрібні деталі краще? Тому що вони простіше міркувати. І якщо легко міркувати про правильність, ви, швидше за все, отримаєте правильний результат.

Щоб процитувати CAR Hoare:

Існує два способи побудови дизайну програмного забезпечення: Один із способів - зробити його настільки простим, що явно немає недоліків, а другий спосіб - зробити його таким складним, що явних недоліків немає .

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

Перший спосіб набагато складніше.

І пізніше в тому ж джерелі (лекція премії Тюрінга 1980 року):

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


6

Це не питання з відповіддю "так" чи "ні". Питання не просто у обслуговуванні, це також питання ефективного використання навичок.

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

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

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

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


4

Ні . це не полегшує обслуговування. Якщо що-небудь привітає більше проблем.

Чому?

  • Програми не є ортогональними, їм потрібно зберегти роботу один одного, наскільки це розумно, що передбачає загальне розуміння.
  • Багато код обох програм однаковий. Ви підтримуєте спільну спільну бібліотеку чи зберігаєте дві окремі копії?
  • Зараз у вас є дві команди розвитку. Як вони спілкуються?
  • Тепер у вас є два продукти, які потрібні:

    • загальний стиль користувальницького інтерфейсу, механізми взаємодії тощо ... Отже, у вас зараз проблеми з дизайном. (Як команди спілкування знову спілкуються?)
    • зворотна сумісність (чи можна імпортувати модельєр v1 в animator v3?)
    • хмарну / мережеву інтеграцію (якщо вона є функцією) тепер потрібно оновлювати вдвічі більше продуктів.
  • Зараз у вас є три споживчі ринки: модельєри, аніматори та аніматори моделей

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

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

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

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


3

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

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

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

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


2
Моя перша робота програміста була програмістом тисячоліття. Програмне забезпечення, над яким я працював, було розбито на сотні маленьких програм, які все зробили незначну частину, з'єднані з пакетними файлами та використовуючи файли для зв'язку стану. Це було велике безладдя, придумане в той час, коли комп'ютери були повільними, мало пам'яті, а зберігання було дорогим. Коли я з ним працював, коду було вже 10-15 років. Як тільки ми закінчилися, вони попросили мої поради, і моя порада полягала в тому, щоб перетворити все на нову монолітну програму. Вони зробили, і через рік я отримав велике спасибі.
Пітер Б

@PieterB У мене був подібний досвід. "Передовий" технологій, на жаль, дуже великий вантажний культ у багатьох напрямках. Замість вибору найкращого методу для роботи багато компаній просто пітимуть за тим, що робить FAANG без будь-якого питання.
CL40

а також: те, що може скластися як монолітне додаток, коли воно буде складено, може бути дуже модульним додатком, кодовим.
Пітер Б

1

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

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

Якщо одиниці даних, з якими програма обробляє, є великими (тобто зображеннями), то будь-які затримки між процесами будуть довше і важче усунути - щось на кшталт "застосувати перетворення до зображення 10 Мб" негайно набере додатково + 20 Мб дискового / мережевого вводу до 2 перетворення з формату пам'яті у формат serializabe і назад. Ви дійсно не так багато можете зробити, щоб приховати від користувача час, необхідний для цього.

Крім того, будь-яка комунікація, а особливо дисковий IO, підлягають перевірці AntiVirus / Firewall - це неминуче додає ще один шар важкого відтворення помилок та ще більше затримок.

Розщеплення монолітної "програми" світиться там, коли затримки зв'язку не є критичними або вже неминучі

  • паралелізована об'ємна обробка інформації, де ви можете торгувати невеликими додатковими затримками для значного вдосконалення окремих кроків (іноді усуваючи потребу в користувацьких компонентах, використовуючи один раз позачергові). Невеликий індивідуальний крок може допомогти вам використовувати кілька дешевих машин замість одного дорогого, наприклад.
  • розділення монолітних сервісів на менш пов'язані мікропослуги - виклик декількох служб паралельно замість однієї, швидше за все, не додасть додаткових затримок (може навіть зменшити загальний час, якщо кожна окрема швидша і немає залежностей)
  • переміщення операцій, які очікують, що користувачі зайнятимуть тривалий час - надання складних 3d сцени / фільму, обчислення складних показників щодо даних, ...
  • всілякі "автоматичні завершення", "перевірку орфографії" та інші необов'язкові посібники можуть бути часто зовнішніми - найбільш очевидним прикладом є автоматичні пропозиції URL-адреси веб-переглядача, куди весь вхід постійно надсилається до зовнішньої служби (пошукової системи). .

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


0

Чи допомагає [це] запобігати помилкам?

Запобігти? Ну ні, не дуже.

  • Це допомагає виявити помилок .
    А саме про всі помилки, про які ви навіть не знали, що ви виявили лише тоді, коли намагалися розділити цілий безлад на менші частини. Так, певним чином це не дозволило цим клопам з’явитися у виробництві - але помилки вже були.
  • Це допомагає зменшити вплив помилок .
    Помилки в монолітних програмах можуть потенційно знищити всю систему і взагалі не дозволяти користувачеві взаємодіяти з вашою програмою. Якщо ви розділите це додаток на компоненти, більшість помилок - за допомогою дизайну - впливатимуть лише на один із компонентів.
  • Це створює сценарій нових помилок .
    Якщо ви хочете зберегти користувальницьку роботу однаковою, вам потрібно буде включити нову логіку для всіх цих компонентів для спілкування (через послуги REST, через системні дзвінки ОС, що у вас є), щоб вони могли безперешкодно взаємодіяти з POV користувача.
    Як простий приклад: ваш монолітний додаток дозволяє користувачам створювати модель та анімувати її, не виходячи з програми. Ви розділите додаток на два компоненти: моделювання та анімацію. Тепер ваші користувачі повинні експортувати модель програми для моделювання у файл, потім знайти файл, а потім відкрити його за допомогою програми для анімації ... Поміркуймо, деякі користувачі цього не сподобаються, тому ви повинні включити нову логіку для додаток для моделювання для експорту файлу таавтоматично запустити додаток для анімації та змусити його відкрити файл. І ця нова логіка, настільки проста, наскільки це може бути, може мати ряд помилок щодо серіалізації даних, доступу до файлів та дозволів, користувачів, які змінюють шлях встановлення додатків тощо.
  • Це ідеальний привід застосувати дуже потрібний рефакторинг .
    Коли ви вирішили розділити монолітну програму на більш дрібні компоненти, ви (сподіваємось) це зробите набагато більше знань та досвіду щодо системи, ніж коли вона була вперше розроблена, і завдяки цьому ви можете застосувати ряд рефакторів, щоб зробити код чистіший, простіший, ефективніший, стійкіший, безпечніший. І це рефакторинг певним чином може допомогти запобігти появі помилок. Звичайно, ви також можете застосувати те саме рефакторинг до монолітного додатку, щоб запобігти тим самим помилкам, але ви цього не зробите, бо це настільки монолітне, що ви боїтесь доторкнутися до інтерфейсу і порушити бізнес-логіку ¯ \ _ (ツ) _ / ¯

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.