Noun.ly
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 [email protected]
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.