This write-up in the Serverless DERN TODO App series won't involve any actual code or further development to our app. So feel free to skip ahead if you're just here for the code.
I just wanted to give a rough road map of where I plan on taking this project, what some of the potential architectural challenges or limitations might be, and also think through some possible solutions.
But first, a meme.
QUESTION: DERN Stack? That just sounds like AWS Amplify but with more steps.
ANSWER: I mean yeah, kind of, but doing things this way gives us a lot more control over each piece of our tech stack. Plus, it's fun way to learn more about Claudia.js, DynamoDB, API Gateway, and all sorts of other AWS tools.
Speaking of other AWS Tools, if you're interested in learning more about AWS Amplify, I'd definitely recommend checking it out. The last that I had played around with it, it was still pretty new in terms of fully-developed features, and in-depth documentation, but there was a lot of cool stuff under the hood like GraphQL, and easy integration with s3 storage.
Turning our attention back to our DERN app, up until now we've been using DynamoDB a little bit wrong. Both the Dynamoose and DynamoDB docs specifically mention that scans are significantly less performant than query. Significant enough that most people recommend avoiding scans altogether unless your're performing ETL operations (and hence would need the entire table) or really know what you're doing.
This is due to the fact that scan iterates over each item in our table, whereas query uses the partition key (aka our primary key) to optimize the query. Query is how DynamoDB offers that single-digit millisecond latency at scale, and Scan slows down the more data (aka items) that your table has. Not good.
What is good, however, is that using scan during development does give us a quick way to get our application up and running, and start to get a sense of what data access patterns our application requires.
If you'll recall back to Part 2, for our Register User feature we scanned the database to check if anyone already had the username we wanted. Essentially, we are enforcing a unique constraint on that attribute, as DynamoDB doesn't have a built-in unique constraint like RDBMS's do.
If the number of users in our application (regardless of active or inactive) started to grow, this would start to slow down the Register and Login functions, because they're searching over the entire database with every scan.
Finding user's by their username is an access pattern we need, so we need a way to efficiently query that information.
One solution this issue, is by using a
Global Secondary Index or GSI. GSI's allow us to create a partition key and a sort key, on a specific attribute in our table (in this case username).
That's merely scratching the surface of GSIs, sort keys, local indexes and all the great features DynamoDB offers. But, we'll be in a much better place once we start to optimize our tables in future parts of this series.
The first (and probably most obvious feature) we'll be implementing is the ability to create Todos. Let's be honest, it's not much of a "Todo" app if it can't even do that.
Fortunately, this is fairly easy once we make the corrections to our DynamoDB tables mentioned above. This feature does however, bring up the interesting concept of "joins", which I put in quotes since joins don't technically exist in DynamoDB.
While joins don't technically exist in DynamoDB, we're still kind of applying the concept of joins to our data, by splitting the Todo items into their own table, then adding a reference back to the owning user's id.
We can then create a GSI on the userId attribute in our Todos table, and very quickly query for every Todo owned by a user.
This "join" concept does open the possibility for some even more interesting features later down the line (which is what I was ultimately trying to get at with this segment) like sharing access to Todos with other users, creating Organizations with multiple users, fine-grained access control and a lot more.
These features are things that I haven't yet had the chance to try and implement, but I think they'll make for some very interesting challenges, and as our app continues to grow and take shape I think we'll be better able to visualize and tackle those challenges.
Overall it's a lot of ideas and things I'd like to try, and hopefully will be able to in this series, time permitting. If only there was some sort of app I could keep track of all these Todos in...