Software Developer в MOJAM
  • State Machine: як швидко і зручно організувати код

    100%))

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

  • State Machine: як швидко і зручно організувати код

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

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

  • State Machine: як швидко і зручно організувати код

    Та да, те що конкретний приклад не видуманий, звісно, все змінює))

    Зрозумів, у Вас є травматичний досвід)
    Цей ПТСР, який вселяє в Вас ірраціональну нелюбов до FSM я в коментарях бороти не зможу))

    Можу лише спробувати відповісти Вам Вашим же методом:
    А ось у мене на проекті була задача зробити флоу користувача в якому потрібно було показати послідовно 15 кроків з розгалудженнями в логіці, де кожен наступний крок залежав від попереднього. Хендлити це флагами — значить створювати якісь костилі із масивів зі станів якими пройшов користувач що б відображати йому потрібний.
    Тому я вважаю що що-завгодно (окрім деяких випадків по типу лоадера на кнопці) треба обробляти виключно FSM. В коді взагалі немає бути перевірок, а boolean тип можна вважати антипатерном! В кожному проекті, в будь-якому контексті (за вийнятком рідких виключень), будь-яка дія користувача має бути описана виключно викликом переходу у FSM )

  • State Machine: як швидко і зручно організувати код

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

    Ви постійно апелюєте до абстрактного надскладного прикладу і приходите к неправильному, як на мене, висновку: людині важко тримати в голові FSM на 100500 станів і переходів, а значить FSM це зло. Тобто не підходить до якогось конкретного утрированого прикладу — не підходить (майже) ніде.

    По-перше в настільки складному кейсі з 100500 станів буде 100500 флагів і їх перевірок. Копирсатись в цьому я б ворогу не побажав. Особливо якщо це ще й event-driven система. Ситуація «тут пофіксив, там полізло» буде повторюватись регулярно. І не дай боже якщо доведеться в це все інтегрувати ще якусь додаткову логіку.

    По-друге Ви самі кажите що є методи оптимізації FSM, як, наприклад, группування в Composite state. Що для мене свідчить про протилежне до вашого висновку — для складних систем FSM досить підходящий інструмент.
    (btw, як Ви самі казали — для 10 станів, можна використовувати що завгодно. Отже досить універсальна штука виходить. Не в кожній дірці затичка, але спектр застосувань досить великий)

    По-трете якщо важко візуалізовувати і відсклідковувати всі зв’язки в FSM, тоді чому не зробити документацію, якусь візуалізацію типу цієї: stately.ai/viz, або ж просто намалювати UML діаграму? (btw що простіше візуалізувати: машину станів, чи алгоритм з усіма тими перевірками?)

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

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

  • State Machine: як швидко і зручно організувати код

    Та наче порівнював нутрощі обох підходів... втім я Вашу думку зрозумів)

    Дякую ще раз за корисні посилання, обов’язково ознайомлюсь (з чимось вже ознайомився) і, ймовірно, вони частково підуть в другу частину статті)

  • State Machine: як швидко і зручно організувати код

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

    Ну і знову ж, чому «ніхто не розгледів міць»? Повторюсь, є паттерн GoF State, стейт-машинап як інструмент є в великій варіативності в якості бібліотек під кожну мову програмування, а в деяких напрямках, таких як мобільна розробка, це взагалі розповсюджена практика. Тому розгледіли ще й як)

    Але в світ front-end розробки часто попадають люди «з вулиці», які все вивчають на-ходу. Часто такі люди не знають подібних концепцій бо вони не закладені в інструменти фреймворку. І тому поширюю подібні знання)

  • State Machine: як швидко і зручно організувати код

    А дочірні класи перевизначають лише ті події, котрі вміють обробляти

    Ну, це ж не змінює суть мого твердження :)

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

    Коли дійде до коду, то воно або перетвориться в патерн GoF, або в енум.

    Цікава точка зору... але гадаю тут дається в знаки різниця в мові програмування)
    Що б на TS (ака JS) щось переросло в GoF паттерн.... я б радий був, але тут скоріше декілька глобальних функцій сторять, з такими ж глобальними пропами, і покладудь в папочку «helpers» XDD

    Енум, здається, не схожий на те, що ви описали в статті як стейт машину.

    В мене там в прикладах є буквально єнум з обернутий в геттер\сеттер модуль)) Втім я дав в статті декілька підходів до реалізації в залежності від контексту і завдання... і State як паттерн також згадав... тому частоково згоден)

    Дякую за посилання, обов’язково ознайомлюсь)

  • State Machine: як швидко і зручно організувати код

    Це одне й те ж.

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

    В GoF паттерні є один основний класс. Умовна модель чогось. З якоюсь своєю поведінкою. Частина цієї поведінки делегується об’єкту стану. Об’єкт стану маючи посилання на нашу умовну «модель» має змогу змінювати стани як забажає, але всі класи (!) станів наслідують один інтерфейс. Тобто кожен клас стану має знати про наявні методи і вміти реагувати на їх виклик, навіть якщо йому це не потрібно. Тобто йде залежність інтерфейсу «станів» від потреб «моделі».
    В тей самий час машина станів, як окремий інструмент, немає цієї умовної «моделі». Такий інструмент цілковито концентрує свою увагу на описі автомата і єдине на що він працює — актуальний стан.

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

  • State Machine: як швидко і зручно організувати код

    За запрошення дякую :)

    Та на моєму досвіді цей паттерн навпаки використовують злочинно мало)

    Мабуть різний в нас досвід)

    Підтримав: Denys Poltorak
  • State Machine: як швидко і зручно організувати код

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

    Інший аргумент — погано можна спроектувати будь-яку систему... до прикладу pub-sub систему можна так спаклюжити що додаток в рандомні моменти часу буде крашитись через непрерирвну рекурсію, але ж це не означає що такі системи не мають права на існування, чи не так? Тоді б можна було відмовлятись взагалі від асинхронності, багатопоточності... та навіть роботи з датою XD

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

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

    Підтримав: Valentin Nechayev
  • State Machine: як швидко і зручно організувати код

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

    Але виглядати то буде жахливо. Як відомо «код частіше читають ніж пишуть». Тому в моїх прикладах я робив акцент на інтерфейсі і описовій частині станів і переходів. Що б максимально спростити розуміння того що відбувається. Не впевнений що вдастся досягти такого ж рівня зрозумілості просто на функціях. Да і питання: для чого? Ви часто пишете про пам’ять, то це все буде для того що б декілька байтів ОЗУ користувача зберегти?)

  • State Machine: як швидко і зручно організувати код

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

    Але показати не можу... попаду під НДА)

    Підтримав: Vitaliy Grinchyshyn
  • State Machine: як швидко і зручно організувати код

    В самому кінці статті. Я показав самописну версію стейт-машини як інструмента, але можна також використати і xstate.js.org або подібну. Це найбільше що мені доводилось використовувати.

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

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

    Підтримав: Vitaliy Grinchyshyn
  • State Machine: як швидко і зручно організувати код

    Кожному інструменту — своє місце.

    Якщо у Вас завдання — зверстати кнопку з лоадером, то машину станів 100% городити не потрібно. Вистачить і флага.

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

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

    В статті я також це описую. Подаю різні варіанти застосування)

    Основна думка: возводити в абсолют якесь твердження типу «в js такому інструменту не місце» це дуже радикальна і неправильна думка, уж вибачте мою грубість. Ідеї на яких базується машина автоматів, так і саму машину автоматів, варто і потрібно використовувати, але лише там де це доцільно)

  • State Machine: як швидко і зручно організувати код

    Ну... по-перше це функція «run», що вона робить? Ініціалізує компонент? Зберігає данні? Завантажує данні?)) У кожної функції є власна ціль)
    Ціль цієї функції, на скільки я бачу, об’єднувати в собі функціонал ініціалізації та підвантаження данних. Тобто у однієї функції дві зони відповідальності, що погано з будь-якої точки зору. Згодом ця функція покриється купою перевірок які будуть генерувати баги при роботі з цим компонентом.

    По-друге він записує ті самі стани в

    phase.value

    . Тобто також оперує станами)
    В мене в прикладах такий простий приклад також є) (тільки функції все ж розділені)

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

  • State Machine: як швидко і зручно організувати код

    Ну... про одну функцію це трішки... утрировано, мабуть. У компонента є багато різних екшенів в різні часи його існування. Від ініціалізації до підвантаженні данних на скролі. Це все описувати однією функцією це досить дивно.
    Але пишуть просто. Без зайвих структурних ускладнень. Але потім виходять інтерфейси які ми бачимо на сайтах: то лоадер завісне, то сторінка просто біла і роби що хочеш, то натиснув кнопку а ефекту 0. Таке трапляється коли розробник пише все на «флагах» і в кожному екшені з десяток перевірок. Це важно контролювати, важко підтримувати.
    JS (а тим більше TS) дає інструменти за допомогою яких можна зберігати стани та розбивати великий алгоритм на менші, і використовувати їх в залежності від стану. А якщо це ще й описувати за домопогою зручного інтерфейсу якогось інструменту.... це значно підвищить якість пропрацювання компонентів і покриє всі корнер-кейси )

  • State Machine: як швидко і зручно організувати код

    Дякую дуже за розгорнуту відповідь... чомусь цей приклад відразу мене наштовхнув на щось типу «океей... тобто нам потрібно крутити паттерн State + докручувати щось типу Мосту»)))

    Хмм... а це цікаво... типу 2-3-4 паралельні актуальні стани...

    Гадаю частину проблеми можна вирішити якщо генерувати сценарії попередньо. Маю на увазі якась подія «save» і під неї підбирається сценарій (стретегія) залежно від стану offline/online etc.

    Також думка: що саме описують стани та чи не буде проблемою якщо в одній стейт-машині перевіряти стани іншої... ну що б не пхати все в одну. Бо по-логіці pffline/online це стани мережі, а не умовної сторінки «product».

    Крч є над чим подумати, дяка)

    P.S.
    Стосовно мого прикладу — він певно покриває більше 90% всіх потреб типових проектів на фронтенді )
    Це не виправдання що б не копати глибше... просто я думаю також в продовженні варто буде залишити посилання і на простіші реалізації. Бо оверінженірінг такий самий гріх (якщо не більший) за 10 булеан флагів в компоненті )

  • State Machine: як швидко і зручно організувати код

  • State Machine: як швидко і зручно організувати код

    Ну... певно якщо випити за раз літрів 5 води, то померти можна))

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

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

  • State Machine: як швидко і зручно організувати код

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

    Підтримав: Oleksandr Suvorov
← Сtrl 123 Ctrl →