Hi friends,
Welcome back to Today Jan Learned (TJL) #8. In this newsletter I share a new lesson every day, so stay tuned for today’s lesson which is about assumptions and coding.
Today’s lesson: check your assumptions!
This sounds obvious, but I’ll show you what can happen if you don’t. If you are interested in the technical details I appended them to the end of the post.
What was I doing?
We are building a Facebook chatbot for a client of ours, a large UK retailer. I was in charge of implementing session IDs for our users, so we can see how they are using our chatbot. What better way to store temporal information like session IDs than in a cache?
Node-cache
As a team we decided to use node-cache for our caching.
Let’s read the documentation on how to store data in our cache and how to retrieve it.
To store a key we use the set() method. How do we retrieve it back?
Alright. Makes sense. To retrieve a key we use get(). Cool. Let’s try something.
Let’s write a dummy function that just pulls our value from the cache. resetAmount should either be undefined (because we haven’t set it yet) or should return the value in the cache.
WHAT?! Why the hell is this a promise?!
Then half a day trying to figure out what the hell was going on. I felt like the first three panels from this comic.
Salvation
After a lot of cursing and banging my head against my keyboard I finally figured out why this resulted in a promise.
Instead of using the library directly, we ran our own version of the cache. In this version we overwrote the default get function making it async. Async functions always return a promise.
This is what it looked like.
Once I realised that, the solution was obvious. I just had to find a way to call the original get function and implemented a get_() method.
Finally, I reached stage 4 of the comic.
Recap
That’s it! Always check our assumptions. I made some assumptions about the cache object that I was calling, which turned out to be wrong.
You can find me on my website janmeppe.com or on Twitter at @janmeppe.
Thank you so much for reading. See you next time!
Previous TJLs
TJL #6: How to remember the difference between margin and padding
TJL #7: According to Jeff Bezos there are two types of failure
BONUS
So here are the technical details of what I was solving.
Problem
For some context, the team that I’m working on is building a Facebook chatbot for a big retailer in the UK. One of the features that I was in charge of was integration with an analytics provider.
This analytics provider requires you to send a thing called a sessionID which is just an identifier for each user session. The problem that I (thought) I was trying to solve was: generate a unique sessionID for every user and reset it when we a get a reset signal (message payload equals GET_STARTED or START_AGAIN).
Bonus: Solution 1
This was my first attempt at a solution:
User comes in
Create sessionID for each user
Check the cache
If sessionID not in the cache (either a new session or an expired on)
return sessionID and save in cache
If sessionID is in the cache
If payload is reset signal
create new sessionID, return, and save in cache
If payload is not reset signal
return sessionID
It’s not important that you follow this solution. What did help me was actually writing it out. Writing out the problem and writing down the solution. I realised that there were some issues with this solution and decided to throw it away
Bonus: Solution 2
My second attempt at a solution which was a lot more elegant than the first one. In this iteration we store the amount of resets in the cache and work from that:
USER comes in (and sends GET_STARTED signal)
Try to retrieve resetAmount from the cache:
If cache is empty
set cache[USER].get_started = 0
return sessionID=hash(USER + cache[USER].get_started)
If cache is not empty
If payload is GET_STARTED
increment cache[USER].get_started
save in cache
return sessionID=hash(USER + cache[USER].get_started)
Final solution
So this is what me and my team came up with. I’d love to hear your feedback!