Why I chose Pharo Smalltalk to build my Bot project
The Pitch
So, a friend called, and asked if I knew any developers who would be interested in building an SMS/MMS based bot. While I had never done such a thing, I thought that it couldn't be horribly tough. We discussed the requirements of the project, and I felt like I had a good handle on all the requirements. It was a bit beyond a simple appliction, but all the pieces were there.
I can't go too in depth with the requirements, as the project has launched in beta and is being tested now, but in a general discussion, all the pieces will make sense.
The requirements
The bot requires some non trivial interactions with the user, but in general, it's really moving along states in a state machine. As it progresses state, it persists information, sends requests to outside services, and finally, creates a record of the transactions, and resets, ready to create a new order.
Assembling the technology
I had only used SMS in a very small capacity once in the past, but this was several years ago. I asked a few people in the know, and it turns out that Twilio is what everyone is using for these projects. The cost is a little under a penny per message, so I knew that I would not want to do a whole bunch of testing live (especially automated testing).
It turns out that Twilio presents the SMS transactions as simple web transactions (with cookies/sessions), so designing the solution turned out to be a really simple REST issue.
This left a few things that I needed to round up:
- A state machine
- A simple document based persistence system
- A REST server
- A testing framework that would allow simple calls internally
So, now that we had the SMS issues out of the way, it was time to find the rest of the pieces. I knew that all of the other pieces were available in (for full disclousure, my favorite language) Pharo Smalltalk, except for the state machine. A quick browse of the software catalog revealed several complete state machines. Honestly, I just looked at the first one ( SState ). As with most anything in Smalltalk, I just looked at the tests to see what it was supposed to do.
I also mentioned that I needed a system that could "talk to itself" and run tests all day long without racking up extra SMS fees. Pharo comes with Zinc, a swiss army knife of HTTP tools on which Teapot was written on. The fact that all of these were objects in the Pharo image made writing and testing the app pretty much effortless.
Assemble the pieces
So now that I have all the pieces, the approach became very simple: write a meaningful test suite, and fill in the blanks with real code. Pharo 6.0 now includes the Calypso Browser which makes the entire system much easier to navigate.
So, my testing system goes something like:
Create an HTTP client instance, create an instance of my REST server, and fire a request at it. Test to make sure that I get back what I expect, and that all object interactions have happened successfully.
Having Teapot (the REST server) and ZnClient (the HTTP client) as objects on my server made these iterations that much easier.
In the end, the Bot would sit and wait, and do the following:
- Greet a new user, and clue them on what to do to progress though doing the steps that create a nebulous "Order" object.
- As the user progresses, the bot will steer them in the right direction, and present any choices that need to be made.
- At certain points in the order process, call out to outside services and set up related objects in the order.
- Persist the data in a json store. I ended up using Voyage. I knew nothing of this persistence package, and got up to speed in less than an hour. After spending a great deal of time with it, I would probably use it any time of the day or night.
- Once the order is complete, it assembles some text documents, shuffles them off to several corners of the Internet, and signs off.
- If something happens during the time this order is being created, and the user is pulled away, the HTTP client/server nature of the Twilio interaction maintains the order right where it is, ready to be pickup up at a later date.
It all went together without any hiccups or drama.
So, why did I choose Pharo Smalltalk?
The main reason I chose Pharo is that I could. I am presented with countless problems that could be quickly and cleanly solved with Pharo. The pushback is always "No one else knows Smalltalk." Which, honestly, is a fair pushback. In this case, this was a solo mission. No pushback.
The other reason? Did I mention there wasn't a whole bunch of time to get this running? While I would be absolutely comfortable creating this solution in many other languages/frameworks, there are some nice things that Pharo brings to the table:
- Working on a live set of objects. I work in Rails daily. I love rails, but most of the time, when you're debugging or troubleshooting, I am working as a coroner at a crime scene. With Pharo, it feels more like playing in a sandbox, with all my Tonka trucks. Everything's moving freely, and I can always pick up a truck, see what's inside, where it's going, and what it does. I can even stop the world while I investigate one truck.
- I don't need bullet proof persistence. As long as I save objects when something meaningful happens to them. I can get bullet proof persistence, but it's beyond the current project.
- Teapot is a slam dunk for a REST server. It took just a few minutes to wrap my head around what was going on.
- While I didn't have time to goof around much, I was done with enough time to learn how to effectively use the pharo command line tools to completely ditch my previous image, build a new one from source and use a script to fire it up.
- The refactoring browser makes refactoring painless. We all know what it's like when the pressure is on, and you make a few mistakes (leaving methods around that you really don't need anymore, but will become scary to remove later, etc.) The browser allowed me to refactor quickly and completely, without leaving mysteries buried everywhere.
I could go on and on, but the gist is that, since all of the pieces that I needed were available in one live image where all of my objects were self aware, and aware of each other, developing the project with Pharo felt more like building a solution than formulating my ideas in an editor, pressing go, and hoping for the best.
If I could, I'd work like this every day.