Learning Alloy: How to Define Objects Generated by Events
If you are software developer, you often implement the object which generated by some other event. But when I represent such objects on Alloy, I always make a mistake. Why? Now I've got the reason. Here it is.
Modeling a "login page".
Generally, authentication in web application uses some session system. In this case, I assume that a session object is generated by "authentication succeeded" event.
Here are the members and their relations.
enum Password {correct, incorrect} some sig UserAccount { password: one correct } sig Session { whose: disj one UserAccount } sig Visitor { signIn: disj lone Session, } sig InputForm { currentVisitor: disj one Visitor, targetUser: one UserAccount, input: targetUser -> one Password } fact { all sess:Session | sess in Visitor.signIn } fact { all vis:Visitor | vis.signIn.whose in currentVisitor.vis.targetUser }
From here, step into the next: defining behavior of LoginForm.
My mistake: "Okay, I will represent a behavior of the LoginForm as 'pred'."
The idea which I came up with first is that I treat a input from users as arguments of function like I used to do in procedural programming. I had sensuously understood that pred is like a function on procedural programming.
pred login[f:InputForm] { f.targetUser.(f.input) = f.targetUser.password implies f.currentVisitor.signIn in Session else f.currentVisitor.signIn = none } check Login { all f:InputForm | !login[f] implies f.targetUser.(f.input) = incorrect && f.currentVisitor.signIn = none }
But this modeling is incorrect. Alloy showed some counter examples. This model allows it to generate a session object despite of the password is incorrect.
result on Evaluator:
I rewrote the pred many times and finally threw away the first perspective.
A different angle
I saw a session object is generated by success of a authentication. So I tried to represent the cause-and-effect relationship between the session object and the authentication in a direct way. It was not a good idea. Because there are no idioms to represent cause-and-effect relationships in Alloy.
Okay, I'll forget the cause-and-effect relationship. Instead of representing it, I wrote variations of the state consisting of valid elements.
fact { all f:InputForm | f.targetUser.(f.input) = f.targetUser.password iff f.currentVisitor.signIn in Session || f.targetUser.(f.input) != f.targetUser.password iff f.currentVisitor.signIn = none }
Oh, I got it despite of the body of constraints was almost same.
I found it must be written as fact what causes what by throwing away the sense of procedural programming and thinking about state.
The Takeaway
All of event processing contains cause-and-effect relationships. But when you will represent it in Alloy, there is no need to define any cause and effect. All you need is thinking about state. And cause-and-effect relationship can be represented by state.
Future work
I represented the rules of authentication and session in web application from a macroscopic viewpoint. So, what makes the rules work? It is every implemented module of the web application. If I represent the specifications of those modules, I must define not only the rules but also events or state transition by using more complicated techniques.
(Special thanks to Lola A.)