Comments 19
Для тех кто не знает сообщаю, что FSM это Finite State Machine.
Машина с конечным числом состояний (finite state machine, FSM), или конечный автомат (finite automaton) — это математическая абстракция, используемая при проектировании/реализации алгоритмов.
Если два человека проходят турникет, и второй успел приложить карточку, до того, как первый прошёл, то со второго деньги спишутся, а турникет закроется перед его носом. Потрясающая математическая корректность, нечего сказать.
Корректный код выглядел бы как-то так:
class Turnstile {
@mem active( next = false ) {
return next
}
@mem payments( next = [] as Payment[] ) {
if( !this.active() ) return []
return next
}
@mem opened() {
return this.payments().length > 0
}
@act on() {
this.active( true )
}
@act off() {
this.active( false )
}
@act coin( payment: Payment ) {
this.payments([ ... this.payments(), payment ])
}
@act push() {
this.payments( this.payments().slice( 1 ) )
}
}
Серьёзно? Вы не понимаете, чем библиотека отличается от прикладного кода (это про математическую корректность), не способны абстрагироваться от корректного примера, который по желанию разработчика жрёт жетоны (это про прикладной хендлер перехода :coin
), и вместо этого предлагаете решение, в котором я могу руками поковыряться в payments
и active
?
У меня все время складывается ощущение, что это такой не слишком тонкий троллинг.
Вы бизнес задачу сперва корректно решите, а потом уже разглагольствуйте про математическую корректность своего решения.
Кстати, вот вам простые и понятные тестовые сценарии без криптографии в комментариях:
'no working until activated'() {
const ts = new Turnstile
assert( ts.active(), false )
assert( ts.opened(), false )
ts.coin({ type: 'card' })
assert( ts.active(), false )
assert( ts.opened(), false )
ts.push()
assert( ts.active(), false )
assert( ts.opened(), false )
ts.off()
assert( ts.active(), false )
assert( ts.opened(), false )
},
'one payment'() {
const ts = new Turnstile
ts.on()
assert( ts.active(), true )
ts.coin({ type: 'card' })
assert( ts.opened(), true )
ts.push()
assert( ts.opened(), false )
assert( ts.active(), true )
},
'multiple payments'() {
const ts = new Turnstile
ts.on()
ts.coin({ type: 'card' })
ts.coin({ type: 'card' })
assert( ts.opened(), true )
ts.push()
assert( ts.opened(), true )
ts.push()
assert( ts.opened(), false )
assert( ts.active(), true )
},
'reset payments on deactivation'() {
const ts = new Turnstile
ts.on()
assert( ts.active(), true )
ts.coin({ type: 'card' })
assert( ts.opened(), true )
ts.off()
assert( ts.active(), false )
assert( ts.opened(), false )
ts.on()
assert( ts.active(), false )
assert( ts.opened(), false )
},
Это бессмысленные тестовые сценарии, они тестируют куски кода, которые могут быть в принципе недостижимы и не тестируют ошибочные вызовы. Такие тесты решают только задачу увеличения покрытия кода тестами, и больше — ничего.
Вы бизнес задачу сперва корректно решите […]
Надо было уровень «сложный» поставить, да. Со «средним» я явно погорячился.
Это как раз бизнес-сценарии, формализация требований. Похоже в тестировании вы понимаете ещё меньше, чем в программировании.
Всё так. Ни в чем не понимаю, просто я симпатичный, обходительный и внятно вру на собеседованиях.
Я тут посетил разрекламированный сайт (искал ссылку на гитхаб, не спрашивайте). Скажите, а вот те разработчики, которые понимают в программировании и тестировании — они всегда вот такие суперреактивные сайты делают, или это ваша личная фишка?

Это вам лично не повезло. Судя по скриншоту, сервер синхронизации был не доступен.
Давным давно, один коллега раскопал подход HSM (иерархических машин состояний). Вы их не используете? Там есть формализм StateCharts за авторством David Harel'а.
Давным давно, когда я ещё бодро писал на VHDL, в среде Active-HDL от Aldec, был очень симпатичный графический редактор FSM. Там были и иерархические и .. (не, недетерминированных там не было).
Выглядело это примерно так:

Но по итогу, проще и быстрее было в коде всё описать. Хотя картинки для документации получались прикольные
Коллега написал компилятор из текстового языка StateCharts (по-сути, DSL) в C++. То есть, картинки никто и не думал рисовать — они сделали какой-то экспорт в GraphViz, но это совсем не то.
Я думал, что Вы имеете ввиду работу STATECHARTS: A VISUAL FORMALISM FOR. COMPLEX SYSTEMS https://www.state-machine.com/doc/Harel87.pdf .
В сторону DSL описаний FSM смотрел только на SCXML - достаточно полная штука, но мне не зашло - уж больно коряво всё получается (вероятно не умею готовить). Пришлось навелосипедить своё.
UPD Ещё смотрел на Ragel, но счастье тоже не наступило
Я её и имел ввиду. Они просто сделали текстовое представление этого визуального языка, вот с него и транслировали.
Я сам себе Харел, и я люблю изобретать велосипедики.
Когда я начинал работу над библиотекой, я изучил всё, до чего смог дотянуться (включая, но не ограничиваясь стандартной имплементацией из коробки gen_statem, попытками мастодонтов изнутри коммьюнити, попытками коллег из параллельного мира, и кучей всего другого). Я был активным контрибьютором «иерархических» состояний в лучший руби gem для конечных автоматов (workflow). Разумеется, работы Харела тоже не остались незамеченными.
Вскоре выяснилось, что поверх акторной системы иерархические автоматы не нужны (Саша Юрич тоже пришел к этому выводу, но он пошел дальше, предлагая вообще не использовать абстракций для FSM и жить на голых процессах).
Вся иерархия легко достигается запуском дочернего автомата, который из своего terminate
зовёт следующий ивент в родительском. В библиотеке даже остались рудименты иерархических структур, но я пока не знаю, не депрекейтну ли я их к версии 1.
SCXML — достаточно полная штука
Я буквально годами изучал всякие подходы, и пришел к выводу, что самая полная штука — это диаграммка PlantUML и набор колбэков для резолвинга переходов :)
Нужны ли FSM синхронные вызовы?