Raph: Hey friends, and welcome to the Deep Stack Podcast.
I'm your host Raph.
Lio: I'm your host, Lio.
Raph: This is the Deep Stack, the Deep Stack Podcast where we
explore everything in modern and not so modern application stacks.
Today we're gonna be breaking down Lio's old project Noun.ly.
So Lio, do you wanna tell us about Noun.ly
Lio: yeah, it's a, it's a fun little project that I started while I was,
uh, working at Microsoft a decade ago.
Raph: Nice.
Lio: in, uh, this was 2000, um, Actually more than a decade ago, like 2011.
And, and Microsoft had entered with Azure there, the cloud space.
And so there was a hackathon to come up with, uh, cloud projects and,
and so Noun.ly is the project that I built in that hackathon and I kept
building on after leaving Microsoft.
Actually it started as it started@stinkybad.com
and I think the URL still
Raph: Excellent name.
Lio: I, well, why it was funny was was a website, or is a website?
It's, it's a URL shortener, but it uses nouns instead of like weird codes.
Right.
So Bitly and a tiny URL were very big back then, or maybe still are.
And I found them frustrating, uh, to share URLs with people, uh, in, in real.
They're unusable, right?
Because you got a code with like eight Q p r capital seven, so it doesn't work.
And so I, I had this idea of using noun only and, uh, announced using nouns.
And because it was nouns, I took a domain name that was like an adjective.
So everything was kind of funny.
I ended up with stinky back chair, stinky horse, stinky bat, you know, uh, unknown.
Raph: Yeah.
Lio: Um, So I, I build that, uh, and.
I build them on, uh, a very early Azure, right, the 2011 kind of Azure.
Interestingly, Azure was one of the first that provided platform as a service before
they even had infrastructure at a service.
You, you didn't even have VMs yet.
And so it ended up being like a Azure website, I think it was called.
It was running on
iis.
Raph: remember that, like that term.
Lio: It was kind of fun.
I thought.
Uh, the experience was cool.
You, uh, you had the command line, you started a new Azure website project
and there was like a dash dash GI that would give you, uh, like a get in edited
folder and as well as a, a remote repo.
And then any get push that you did, uh, they had their.
Builder, uh, that I, I forgot what it's called.
Like something with a K that would look at your files and then figure out whether
it was like a Python or a, uh, C sharp.
I think the initial, the first version I, I built was C Sharp, and then it
would build it and, and push it and host it and, and that experience to go from,
um, you know, using the command line to get a empty folder and then get, commit,
get, push, and it was up and running.
Uh, I think everybody was still catching up to, to that behavior,
uh, to that ex deaf experience.
So I, I really liked it.
course, it was, it was very microsofty, you know, like, it was like C sharp,
uh, only I s no, no Linux containers.
Uh, so, um, so, so that was the, the first version of stinky bad.
But then when I, when I left Microsoft, that's when I started using.
Like more open source tools.
So I, I rewrote the app and, uh, D Lang like that, that was like the, the, the
thing, the language that.
I used for my hobby, hobby projects.
Um, and so I, I, I, I, I wanted to use that.
Uh, I started using, uh, instead of, of course d if you push decodes
to the, to the Azure websites, I didn't know what to do with it.
So I had to build my own, uh, But then by that time, Azure websites had docker
support, so you could actually, uh, it, it could, uh, host containers as well as raw,
Raph: What year was that?
Lio: Sorry,
Raph: What year was that?
That they started to support Docker containers.
Lio: uh, I don't know, maybe, maybe 16 or something.
2016.
Raph: Okay.
Yeah.
Lio: I don't remember, but that was some much later.
Raph: okay.
Yeah, I was, I was surprised.
I was like, wait, that the, the timeline, I, I, I thought it was just
like maybe a, a few years after, and I was like, that's, that's impressive of
the, or that, that early on the, the,
container train.
Lio: that particular feature with Docker containers got renamed a bunch of times.
Uh uh.
Now it's, even now I think it's called.
Uh, Azure website for Docker or something.
I, I, I don't, I don't keep up with the naming,
Raph: Yeah.
Lio: yeah, so, so that the whole stack from Stinky Bad has been
completely rewritten around that time.
Like maybe five, six, um, Or two, 2016 ish.
So that's when I also got the domain name, noun.
Noun.
Actually, that was a little earlier, I think maybe 2015, to be
honest, because people liked it.
You know, people started using it, uh, stinky bad.
I actually got, I, I got like a bunch of emails from users that said, Hey,
I, I want to use, Uh, stinky on my, uh, presentation, but I, I cannot
show stinky bad.com on, on at work, you know, so is there a way I can
have a, a different domain name?
Raph: Yeah.
Lio: Um, and actually it, it was, presentations was the perfect use case
because yeah, URLs in a presentation are pretty much pointless because people can't
get it and they'll have to wait until you mail if, if you mail them the deck.
Raph: Yeah.
Lio: And so around that same time, I got the domain noun.ly as well as Noun.ly.com.
And I, I added QR code, code generator so that on your slide you could put both
the noun as well as the, the QR code, uh, which because the nouns are short, the
QR code kind of had a, uh, didn't require very high resolution, right, because you
didn't have a lot of bits to put in there.
Raph: Yeah.
Lio: at that time, the new, well now old, but the new
stack, uh, was, uh, built right?
So the backend was rewritten in D Lang using, uh, these vid, uh, web framework,
which was back then was state of the art.
It was like asynchronous, you know, all the, all the, the
good stuff, uh, co routine.
All the stuff that, you know, uh, the, the new modern web frameworks and no
js, python, uh, rust, they, they all use that same kind of architecture right now.
Fived is very dated.
Uh, um, but yeah, so that's what it's using now.
So if you go to now, that's what it's using, it's using
the fived at the backend.
Uh, it, it's not using any, any front end framework.
Everything is.
Uh, pretty raw, uh, handwritten, uh, Java script and css.
I, I think it, it was using, what's the Twitter CSS framework called again?
Raph: Oh, bootstrap.
Lio: I guess so.
Yeah, bootstrap.
I think it was using Bootstrap.
I kind of forgot cause I haven't touched, I haven't touched it in a long time.
Raph: You know what I love, so I just went to the website.
I like that you have a little beta, beta banner on
the top left.
Lio: beta I got from Google, so I'm, that's, that's like a disclaimer
Raph: It's a, it's a 12 year old beta.
Lio: of beta.
Raph: Yep.
Lio: so the, the, so talk about deep stack, right?
So front end is, uh, handwritten html, uh, with, uh, cs.
Raph: That's, that's, uh, called that artisanal HTML
Lio: Oh yeah, exactly.
Exactly.
Um, which to be honest, for that kind of single page app, I really think I don't
need a, i, I don't need a framework.
Right.
Raph: I agree.
Lio: The, the jQuery's biggest feature, the dollar sign I just
built as a, you know, as a one-liner.
And, and so to reference, uh, elements, you, you, I, I use that,
uh, that same kind of, uh, style.
Um, uh, I al and, and so.
There's only one rest call basically there you can, uh, create a noun
and you can dereference a noun.
So that's, that's pretty much it.
Uh, I also built, uh, two, uh, two native apps for iOS and Android
Raph: Oh,
Lio: in similar fashion.
I, I, I didn't use any framework for those.
Raph: are they still up on the app stores?
Lio: They should be there,
Raph: All right, cool.
Lio: honestly, I, I, I need to revamp them.
I, I wonder if they.
Still work because as the
Raph: Oh,
Lio: of times the, the operating system, um, get revamped and, and if
you do not recompile and re-upload your app, they'll, they'll just don't
make it show up on the newer devices.
And so it's possible that, uh, it's not
Raph: longer listed.
Lio: It could be.
Yeah.
Raph: Yeah.
Yeah.
It's gone.
Lio: so I, I didn't use a framework for the native.
Raph: Yep.
Lio: Partly because that, that is kind of how I learn things.
And same, same as, you know, not using jQuery and using JavaScript and, and
writing CSS and html, if you don't know the pain points of doing that, I, I,
I don't think you'll, you'll know the value that frameworks provide or which
framework even to go for because you, you, you, you want to address that pain and
if maybe the pain isn't even there, like in the case of of of front end for noun.
Honestly, there is no pain in using JavaScript and XML http.
There was no fetch api, right, so the XML http request to talk to a backend.
Honestly, it's, it's, it's not a big deal.
Raph: Yeah.
Lio: Incidentally, my team and Microsoft was in charge of XML H
G T P request, so I did not have a problem with XML H G T P request.
Raph: Yep.
Yep.
Lio: One of my first tasks joining that team was actually, uh, xml, H E T
p request had been added to Microsoft Internet Explorer by the office team.
I became a standard afterwards, and then people started complaining
that that Microsoft browser didn't support the standard.
So my first task was to change XML H G T P request and Internet
Explorer to follow the standard.
So that was kind of a fun task.
So for me to use XML, H G T P request was, was not a big issue.
If you know the, the quirks, it's, it's a, it was never intended as,
As a beautiful API for external use.
It just became the begin beginning of Ajax, right?
Um, um, so that was the front end.
And again, doing that handwritten full circle loop really makes you appreciate.
When to use a framework, what framework you to use, which parts
to use it for instead of blindly using every feature available.
Right.
Um, and so the same for, for the native apps.
This is, again, a, a, a one page application.
Um, I, I didn't feel the
need to
use, like,
Raph: and Java.
Lio: so I think I, I used Kotlin on Android and I used, uh, well Swift on iOS.
Raph: Yeah.
Lio: And, and, and here's my biggest takeaway from this project was that
once you design your model view, uh, view model, right, your, your model
view controller, the, the new model view, view model, M V V M architecture,
once you design that architecture, uh, it's the same for both apps.
And, and so defining what your model looks like, what your model view looks like.
What your views look like.
That is 80% of the job.
Then translating that into, translating that twice, once into
Swift and once into, into Kotlin,
Raph: Not a
Lio: it's really negligible.
Like it's, it's like, um, like the, I I always say like, in our profession,
typing is the least of my worry.
You know, like designing something like good architecture and, and a
stable, uh, resilient architecture.
That, that is the hard part.
Right.
So,
Raph: so what you're saying is chat, G P T is not taking our jobs just yet.
Lio: Well, un unless they get into, in, into the designing
Raph: Yeah.
Yeah.
Lio: Yeah.
So typing the same architecture twice, once in, in Kotlin, one's in Swift.
No problem at all.
In fact, both apps are open source.
So, and, and if you look at them, it's kind of funny, I, all the files
on the folders have the same name.
Just one is written for iOS and the other one is, is written in, uh, in Kotlin.
And then there, there's, of course, there's 20% is, uh, different
in the operating system, right?
Yeah.
You, once you get to storage, for example, they all have their, their own
way of doing, uh, local preferences, local store, uh, stuff like that.
Their, their fetch api, you know, the HTP API is a little different, but
honestly, you, you write small, thin abstractions and then the rest of your
app looks the same and it's beautiful because you end up at the same box in.
And you fix them in both as opposed to if you used to, uh, web frameworks,
if you use a iOS framework or, or like one of those phone gap things.
I, I'm not a fan.
You get their own, they have their own quirks and now you're one step further
away from the, the source of the problem.
And I find debugging a higher level problem, always harder
than debugging a low level one.
Raph: Yeah, I can see that.
I will in a, in a future episode, perhaps I will push back on
a little bit of that, but,
Lio: Yeah, I, I, I know exactly when to appreciate those, uh, frameworks
after having, you know, doing the, the, the manual work.
Raph: Yep.
Lio: Um, so we, we are going through the stack, right?
We, we have, uh, art Artisan Know, H M l, JavaScript, css.
Uh, Uh, native apps, uh, Kotlin and, and Swift.
Um, our, our REST api, very straightforward rest API
with just crud, crud, nouns.
Basically, you know, you can post, you get a noun, you can delete that noun, you
can get it to the reference, the noun.
Raph: What, uh, what database are you using?
Lio: Um, yeah, okay.
That is still Azure table actually.
So I, I wanted to, in that new world of cloud, uh, they had introduced Azure.
Uh, Azure Blob Store, Azure Table Store, and uh, there was a third one.
The, the very Early Storage Services or Azure queue.
Yeah, those were the first three high level storage services that Azure
provided back in the, the early tents.
And so I, I used Azure Table,
Raph: Okay.
Lio: is kind of like a precursor to Dynamo, right?
Dyna might have been around actually because a Azure was
really catching up on, on a Amazon in the early, early cloud years.
But Azure Table was perfect because they have this key value kind of
behavior and and the key is the nouns.
Raph: Wait, but so you had this, you had this back in 2011.
Lio: right?
Yep.
Raph: Okay.
Lio: So I was using Azure Table.
I, I'm still using Azure Table as a key value store.
Um, so as stinky, bad, and now only got more popular, I, I ran out of nouns.
And so the nouns became limited in time.
So after 24 hours, your link might no longer be valid because
it, there's like a garbage, lazy garbage collection that's happening.
And, but you can get, and, and as nouns are taken, You end up with more nouns.
So instead of stinky bad chair, you would end up with stinky bad horse chair, right?
And, and still was fun.
Oftentimes you end up with very fun combinations.
Raph: Yeah.
Lio: Um, and, and key value store was perfect, right?
You have a, you have a key and, and the value becomes the URL that is being de
referenced, but plus a bunch of metadata.
Uh, interestingly, as soon as these, the site was up and running, I, I
got a shitload of spam because all of these bots, anytime they see a
added box, they just put links in it.
Right?
You get like a lot of spam.
So, so in, in the backend, I, I, I think 60% of the backend code is anti.
So I, I do like the, the, i I do like a honeypot in the HTML form, right?
So that means like a bogus field with like a, a, a display non CSS class
that bots, if bots put something in there, then you know, it's a bot.
I, I reference, uh, two external honeypots.
So there is the honeypot project actually, that, that was cloud flare.
First project, uh, cloud flares.
Uh, before it was called CloudFlare, there was honeypot, uh, project.org,
I think, uh, where people would, uh, volunteer to put a piece of form on
their website that cloud honeypot.
So the early CloudFlare would, uh, use to detect, um, bots and, and keep a, a.
A blacklist of these, uh, of these bots, of these IP addresses
that these bots were using.
And so that was called a rbl, I think.
Uh, RBL stood for, um, request block list or something.
I forgot what the R stood for.
Raph: Yeah.
Lio: Um, And so, and, and there's another one, uh, spam house.org.
So I, these, both of these have public RBLs and these RBLs, you can
query them using DNS is actually kind of funny, an API designed on dns.
So to, to query these databases, you would craft a, uh, DNS request.
So you would ask, what is the IP for, you know, for this domain.
But the domain was not, not a real domain, right?
So basically the.
You the, the, the IP address that you want to query,
Raph: Mm-hmm.
Lio: uh, you, you pre-end it to their, uh, RBL domain.
So I think it was like rbl dot spam house.org and rbl dot
uh, uh, project honeypot.org.
And so you, you repent the IP address and then it would return an IP address.
If it says not found, like, you know, an X domain, uh, IP, not,
uh, or domain address not found, then, then it was not in the list.
If it returns an IP address, then that IP address instead
of, it's not a real IP address.
In fact, it would always be local host, always do 1 27 0 0
x, and then the last digit, uh, of the IP address actually tells.
Some metadata about, you know, why it was blocked.
Raph: Okay.
I feel like I vaguely remember coming across this many
Lio: Yeah, it's kind funny.
Raph: Yeah.
Lio: Uh, and so, and, and so I, I did that, I did, uh, the form
honeypot two, uh, RBL queries.
And then there's a little bit of, um, because my now only doesn't have a login,
so it doesn't have an idea of a session and I didn't want to get into that.
Um, that, that is like a rabbit hole.
I didn't wanna get,
Raph: Yeah.
Lio: so to prevent spam, I did, um, kind of proof of work.
So, so the, the no only JavaScript when you post the JavaScript
calculates a bunch of hashes with, with, uh, with the current time.
Uh, and the, and the salt that keeps changing until that hash
ends in a number, a bunch of zeros.
It's kind of like how, how the early, well, so how, how Bitcoin,
but also the early, um, cash hash.
So cash hash was an anti-spam, pre pret Bitcoin, right?
Uh, uh, anti-spam mechanism.
And so inspired by cash.
The, the website, when you do a post on ly form it, it does a bunch of
these iterations until it has a hash with a bunch of zeros, and then it's
very quickly to test backend, whether there's zeros in the, in the hash.
So using these, that's why I mean, 60% is anti-spam in, in the, in
the backend because of the actual key value is, is very simple.
Raph: Wild.
Lio: Uh, Um, yeah, so, uh, we, the storage is just key value store.
It can, honestly, it can be any key value store because I'm
not using any, any fanciness.
The only fancy feature, it's not fancy anymore because
now every store provides it.
The on the only fanciness is the optimistic locking, right?
So if you have multiple.
Uh, customers going to the website, multiple users going to the
website, and they, because of the, the algorithm is deterministic
when it returns a noun for a url,
Raph: Mm-hmm.
Lio: um, it's not random.
Raph: Okay.
Lio: And so it's there, there's a risk that both would get the same noun.
And so how do you prevent this kind of concurrency?
And I'm using optimistic locking.
Optimistic locking boils down to every record keeping track of aversion
and when the record is updated.
So for in, in the noun only case, the key is the, the noun or nouns that you.
That you're about to get right?
So when a record gets updated, it has to provide the version that it's
of the record that it's updating.
So if somebody wins the race, Then your version would no longer match.
And, uh, and there's an iteration loop a second time where it picks
another noun and, and it would try again until it, your browser wins the
race and, and you get the nouns, uh, displayed in, in your browser window.
So optimistic locking is how you avoid like locking database tables, locking
records, all this kind of locking, which.
If you do not unlock, you know, you, you can get into a deadlock, you can
get into, uh, a lock that that has to expire before somebody can do something.
So, locking to me is something to be avoided.
Raph: Yeah,
Lio: And, and now a lot of these key value stores, right, Redis,
uh, NATS Dynamo, they all have this optimistic locking, uh, as a pattern.
Raph: Yep.
Lio: Um, so, and then, then the last thing I was around the same
time, I, I got to know, uh, Nick's.
So the next package manager, I've been using macros, but with the NS
package manager and, and the NS package manager and can build Docker images.
And it's kind of cool because if you use Nix to build a Docker
image, the Docker image will g.
only stuff that is referenceable, right?
The, the, the way Nix works, everything has a hash based on the,
the sources that were used to generate.
And so when you start with your binary, which is my noun,
only the language binary,
Raph: Yep.
Lio: basically scans that binary.
And if there's a hash to TC data at dc, data will be pulled
in if there's a hash to gyps.
Which the, there probably isn't because it was using D Lang, but
it would pull that in, right?
So everything because of this, this, this, uh, tree of hashing, uh, It would
only pull in stuff that are, is actively being referenced by that, uh, that binary,
the, the, the final, the final binary.
So you, you end up with very small, uh, docker images from scratch, basically
the, the equivalent, uh, as writing your own from scratch and copying only
the, the, the stuff that you would need.
Raph: Yep.
Lio: So that was kind of cool.
Uh, not only really let me experiment with all these utility.
Yeah, it, it's, it's, it's an old website.
Uh, the, the apps might have been delisted, so it needs some
love and I probably need to spend some, some time to, to revamp it.
Raph: so, so how are you gonna do that?
Lio: That's a good question.
Like I probably wouldn't use D Lang anymore.
Raph: No.
Lio: not, not because of the language.
I think the language is still being actively developed, getting new features.
Dealing is, is not well known, but it, it's, it.
A lot of the features make it into the other languages.
Like Rust has, has features that, that started in D Lang c plus plus.
The new c plus plus has features that started in D Lang.
So I, I really feel it's, it's kind of fun having followed that language and
the design and the discussions behind the features that are being added.
Raph: Yeah.
Lio: It, it taught me a lot.
It's just that 5g, the web framework is, is really old right
now.
Raph: Yeah, their, uh,
Lio: I, and I'm.
Raph: a little, a little dated.
Lio: it's very dated.
I don't think there's a new modern alternative, so I would probably
use like a go or type script
Raph: Hey, the latest, latest commit to Vibe D was eight hours ago.
So
Lio: Well,
Raph: maintained.
I don't know how actively.
Lio: Yeah.
I, I, I think it is being maintained.
Yeah.
But I wonder how much of those are just.
Fixing breakage, uh, happening by the compiler.
The compiler features are
being added.
Raph: it, it still hasn't gotten to a version one.
It's still at 0.9 0.6.
Lio: There you go.
Yeah.
Not great.
Raph: Yeah.
Lio: So, uh, I wouldn't use Azure Table probably as another
one of those things that, that I don't think it got any features.
In fact, I, I.
Considering the size of my data set, it's not big, right?
Um, because the nouns expire after 24 hours.
The number of keys that I have to keep in memory is pretty constant.
Doesn't change much.
It's not very big.
I could probably keep the whole thing in memory.
Uh, of course, I cannot use local memory, right as I have multiple
instances of my backend up and running.
They, they need, uh, like a consistent memory store.
A consistent store,
Raph: Yep.
Lio: but I could probably do it in Redis or Nats.
So I would use either one of those two.
Perfect.
In-memory databases, I don't need persistence.
Like the, what is the worst that can happen if I, if I lose all
my instances and, and all the keys and the values are gone,
Raph: Mm-hmm.
Lio: like only the active nouns would've been affected and which are not that many.
So that's probably the better architecture as opposed to doing like a round.
To a persistent database like Azure Table, right?
It's a little bit overkill.
Um,
Raph: Would you, you wouldn't, you wouldn't switch to a, to a, a full,
full blown front end framework with
Lio: I could be tempted.
No, I I actually, I would be tempted too.
Raph: Yeah.
What would be the value there?
Lio: so,
Raph: for fun?
Or would there be some value?
Lio: yeah, maybe, maybe just for fun to
Raph: fun is valuable.
Lio: To, to me, a project like not only is perfect, uh, ground
to, to experiments with, right?
Like, uh, what would it look like using View, what would it look like using React?
You know, how and how do you compare, like how do you quantify the costs
and, and, and, and, uh, the value of these, uh, of these frameworks.
Raph: Yeah,
Lio: So the one that.
Um, the one that I personally haven't used yet, but would love to
try and maybe now only would be a occasion to try it, it's felt kit.
So maybe I, I, I would try that for now.
Only 2.0.
Get it out Data.
Raph: Yeah.
Finally remove that, that little flag.
Lio: Yeah.
So yeah, it's a fun little project.
Um, I still use it in my presentations.
Uh, there is, it has some usage.
I mean, I'm not marketing it.
Um, you know, if people like it, let me know.
If people think if, if it doesn't work, let me know.
If, uh, there's a feature you would like to see, let me know.
It's quite, quite fun for me to e.
Raph: That's noun ly, right?
Noun ly awesome.
Lio: So a little, uh, Easter egg.
Raph: Yeah.
Lio: Uh, if you go to noun mom, m o m, it's goes to a five video that one of my
friends got me when I launched Stinky Bad.
And so it still references stinky bad, but it's hilarious.
Like I, maybe I should do a ask the same guy to do a new one.
So, uh,
Raph: Oops, that's my camera deciding.
It has been half an hour.
Alrighty.
Thanks for listening.
We are building projects that should make it a lot easier for developers
to build projects like Noun.ly.
Lio: Yeah, check, check out Defang.io, which is making building web apps
cheaper, easier, and more resilient.
Raph: And check out the Chewy Stack at gochewy.io.
A deep stack framework that helps developers build better products faster.
That's Defang defang.io.
And gochewy.io.
gochewy.io.
Thanks again for listening, and we'll see you on the next episode.