Всем привет, с вами вновь сумасшедший профессор (хотя совсем не профессор и возможно не совсем сумасшедший). Разберем очередную актуальную тему или не очень актуальную.
Как конечные автоматы заставляют нас бросить решение реальной задачи и уводят в сферические псевдо-математические дебри.
Или можно ли для произвольной задачи программирования найти практический смысл?
Вот тут вот мне попался интересный пример попытки объяснения конечных автоматов как математической модели вычислений (офигеть!):
Понятие о конечных автоматах: руководство разработчика по предсказуемой логике приложений
По моему идеальный пример чтобы разобрать как конечные автоматы (как пример паттерна проектирования) уводят нас в сторону от решения реальных задач программирования и проектирования программируемых функций электронных устройств.
Казалось бы нет ничего проще светофора и это идеальный пример для демонстрации применения конечных автоматов и … того как восхищение конечным автоматом как математической моделью вычислений уводит нас не только от решения реальных задач при проектировании программы, но даже от элементарного понимания этих задач.
Что же такое светофор с инженерной точки зрения?
На самом деле это три лампочки и три ключа для управления — включения-выключения каждой из этих лампочек. Наша вычислительная система (просто процессор) должна управлять состоянием ключей, а ключей у нас три и состояний получается тоже вроде бы три, правда состояния отдельных лампочек вроде бы проще, только ВКЛ и ВЫКЛ. Но это только для домохозяек. Те кто маленько разбираются в электронике (а не только в языках… программирования) знают что состояний вообще говоря больше, так как вы можете включить лампочку, а она не включится! Как это учесть? Это вообще можно учесть? Получается у композиции, даже такой примитивной как лампочка-ключ (выключатель), не два состояния, а вообще говоря четыре:
-
включили лампочку-она горит
-
включили лампочку-она НЕ горит
-
вЫключили лампочку-она не горит
-
вЫключили лампочку-она (все равно!) горит
Как же это вообще программировать? Оказывается это надо не программировать, а понимать как это реализуется схемотехнически! У нас для каждой пары лампочка-ключ должен быть одна управляющая линия (контакт, нога, пин, GPIO, …) И
одна контролирующая-входная-сигнальная линия (контакт, нога, пин, GPIO, …)!
Итого у нас оказывается два бита состояния — один бит задаем мы, второй возвращает нам лампочка. Два бита — это четыре состояния, все сходится.
Вот так вот мы выяснили что у одной управляемой лампочки может быть больше состояний чем у целого светофора! Маленько попозже мы вернемся к этим четырем состояниям для одной лампочки, а пока вернемся к нашему целому светофору.
Вообще-то, когда у светофора зеленый свет вскоре должен переключиться он начинает моргать, скажем три раза. Он должен погаснуть и загореться. У нас была такая красивая стейт машина из трех состояний и куда, а главное как нам отразить это новое состояние моргающий зеленый? Чем нам помогла наша исходная стейт-машина, я что-то, хоть убейте, не вижу! Но есть и другие вопросы, например: «А это вообще состояние?» Давайте попробуем опять разобраться, с инженерной точки зрения, что такое моргающий зеленый? Это значит что зеленая лампочка то горит то гаснет, с инженерной точки зрения это определяется временем периодов, когда она горит и потом НЕ горит. Оказывается что состояние светофора определяется в том числе временем-периодами. Если лампочка определенного цвета горит достаточно долго мы определяем это как состояние соответствующего цвета, это просто красный, желтый, зеленый, в случае светофора.
Если лампочка то включается, то гаснет, у нас на бытовом уровне, есть такие понятия как моргающий зеленый и моргающий желтый, как минимум. Это более сложные состояния и это отражается в названии этих состояний.
Но это все состояния, которыми мы оперируем как потребители функции светофора, и к которым мы привязываемся в бытовых ситуациях связанных с сигналами светофора. Это совершенно не то что нам нужно для понимания или проектирования светофора как технического изделия которое должно обеспечить определенные технические параметры.
С точки зрения управления лампочками светофора, мы должны обеспечить заданные периоды включения и выключения этих лампочек, при чем наверно в разных условиях при разных параметрах трафика разные. Самым простым способом это сделать будет конечно не какая-то абстрактная стейт-машина-конечный автомат. У нас должна быть возможность определить в программе таблицу вида:
красный : 20 секунд
желтый : 5 секунд
зеленый : 17 секунд
ВСЕ выключено : 1 секунда
зеленый : 1 секунда
ВСЕ выключено : 1 секунда
зеленый : 1 секунда
ВСЕ выключено : 1 секунда
зеленый : 1 секунда
КОНЕЦ таблицы!
Код который работает по этой таблице будет примерно такой:
tablRec = Table.firstRec();while(true){setLampsState(tablRec.colors);timer = setTimer(tablRec.period);waitFor(timer); tablRec = nextRec(Table);if(tablRec == 0) tablRec = Table.firstRec();}
Представляете! И это все! Сравните с любой стейт-машиной, которую можно было бы разрабатывать (долго и упорно) вместо этих 10 строчек и одной линейной таблицы, вся логика записана последовательно, все перед глазами! Это называется хорошо локализованная логика.
Как видите стейт-машина нам оказалась не просто не нужна, без нее все выглядит намного проще, а самое главное совершенно понятно как этим управлять! Запишите другие периоды в таблицу если вам надо управлять другим типом трафика! Гораздо проще просто записать состояния в таблицу и просто загружать это состояние по соответствующему событию, а самое главное это абсолютно прозрачно управляется конфигурируется. И если попробовать проанализировать, что же у нас является состоянием в этом коде, то можно придти к мнению что текущим состоянием, которое подлежит загрузке в систему является не только состояние лампочек светофора, состояние включает в себя еще и периоды на которые эти лампочки зажигаются или выключаются! Оказывается состояние системы, даже такой простой как светофор на инженерном языке выражается немного сложнее чем мы привыкли в повседневной жизни. Но при этом очень просто и детерминировано-прозрачно эти состояния можно записать в виде программы и таблицы данных для этой программы. Оказывается, если правильно разделить описание системы на список данных по состояниям этой системы и процедуру, которая позволяет переключать эти состояния по событиям, которые происходят в системе то программа получается намного проще.
Теперь можно вспомнить что у лампочки светофора на самом деле может быть четыре состояния, и что мы можем включить лампочку, а она не загорится. Можно ли учесть это в этом псевдокоде нашей программы? Очень просто! Достаточно заменить простой вызов:
setLampsState(tablRec.colors);
вызовом с условием, например так:
inColors = setLampsState(tablRec.colors) ;if (inColors != tablRec.colors){setError (parseColors(tablRec.colors, inColors ));break;}
И нам придется выйти из цикла и куда же мы попадем?
В самом простом случае нам придется погасить все лампы светофора, но есть еще вариант включить резервное аналоговое управление которое, наверно, должно включать и выключать желтый сигнал светофора.
На самом деле управление светофором гораздо сложнее, так как светофор ни когда не работает в одиночку, если на одном светофоре горит зеленый, на светофоре перпендикулярного направления должен гореть красный сигнал. Это значит контроллер управления должен находиться где то между ними или на каждом из них, но должен надежно принимать сигнал синхронизации от своего перпендикулярного собрата, пешеходного собрата, … Как это сделано на самом деле, я боюсь мы никогда не узнаем, к сожалению, потому что реальные инженерные задачи имеют мало общего с высокохудожественными паттернами проектирования и не пользуются популярностью даже в профессиональных или полупрофессиональных социальных сетях, или вообще, в каких бы то ни было социальных сетях.
Всем удачи и понимания того что вы на самом деле делаете.
ссылка на оригинал статьи https://habr.com/ru/articles/1044244/