Hacker News new | past | comments | ask | show | jobs | submit login

In the article the author states:

  From this, we get that accounts should certainly behave like state machines.
  And from that, it’s reasonable that other pieces of code ought to be able to
  dynamically inspect an account’s current state, as well as its complete graph
  of states and transitions. That’s as much a part of its public interface as
  any particular method.
I disagree with this a bit. I think that the state transitions are not part of the public interface -- they're an implementation detail of the SM. The public interface of a SM are its states and the events it responds too. It's up to the SM to decide when to do the transitions. (The _author_ of the SM would be very interested in it's transition graph/conditions of course.)

For example, reviewing a bunch of the javascript SM libraries I see a few have the SM define a "transition table". This works for simple SM but makes it difficult to conditionally transition. Perhaps we want our bank account SM to automatically transition to the "hold" state if the balance goes below zero. With a fixed (i.e. as configuration) transition table we can't do this (or we have to fight against the SM library, or the SM library has to be more complicated).

I guess I'm fairly influenced by this book: https://www.amazon.com/Practical-UML-Statecharts-Event-Drive... I found that approach worked very well when I used it to implement a fairly sophisticated UI on an embedded device. It was easy to rationalize about, easy to read in the code, and easy to maintain (add/move states). Seems like something similar in javascript would be nice, except doing things in a javascript way.




Author here.

Conditional transitions, before- and after- actions, state entry conditions/validations, ... There are all sorts of places to go that have been proven fertile for developing robust software.

But you know... In one essay (two if you count its predecessor)... You have to draw the line somewhere. The goal is not to present a unified theory of modelling domain objects with state, nor is it to introduce some code that should be copied and pasted into a production pull request.

The simple goal is to provoke a conversation.

And if the outcome of that conversation for some people is, "We need conditional transitions, so the exact thing articulated in the essay is NoDamnGoodForUs," then I am actually quite satisfied that I've done my job as a blogger.

And if I can address your specific point--which I hope you understand that I agree with, even if it disagrees with that one paragraph--there are multiple approaches, and I think that if we really were modelling bank accounts as domain object with .deposit or .withdraw methods, we could do just as you suggest and bake a conditional transition to a Held state.

But we could also ask if the bank account is responsible for making that decision? In some architectures, we might say that this is burdening it with too much responsibility. I actually mulled this over with the following use case, which I decided to cut from the essay:

Consider a "suspicious deposit," or maybe a "suspicious transaction pattern," like a series of deposits and immediate withdrawals. PayPal is notorious for freezing accounts that violate some set of hidden rules.

Should the .deposit and .withdraw methods know about this and sometimes transition to "held?" One could argue this is not the account's responsibility, especially if some aspects of what makes a transaction suspicious involve things outside of the balance, like how long the customer has been with the institution.

Of course, there could be a line of code that calls a "Transaction Evaluator" thingummy from within the .deposit and .withdraw methods, or even a .validate method that always checks for this kind of thing after any action.

Or... Maybe this is a lot more like an MVC architecture, and the responsibility for checking the transaction falls to the controller, not the account model. So the controller calls .deposit or .withdraw, and the controller checks for suspicious transactions (or for negative balances), and the controller calls .placeHold on the account if necessary (and possibly on ALL accounts for the customer).

I'm not suggesting that this is superior to your suggestion, but it was something I thought about, and in some application architectures, I think what I just described is the way to do it. In others, what you described is the way to do it.

JM2C. Thanks for your comment.


Good points, I pretty much agree with everything you said. "NoDamnGoodForUs" is a little strong, more like "AlmostButThisOneUseCaseNeedsALittleMore" :)

Interestingly, that embedded device I made wound up being MVC without explicitly intending so -- the statecharts were the controllers. The only conditional transitions had to do with code reuse, where a single implementation lead to slightly different transitions depending on how it was configured.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: