Невже щось, що мутує, врешті-решт не маніпулює станом?
Так, але якщо він стоїть за функцією члена малого класу, яка є єдиною сутністю у всій системі, яка може маніпулювати його приватним станом, то ця держава має дуже вузьку сферу застосування.
Що ви повинні мати, щоб мати справу з якомога меншою кількістю держав?
З точки зору змінної: якомога менше рядків коду повинно мати доступ до неї. Звузьте область змінної до мінімуму.
З точки зору рядка коду: якомога менше змінних має бути доступним з цього рядка коду, наскільки це можливо. Вузькі кількість змінних , що рядок коду може можливо доступ (це навіть не важливо , що багато це робить доступ до нього, все , що має значення , чи є це може ).
Глобальні змінні настільки погані, оскільки мають максимальний обсяг. Навіть якщо вони мають доступ з 2 рядків коду в кодовій базі, з рядка коду POV завжди доступна глобальна змінна. Із POV змінної глобальна змінна із зовнішнім зв'язком доступна кожному окремому рядку коду у всій базі коду (або кожній окремій рядку коду, що так чи інакше включає заголовок). Незважаючи на те, що до нього доступні лише два рядки коду, якщо глобальна змінна видима до 400 000 рядків коду, ваш негайний список підозрюваних, коли ви виявите, що він встановлений як недійсний стан, тоді матиме 400 000 записів (можливо, швидко зменшиться до 2 записи з інструментами, але, тим не менш, у найближчому списку буде 400 000 підозрюваних, і це не є обнадійливою початковою точкою).
Цілком ймовірно, що навіть якщо глобальна змінна почне змінюватися лише двома рядками коду у всій базі коду, невдала тенденція розвитку кодових баз змінюватись назад, як правило, збільшуватиметься чисельність цього числа, просто тому, що може збільшити стільки розробники, несамовиті дотримуватися термінів, бачать цю глобальну змінну і розуміють, що вони можуть приймати ярлики через неї.
Нечистою мовою, такою як C ++, чи справді управління державою не те, що ви робите?
Загалом, так, якщо ви не використовуєте C ++ дуже екзотичним способом, який дозволяє вам мати справу з виготовленими на замовлення незмінними структурами даних та чистим функціональним програмуванням протягом усього часу - це також часто джерело більшості помилок, коли управління державою стає складним, а складність - часто функція видимості / експозиції цього стану.
І які ще способи впоратися з якомога меншим станом, окрім обмеження змінного терміну служби?
Все це знаходиться в царині обмеження обсягу змінної, але є багато способів зробити це:
- Уникайте суворих глобальних змінних, як чума. Навіть якась німа глобальна функція сеттера / геттера різко звужує видимість цієї змінної і, принаймні, дозволяє певний спосіб збереження інваріантів (наприклад: якщо глобальній змінній ніколи не слід дозволити бути негативною величиною, сетер може підтримувати цю інваріантну). Звичайно, навіть дизайн сетерів / геттерів на додаток до того, що в іншому випадку було б глобальною змінною, є досить поганим дизайном, я можу сказати, що це все ще краще.
- Зробіть свої заняття меншими, коли це можливо. Клас із сотнями функцій-членів, 20 змінних-членів та 30 000 рядків коду, що реалізує його, мав би досить "глобальні" приватні змінні, оскільки всі ці змінні були б доступні для його функцій-членів, які складаються з 30-ти рядкових кодів. Ви можете сказати, що "складність стану" в цьому випадку, при цьому дисконтування локальних змінних у кожній функції члена є
30,000*20=600,000
. Якщо б було доступно 10 глобальних змінних, доступних над цим, то складність стану могла б бути такою 30,000*(20+10)=900,000
. Здорова «державна складність» (мій особистий вид винайденої метрики) повинна бути в тисячах чи нижче для класів, а не в десятках тисяч і, безумовно, не в сотнях тисяч. Про безкоштовні функції скажіть сотні чи нижче, перш ніж ми почнемо отримувати серйозні головні болі в обслуговуванні.
- Так само, як і вище, не реалізовуйте щось як функцію-члена або функцію друзів, яка в іншому випадку може бути нечленем, недругом, використовуючи лише загальнодоступний інтерфейс класу. Такі функції не можуть отримати доступ до приватних змінних класу, і, таким чином, зменшити потенціал помилок за рахунок зменшення сфери застосування цих приватних змінних.
- Уникайте декларування змінних задовго до того, як вони фактично потрібні функції (тобто уникайте застарілого стилю C, який оголошує всі змінні у верхній частині функції, навіть якщо їм потрібно лише багато рядків нижче). Якщо ви все-таки використовуєте цей стиль, принаймні прагніть до коротших функцій.
Поза змінні: побічні ефекти
Багато цих керівних принципів, які я перераховував вище, стосуються прямого доступу до сировинного, змінного стану (змінних). Однак у досить складній кодовій базі просто звуження сфери необмежених змінних буде недостатньо, щоб легко міркувати про правильність.
Можливо, у вас, скажімо, центральна структура даних, що стоїть за абсолютно ТВОРИМ, абстрактним інтерфейсом, цілком здатним ідеально підтримувати інваріанти, і все-таки стикається з великим горем через широке опромінення цього центрального стану. Прикладом центрального стану, який не обов'язково є загальнодоступним, а лише широкодоступним, є графік центральної сцени ігрового двигуна або структура даних центрального рівня Photoshop.
У таких випадках ідея "стану" виходить за рамки необмежених змінних, а саме до структур даних і речей такого роду. Це також допомагає зменшити їх обсяг (зменшити кількість ліній, які можуть викликати функції, що опосередковано їх мутують).
Зверніть увагу, як я навмисно позначив тут навіть інтерфейс червоним, оскільки з широкого, зменшеного архітектурного рівня, доступ до цього інтерфейсу все ще мутує стан, хоча і опосередковано. Клас може підтримувати інваріанти в результаті інтерфейсу, але це заходить далеко лише з точки зору нашої здатності міркувати про правильність.
У цьому випадку центральна структура даних стоїть за абстрактним інтерфейсом, який може бути навіть недоступним у всьому світі. Він може бути просто введений, а потім опосередковано мутований (через функції учасників) із завантаження функцій судна у вашій складній кодовій базі.
У такому випадку, навіть якщо структура даних ідеально підтримує свої власні інваріанти, дивні речі можуть відбуватися на більш широкому рівні (наприклад: аудіоплеєр може підтримувати всі види інваріантів, як, наприклад, рівень гучності ніколи не виходить за межі від 0% до На 100%, але це не захищає його від того, що користувач натисне кнопку відтворення та матиме випадковий аудіокліп, відмінний від того, який він нещодавно завантажив, розпочати відтворення як подія, що призведе до того, що список відтворення перетворюється в правильний спосіб, але все ще небажана, гнучка поведінка з точки зору широкого споживача).
Спосіб захисту себе в цих складних сценаріях - це «вузьке місце» в кодовій базі, яка може викликати функції, які в кінцевому підсумку можуть викликати зовнішні побічні ефекти навіть від такого широкого погляду на систему, що виходить за межі необмеженого стану та за межі інтерфейсів.
Як не дивно, як це виглядає, ви можете бачити, що жоден "стан" (показаний червоним кольором, і це не означає "сира змінна", це просто означає "об'єкт" і, можливо, навіть за абстрактним інтерфейсом), до якого звертаються численні місця . Кожна з функцій має доступ до локального стану, який також доступний центральним оновленням, а центральний стан доступний лише для центрального оновлення (що робить його більше не центральним, а скоріше локальним).
Це лише для дійсно складних баз коду, як гра, яка охоплює 10 мільйонів рядків коду, але вона може надзвичайно допомогти в міркуванні про правильність вашого програмного забезпечення та виявленні, що ваші зміни дають передбачувані результати, коли ви істотно обмежуєте / обмежуєте кількість місць, які можуть мутувати критичні стани, що вся архітектура обертається навколо, щоб правильно функціонувати.
Окрім необроблених змінних, це зовнішні побічні ефекти, а зовнішні побічні ефекти є джерелом помилок, навіть якщо вони обмежені кількома функціями членів. Якщо навантаження функцій човна може безпосередньо викликати ті кілька функцій членів, то в системі є завантаження функцій судна, що може опосередковано викликати зовнішні побічні ефекти, і це підвищує складність. Якщо в кодовій базі є лише одне місце, яке має доступ до цих функцій-членів і що один шлях виконання не викликається спорадичними подіями всюди, а натомість виконується дуже контрольованим, передбачуваним способом, то це зменшує складність.
Складність держави
Навіть складність стану є досить важливим фактором, який слід враховувати. Просту структуру, широко доступну за абстрактним інтерфейсом, не так складно зіпсувати.
Складну структуру даних графіків, яка представляє основне логічне зображення складної архітектури, досить легко зіпсувати, і таким чином, що навіть не порушує інваріанти графа. Графік у багато разів складніший за просту структуру, і тому стає ще більш важливим у такому випадку зменшити сприйняту складність бази даних, щоб зменшити кількість місць, які мають доступ до такої структури графа, до абсолютного мінімуму, і там, де така стратегія «центрального оновлення», яка перетворює парадигму витягування, щоб уникнути спорадичних, прямі поштовхи до структури даних графіків з усіх куточків справді можуть окупитися.