If you enjoy reading these exercises then please buy Crista’s book to support her work.
Style 3 – Monolith
As the name suggests, this style is typified by the use of one big blob of code that contains all our application logic!
- No named abstractions (i.e. no methods/functions)
- No, or little, use of libraries
The first constraint meant that we can’t break up the logic into smaller functions, hence why everything is inside one big for loop.
I took the second constraint to mean that we should limit the number of namespaces we open (as is the case in Crista’s version). Which means a Dictionary is out of the question. I could still use a Map but that feels too much of a cheat so I decided to stick with an array of string * int tuple to keep track of the word frequencies.
First we need to load the list of stop words:
Then we read the text line by line and process it in one giant for loop…
One caveat I ran into whilst working on this, is with the behaviour of File.ReadAllLines. It removes the line ending character for each line, which means whilst looking for words in a line we have two cases:
- words in the middle of a line, e.g. “I spoke to Elizabeth today…”
- words at the end of a line, e.g. “…turned around to Elizabeth”
so to make the logic consistent, and remove the special case (case 2) I decide to just add the newline character at the end of the string we need to process.
Other than the above caveat, this code is pretty simple. I decided to deviate from Crista’s implementation in another place – her solution reorders the word_freqs array whenever an existing word count is updated. But I figure it’s likely more efficient to just do it once after the main loop.
sidebar: I have used higher-order functions in a few places, which I’m not sure if they constitute as cheating. However, I don’t consider them violations to the constraints we have set ourselves for this particular exercise.
Code written in this style is generally hard to follow as you need to keep the entire application logic (i.e. the big for loop) in your head whilst trying to understand its behaviour, and we know our brains are not great at holding many items in the active memory (the famous 7 +/- 2 rule).
One thing to note is that, whilst this style was commonplace with low-level languages (and goto was popular back then too), it’s possible to program in this style with high-level languages too (as we’ve done with F# here).
I also find Node.js style callbacks tend to lend themselves to this style of coding too.
You can find all the source code for this exercise here.
I specialise in rapidly transitioning teams to serverless and building production-ready services on AWS.
Are you struggling with serverless or need guidance on best practices? Do you want someone to review your architecture and help you avoid costly mistakes down the line? Whatever the case, I’m here to help.
Check out my new course, Complete Guide to AWS Step Functions. In this course, we’ll cover everything you need to know to use AWS Step Functions service effectively. Including basic concepts, HTTP and event triggers, activities, callbacks, nested workflows, design patterns and best practices.
Here is a complete list of all my posts on serverless and AWS Lambda. In the meantime, here are a few of my most popular blog posts.
- Lambda optimization tip – enable HTTP keep-alive
- You are thinking about serverless costs all wrong
- Many faced threats to Serverless security
- We can do better than percentile latencies
- I’m afraid you’re thinking about AWS Lambda cold starts all wrong
- Yubl’s road to Serverless
- AWS Lambda – should you have few monolithic functions or many single-purposed functions?
- AWS Lambda – compare coldstart time with different languages, memory and code sizes
- Guys, we’re doing pagination wrong