Налаштуємо відмовостійкий Redis кластер на Highload fwdays | 13 жовтня
×Закрыть
Solution Architect в EPAM
  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    більшість патернів — це ж про те, як зв’язуватися класи і інтерфейси

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

    Якщо ви боїтеся зв’язків, значить, у вас якісь фундаментальні прогалини в плані ООП.

    Про пониження порядку зв’язків говорять не тільки патерни. В Domain Driven Design є поняття Bounded Context. У ньому ви ізолюєте бізнес моделі, які відносяться до конкретного субдомену. Моделі різних Bounded Context не можуть спілкуватись на пряму. Якщо модель відноситься до декількох Bounded Context одночасно, то спеціалізована копія моделі буде присутня у всіх Bounded Context до яких вона має відношення. Ще є понняття Aggragate. Це група споріднених моделей, які мають тісні зв’язки між собою і які можна сприймати як одну функціональну одиницю. Aggratege має Aggrate Root — тільки до цієї моделі можна звертатись поза межами Aggratege і вона здійснює оркестрацію інших моделей всередині Aggratege.
    Велика кількість зв’язків є джерелом неконтрольованої складності системи. Про це багато писали Мартін Фаулер та Ерік Еванс.
    Як ви думаєте, чому Microservices стали такі популярні? З ними складність деплойменту суттєво виросла, отже мала бути дуже суттєва перевага, щоб компенсувати витрати на складний деплоймент. Цією перевагою було якраз фізичне розділення між компонентами, які не спорідненні.

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    В цьому і є принцип Agile — зробити свою систему гнучкою для змін

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

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

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

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    Так, можливо б дійсно мало сенс

    Поддержал: Sergiy Morenets
  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    Йдеться не тільки про loose coupling, але і зменшення кількості самих залежностей. Декілька способів, як зменшити кількість залежностей

    — Дизайн Патерн Фасад — за Фасадом можна сховати взаємодію декількох компонентів системи, замість того, щоб додавати ці компоненти як залежності до нашої компоненти. Замість залежності від N компонентів ми маємо лише залежність на 1 компоненту — Фасад. Переваги такого підходу: Фасад можна перевикористати; наша компонента стає простішою, її лекше спеціалізувати на виконанні тільки одного обов’язку; якщо компоненти за Фасадом вимагають змін, то зміни зачеплять лише Фасад.

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

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

    — Подібно до Стратегія можна сказати і про Конвеєр.

    — Event Drivent Architecture: є спільна шина даних, через яку компоненти обмінюються повідомленнями. Компоненти не знають про інтерфейси одне одного, вони повністю незалежні. Компоненти лише знають, що в шині даних є повідомлення і на деякі з цих повідомлень (наприклад за певним тагом) їм потрібно реагувати.

    Якщо в loose coupling ви намагаєтесь зробити так, щоб один компонент взаємодіяв з іншим, але не сильно знав про цей компонент і не залежав від його реалізації, то у випадку зменшення кількості залежностей ви намагаєтесь зробити сам компонент простішим, понизити його складністі за рахунок інтеграції або комунікації з меншою кількісті залежностей. Я десь читав, може в тому ж Clean Code, що в конструкторі не бажано мати більше, ніж 3 аргументи (мається на увазі, що у вас IoC і ви не створююєте залежності в коді через new). Тобто десь в такому діапазоні варто тримати порядок залежностей, щоб легко контролювати ріст складності.

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

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

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

    але закриті для змін

    не означає «але для рефакторінгу можна». Ви змінили код і не завжди можете точно спрогнозувати наслідки. Code Review і повторне тестування мають певну ціну.

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    Спасибі. Дуже вичерпна відповідь. Ще раз дякую!

    Поддержал: Oleksii Ozun
  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    1) Зачем? «Хочу» — это не описание проблемы,

    As a User I want to order a Product. Нічого не нагадує? ) Це мабуть чи не найраща форма опису юзер сторей.

    StringBuilder є в .NET і Java. Є такий GoF паттерн білдер. За вашою логікою .NET і Java мають ознаки поганого дизайду.
    В джаве 100500 примеров плохого дизайна и костылей. В дотНете уверен так же.

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

    Еще важнык призанак того что код имеет плохой дизайн:
    Наличие слов Сервис, Менеджер, Хелпер (или названий других паттернов) в названиях классов.

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

    Поддержал: Nazar Iceman
  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    email з додатковими даними про дату створення і чи він провалідований дуже добре підпадає під Value Object в DDD.

    Без сценариев использования невозможно однозначно сказать соблюдаются SOLID принципы или нет

    Погоджуюсь. Контекст зажди має дуже велике значення. Під контекстом я маю на увазі сценарії використання і бізнес домен.

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    Можемо наступного тижня спробувати. Зробимо Draw.io і пошарим доступ? Може є якісь кращі тули для колабораційного дизайну і коментів?

    Поддержал: Dmitry Bugay
  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    Дуже дякую!

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    Спасибі :)

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    Не проблема, як це зробити на колекції. Нехай у вас запит до віддаленого кешу 1 мілісекунда. Прохід по колекції, яка робить енумерейшен 1000 елементів віддаленого кеша займе 1 секунду. Це так трохи довго. Для бази данних можна зробити варіант з Deffered execution docs.microsoft.com/...​#deferred-query-execution. Тоді ви не витягуєте дані з бази рядок за рядком, а ваша колекція робить одну квері і всі обчислення зробить база даних. Але навантажувати базу також не варто. І таке не спрацює для Редіса.
    Мій поінт в тому, що якщо у мене метод кеша повертає об’єкт, то я його можу безпечно використовувати скільки завгодно разів. Якщо у мене метод повертає проміс і мені цей метод треба використовувати n разів, то я буду по можливості такий метод уникати, бо це може принести вже імпакт на 10-100 елементах.

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    Клас з 3-ма методами. 1 щось робить. 2 пусті. Просто, щоб попадати під один інтерфейс. Можливо, але для цього мають бути серйозні аргументи, щоб на це всі погодились.
    Ви згадали про сетери, але нічого не сказали, про гетери. Якщо мій інтерфейс каже get(): Object, я безпечно можу його використати в циклі з 1000000 кроків. Якщо мій інтерфейс мені каже get(): Promise < Object >, то я вже подумаю, чи можу його просто так в циклі використовувати. Знову батчітг. Добре, але дістати 1000000 елементів — не дуже дешево і може їх доведеться десь локально кешувати. Або тримати всі 1000000 під одним ключем. Таке рішення породжує дуже багато питань. Я все ж схиляюсь до думки, що треба розділяти fine grained та coarse grained

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    А можно примеры этих магических шаблонов?

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

    Не очень понятно зачем нада команда. Если есть шаблоны с которыми можно работать однозначно, то можно и автоматизировать процес создания кода.

    така автоматизація буде доступна через років так 50-60, а проект вам треба робити вже

    СОЛИД — это принципы, а не шаблоны. Принципы выше по уровню абстракции. Тот же СРП мы с вами понимаем по разному.

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

    Снова же не понятно как обяснить команде что методы:

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

    А какая у меня роль в проекте?

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

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    ... и коменда потом пишет что попало как попало :)

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

    Тут проблема в том что разработчики должны __понимать__ зачем это надо, а не просто знать.

    Розуміння приходить з часом. Не всі з однаковою швидкістю зрозуміють, «чому цей клас так дивно написаний». Але оскільки ви домовились працювати по цих шаблонах, то всі їх будуть фоловити. Це вас трохи вбереже від серйозних помилок в дизайні коду. Потім на код рев’ю ви будете обговорювати різні ситуації і мало помало розуміння прийде.
    Важливо, щоб всі розуміли, що ми пишемо код по певним шаблонам не тому, що так треба, або мені сказали. А тому, що команда так вирішила спільно і це спільна відповідальність. Коли робите шаблони, то пояснюйте на прикладах, щоб команда якомога глибше могла зрозуміти, чому так і погодитися з цим. Слухайте, що каже команда і рефлексуйте їхні слова у шаблонах. Чим ближче шаблони будуть до вашої команди, тим скоріще прийде розуміння солід.

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    Применимо и к юзеру. :) Вот та самая инкапсыляция в модели ,от который вы избавляетесь перенося все в хелперы, решает эту проблему.

    Я не впевнений, чи правильно вас зрозумів. Ви кажете, що хелпер — це SubscriptionManager і його треба перетворити в модель? Я ніде не писав, що SubscriptionManager — це хелпер. Це частина доменної моделі. Інформацій експерт з підписок. Якби ми робили розділення на DLL, то він би був разом з User і Movie в одній DLL Models. Тобто в одному пакеті. Так, у нього є статичні методи, але він сам не статичний. Його інстанс можна створити.

    Если у вас не возможны разные поведения для одной модели, почему бы не держать это поведение в самой модели?

    Я хочу, щоб subscriptionType був прозорим для всіх, крім менеджера підписок. Щоб тільки ця сутність операвала підписками і при зміні підписок я змінював тільки її, а не 4 класи, як я це описував у попередньому коменті у випадку, коли кожен клас опрацьовує subscriptionType. Оскільки я хочу забезпечити строгу однорідність обробки підписок і контроль їх тільки в менеджері підписок, я можу зробити додаткові констреінти на можливість наслідування.

    Еще важнык призанак того что код имеет плохой дизайн:
    Наличие слов Сервис, Менеджер, Хелпер (или названий других паттернов) в названиях классов.

    StringBuilder є в .NET і Java. Є такий GoF паттерн білдер. За вашою логікою .NET і Java мають ознаки поганого дизайду.
    Я неодноразова бачив рекомендації і з ними дуже погоджуюсь, що додавання патерну до імені — дуже рекомендовано. Просто назва патерну вже вам скаже дуже багато про клас.

    Поддержал: Nazar Iceman
  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    Вот это то о чем я говорил: работаете вы с локальным кешом, появляется необходимость работать с удаленным и ... вы переписываете ваш код на ноые абстракции :)

    Для розподіленого кеша буде інший метод, інший клас та інтерфейс буде іншим. Я сумніваюсь, що в один момент у мене є клас, чи метод для роботи з локаним кешом (кеш в memory space процесу) і я в один момент його переписую, щоб він здіснював віддалений доступ до іншого процесу, або сервера і брав звідти дані. Є fine grained та coarse grained інтерфейси. fine grained ви використовуєте, коли доступаєтесь до адресного простору вашого процесу. Наприклад, ви можете окремо змінити адресу користувача, та окремо його ім’я, тому що доступ до пам’яті процесу швидкий. Якщо ви здійснюєте віддалений доступ, ви витрачаєте додатковий час на міжпроцесорну комунікацію або мережеву комунікацію. Вам вже дорого окремо змінювати адресу користувача і його ім’я, тому ви будете робити це за раз одним викликом. Це coarse grained.

    почему инстансоф это признак плохого дизайна

    instanceof — це відносно перевірки IRemoteDataSource? Вам instanceof не обов’язково використовувати. Краще зробити так f(remoteDataSource: IRemoteDataSource).

    Что такое «командная лента»?

    Command Line, Terminal, cmd, cin, cout, Console.Read, Console.Write

    Лучше пользоваться абстракциями.

    Ніхто про це не сперичається. Я про це пишу в розділі Dependency Inversion цієї статті.

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    Може і YAGNI. Все залежить від складності. Проект на 2 місяці і на 2 розробники не такий самий, як проект на рік і на 10 розробників. Це я дуже умовно прив’язав кількість часу і кількість розробників до складності проекту. SOLID, GRASP, DDD, шаблони проектування — це все про контроль складності. Впроваження цих практик в проект не дається безкоштовно. Я скажу дуже умовно так: якість архітектури — це довгострокова інвестиція. Якщо ви бачите, що через півроку буде складно, ви на початку проекту інвестуєте час і ресурси в розробку аріхтектури. Ви умовно тратите місяць на дизайн, на PoC, на приклади коду, на документування best practicies, на підготовку команди і так далі. Це може бути дуже сумнівна делівері в очах замовника, бо так ви можете не зробити навіть жодного скріна. Зате, якщо правильний фундамент закладений, пройде рік, а ви спокійно і прогнозовано додаєте нові фічі.

    Окрім того, хіба девелопери мають повну картину проекта та планів,

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

    чи думати наперед, що буде з проектом — то робота архітектора та лідів?

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

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    Я до блогу ще не дійшов, щоб почитати і зробити свій висновок, але я переглянув твіти. Автор цього коменту посилається на твіт, у якого тільки 20 лайків. Такий собі проф. В інших твітах дуже багато «мені не подобається», «Мартін <&(&%^$%> людина, а людину не можна відокремлювати від книжки», «Мартін ретвітнув Трампа, shame!». Якусь конструктивну критику важко побачити. Я з цікавості загуглив top software programming books 2020. Майже кожне посилання у видачі згадує або Clean Code, або Clean Coder.
    Програмісти не народжуються з досвідом програмування і дизайном програмного коду. Ми ще не живемо в матриці, де можна всунути в голову флешку і ти вже вмієш писати правильно складний код. Можна вчитися в колег, можна вчитися на Stack Overflow, але чи завжди ми щось хороше звідти почерпнемо? Чи буде у нас цілісна картинка світу, чи тілько того, з чим доводилось працювати? Про Clean Code дуже багато говорять. Звісно не треба сприймати книжку як святий грааль тільки через те, що про неї багато говорять. Але варто її прочитати і зробити для себе якісь висновки. Мабуть вона ж не просто стілки разів була рекомендована. Там описані досить фундаментальні речі. Тренди 2020 аля кубернетіс, серверлес, лябди і т.д. не сильно спасуть від поганого дизайну коду.

  • Чому SOLID — важлива складова мислення програміста. Розбираємося на прикладах з кодом

    І получилось так, що

    subscriptionType === SubscriptionTypes.PREMIUM

    Зустрічається і в класі AccessChecker, і в класі MovieReader. Експертиза того, які є підписки і як з ними потрібно працювати вже є в обох класів. Але раз є в 2-ох, то може бути і в 3-ох. Наприклад, клас який відповідає за User Support. Там ж ми також десь напишемо subscriptionType === SubscriptionTypes.PREMIUM, бо у кого преміум, тому мають відповідати скоріше. Розсилка пошти — subscriptionType === SubscriptionTypes.PREMIUM і тепер лист в пурпурних тонах.
    І все б нічого, до того моменту, коли додаємо ще одному підписку — Standart. Ми додали підписку, а чому це зачіпає усіх: AccessChecker, MovieReader, SupportService, EmailService. Ще раз, додалась ще одна підписка, а ми вже модифікуємо 4 класи. У нас експертиза по підписці розплилась по всій програмі. MovieReader — читає фільми і розуміє типи підписки. SupportService — опрацьовує запити користувачів і розуміє тип підписки. EmailService — відправляє лист і розуміє тип підписки. У нас тут вже у кожного по 2 responsibility.
    Чому я у своєму прикладі зробив AccessManager і тільки у ньому тримав всі subscriptionType === SubscriptionTypes.PREMIUM. Тому що у ньому я можу повністю зусередити всю логіку по роботі з підписками. (AccessManager вже більше не здається мені вдалим іменем, думаю SubscriptionManager було б краще)
    У ньому я можу написати методи аля getSupportPriority, getEmailBaseColor, getSomeOtherSubscriptionDependantValue. Це мій інформаційний експерт по підписках. Він скаже все, починаючи від того, як фільтрувати фільми, до того, в яких кольорах має бути лист. Я додаю Standant Subscription, і те, як фільтрувати тепер фільми я пишу тільки в AccessManager (SubscriptionManager), що зелений колір для листа я пишу тільки в AccessManager, що користувачі з стандартною підпискою мають більший пріоритет, ніж з базовою, я пишу в один єдиний AccessManager, бо це єдиний інформаційний екперт по тому, як поводитися з підписками.

    если методи статические, то вы не сможете их переопределить.

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

    — 4 метода работают с одной сущностью (Movie) и 1 с другой (User) — вот это уже признак нарушения СРП.

    Єдина відповідальність != робота з єдиною сутністю. У сутності Фільм та Користувач є інформація про підписку. Наш клас відповідає за роботу з підписками. Цей клас ж не робить стрімінг відео, чи перевіряє логін і пароль користувача. Він сфокусований на тій частині сутностей, яка має інформацію про підписку.

    Поддержали: vz, Oleg Zinoviev
← Сtrl 123 Ctrl →