PETE HODGSON: OK. So, thanks for coming.
Today I'm talking about Rails as an SOA client.
So, in the beginning, there was a Rails application.
And in the beginning, most of these Rails
applications
were pretty straight-forward.
Pretty simple things. They were normally
just talking to a single database.
And this is how most of our Rails applications
start.
They're green fields, and we're talking to
a single database.
Quite often, we, or pretty soon, particularly
now days,
we start talking to services. These might
be external
services like Twillo or Twitter, or they might
be
internal services that we're using as part
of doing
our job in a, in a more enterprise-y situation.
And as time has gone on, we've noticed, or
I've noticed, that our Rails applications
are depending more
and more on services. So, I think there's
kind
of two big forces in play here. Force number
one is, as time has grown and as Rails
has matured and our community's matured, our
Rails applications
have been kind of growing into these big monoliths,
mono Rails, these big, bloated applications,
and now there's
this kind of movement, quite a widespread
movement, meant
to break up our large, monolithic Rails apps
into,
into services and, obviously, something needs
to talk to
those services. And normally that is a Rails
app
fronting those services.
The second big force is, Rails applications,
which I
think started off mainly being used by start
ups,
have moved more and more into enterprise-y
places where
there are a lot, lot, lot of services. And
in these enterprise contexts, Rails apps are
normally talking
to a lot of services to get their job
done.
And this is, even goes to the extreme where
we have Rails app that don't actually have
any
local data storage at all, are not doing any
kind of persistence. All they're doing is,
is interacting
with services to do all of their work.
So, I, I built an application like this fairly
recently, and I'm gonna talk to you guys about
what we built, some of the techniques we used
to be successful in building these kind of
services
only application. Yup. So that's, that's gonna
be the
talk today.
My name is Pete. I work for this consulting
company called ThoughtWorks. So, we work with
clients to
help them build software and get better at
building
software. I've been with ThoughtWorks for
about four years.
As you can tell from my accent, I'm in
the San Francisco office.
I really am in the San Francisco office. And
I, I, in my time in ThoughtWorks, I've done
a lot of different things. I've done a fair
amount of Ruby and Rails, but I've also done
some Scala, some JavaScript, some, some iOS.
And I've
also worked in a lot of different contexts,
organizations.
So I've worked in really small start ups all
the way through to huge, lumbering banks.
And, one of the things that I love about
ThoughtWorks is I get to move in all these
different places. And one of the things that
I
think ThoughtWorks brings to its clients is
ideas from
one place applied in a different place. So,
what
we find ourselves doing a lot is taking ideas
from the Rails community and introducing them
to the
Scala community. Or taking ideas from mobile
applications and
introducing them to our client-side JavaScript
applications.
And, indeed, taking ideas from start ups and
taking
them to the enterprise. And so, shockingly
enough, vice
versa. So, that's part of what I'm gonna be
talking about today is, there's this subtext
of kind
of taking ideas from other communities that
are successful
and bringing them into the Rails community.
And so this is gonna be a kind of
a talk in two parts. The first part I'm
gonna talk about some kind of more hand wave-y,
how do we live in this ecosystem environment.
And
some tools and techniques that can help with
that,
particularly in the context of Rails. And
then I'm
gonna dive into some more kind of nitty gritty
kind of, how do we actually build these things
into our Rails applications?
So, first off. Co-dependence versus independence.
So, as I
said, I worked for a client. We were building
a large, we were building, actually, a pretty
small
Rails application in front of a very large
set
of services. We were building an online store
for,
for a large book retailer. They were going
to
a new market, and they didn't want to have
to keep working in Java. So they were taking
this as an opportunity to build a green-filled
Rails
app for a new market, which was still gonna
be using all of their existing services, which
were
implemented in a variety of languages.
So this is what the home page of this
application kind of looked like. There was
this kind
of list of all the products and prices and
descriptions and all that kind of stuff. And
then
across the top we had these kind of deals
of the day.
And the way that this worked was, was interesting
or, I, I suppose is, is interesting if you
haven't worked in like a large enterprise
like this.
But the information to power this page was
coming
from a lot of different places. And our Rails
app was really just responsible for stitching
that information
together. So, we had the product service that
was
kind of serving up product catalog data, and
then
we had the deals service that was kind of
telling us what the deals of the day were.
And, as I said, the Rails app was just
kind of there to kind of, go over here
and get some information. Go over here and
get
some information, and then kind of plug it
all
together. So when you're building an app like
this,
you get this interesting phenomenon, where
this app, on
its own, really can't do much at all. In
fact, it can't do anything. We, there wasn't,
there
was probably not a single page of this app
that would render if those services weren't
there.
So, what, this is what I mean by co-dependence.
This application was incredibly co-dependent
on the ecosystem of
services that it lived inside of. But ideally
we
don't want to be co-dependent, because we
want to
be able to run this thing in isolation, to
test it in isolation, to debug it in isolation.
So, we don't want to have to stand up
the entire enterprise on our laptops just
in order
to, to run this thing when we're, when we're
on a train or in a plane. So, we
want independence, but we're in a situation
of co-dependence.
And this gets even more interesting when you
start
thinking about it in terms of teams. So, in
our case, we had our team, let's call us
the red team. We're building the Rails application.
But
we weren't building any of these services.
The deals
services might have been maintained by the
green team
and the blue team, of course, were working
on
the product service.
And these teams were teams we sometimes, we
didn't
even know where they, where they were. We
had
vague ways of getting in contact with them,
but
we, we didn't have a very good relationship
with
them. And this leads to lots of interesting
side-effects.
So one thing that you might note here is
the shape of the teams. Lines up pretty closely
with the shape of the services. So this gets
to this thing called Conway's Law. Don't tell
DHH
that I'm talking about laws.
Conway's Law, coined in the 60s, says that
the
communication patterns of a software system
tend to mirror
the communication patterns of the people who
build that
system. How many people have heard of Conway's
Law,
by the way?
So, I'm trying to avoid calling it a law
but I'm not going to be able to do
that. I think Conway's Law is the most important
law for us to understand as software engineers.
Oh,
I said. As people. As software writers. Sorry.
Conway's Law says that how people work together
effects
system architecture. And, and the flip-side.
System architecture effects
how people work together. And, this isn't
kind of
a, a possible outcome. This is reality. This
is
empirically shown for fifty years, sixty years
almost. This
does happen. This is true.
So you can't, like, decide you don't want
it
to happen. But what you can do is you
can either wield Conway's Law to your advantage,
go
with the grain and, and use it to your
advantage, or you can kind of yield to Conway's
Law and have it beat you up.
So I'm gonna talk a little bit today about
how we wielded Conway's Law to our advantage
rather
than have it beat us up.
So, here's our three teams. One of the most
fun aspects of, of working in a system that
has more than one team is, is when you
find a bug. So let's say we've got our
deal, deals of the day section, and we've
noticed
that the prices are missing in some of the
deals section when we run the application.
So now
we start to play this game, it's called Who's
Bug is it Anyway?
Hands up if you've played this game. Awesome.
OK.
I wasn't sure if that was a cultural reference
that people wouldn't get. So, we know that
the
deals aren't loading correctly, but is that
the deal
service's fault? Maybe the product service
isn't returning the
right data for those deals. Maybe we're asking
it
the wrong questions. Or maybe we just have
a
bug in our rendering code.
The fundamental issue of all of these things
is
this tension between co-dependence and independence.
We are co-dependent.
We want to be independent. Some people solve
a
lot of these problems by embracing co-dependence.
So, if
our Rails app needs the services to be up
and running in order to run, we'll stand up
the services. You can do that. You can stand
up copies of the services locally on your
laptop.
This is more and more easy to do nowadays
cause we've got kind of trendy dev-ops things
like
Vagrant and Chef and Puppet.
That will only get you so far. Try standing
up a bank on your laptop. It's not happening.
Very, very common approach here is to, to
use
kind of shared services. So a shared dev environment.
A shared kind of staging environment. That
kind of
thing. And that, that works quite well. But,
for
our team, we decided to go the alternate route.
We wanted to, as much as possible, push for
independence. And, the main way we did that
was
by rem- replacing our dependency on services
with fake
services.
So, when we wanted to test our application,
we
wanted to test just our application in independence.
And
the way that we did that was, for each
of our dependent services, we replaced those
services with
kind of a fake version of that service. And
by doing that, we were allowed to run these
things that, that we called bounded integration
tests.
So, these were tests that tested the entire
stack
of our application, of our Rails application,
from top
to bottom, from kind of html all the way
down to the network. But, we weren't, we were
testing that in isolation. We weren't actually
hitting those
shared services.
And what's really interesting here is, do
you see
the, the boundary of those tests lines up
almost
perfectly with the boundary of our team. So
this
is a really good example of using Conway's
Law
to your advantage. Embracing Conway's Law
and shaping your
approach, shaping your software, with the
shape of your
team. And this was something that helped us
win.
So, if you want to build these fake services,
what are your options? Comes down to, to two
different kind of techniques, really. In-process
and out-of-process. So
in-process means you're kind of messing around
with the
actual Rails, running Rails process, and like
replacing the
network stack with a fake network stack maybe.
Out of process means you're standing up a
real
http server. It's an actual, you know, you
can
actually talk to it over http. And your application,
your Rails app, rather than pointing to a
real
deal service, it's going to point to this
fake
deal service. It's gonna look and smell like
a
deal service. You send it a request. It gives
you a response. It's not a real deals service.
It's a fake service that we have control over.
So, you can imagine if we wanted to test
unicode rendering, we could stand up a fake
product
service that returned a product tied tool
that was
all kind of snow man and that kind of
stuff. And, and that allows us to test how
we handle unicode titles without having, then,
to need
a unicode title.
So, in process, a couple of popular options,
vcr
and webmock. We actually used vcr quite heavily
on
this project that I'm talking about. So basically
it
just kind of sits, it kind of injects itself
in between your application and the network
layer and
records all the interactions between your
application and the
network, and then you can kind of flip it
into playback mode, and rather than, next
you time
you go and make a, make a network call,
it's not actually gonna call the network.
It's going
to just play back the previously recorded
interaction. So
that worked out well for us with some caveats.
Out of process, you've got a lot more options,
because you're not running out of process.
You don't
have to use Ruby. You can use whatever tool
makes the most sense. So mimic is a really
good option here. This is actually a Ruby
gem
written by Luke Redpath. It's a Sinatra application
that
pretends to be whatever you want it to be.
Outside of the Ruby community, or outside
of the
Ruby language, I suppose, there's a library
called moco.
It's quite powerful. Stubby is another one.
And then
there's this interesting one called montebank.
What makes montebank
interesting is it doesn't just fake out http,
it
will fake out whatever protocol you want.
So it
can fake out smtp to it, so you can
check emails. It'll fake out web sockets.
That kind
of stuff. So that's an interesting one to
look
at.
So now we've got these bounded integration
tests. And
that means we have some confidence that it
wasn't
us that, that's creating this bug. Because
our bounded
integration tests are passing. So all was
happy and
we can go on with our day.
Well, obviously not, because we actually still
don't know
where the bug is. And the goal here is
not for us to kind of, prove that we,
it's not our fault. The goal is to identify
the problem and fix it, because at the end
of the day it's a system. We're a part
of that system and we need to fix the
system and move on.
So, so we're left saying, OK. We know it's
not our fault. We'd like to help our, our
comrades on other teams figure out where the
problem
is. And for that we used a technique called
contract tests. So, contract tests, also sometimes
referred to
as consumer-driven contracts. The idea with
these is we
write test code that expresses what we expect
a
dependency, an external service to do, and
then we
run those tests against a real version of
that
service, and we find out if that service actually
does what we expect. Quite simple.
What's weird is we're testing someone else's
code. We're
not testing our code. We're, we're writing
tests, but
we're testing another team's services. So
here's, again, our
boundary, our bounded integration tests. And,
so we verified
that the way that the Rails app is, that
the Rails app does the right thing when it
talks to what we think these services are
doing.
Contract tests, once we add these, actually
verify that
what the service does is what we think it's
gonna do.
Cause it could be that there's a bug in
the service, and these tests will find those
bugs,
hopefully, because we'll ask it to do something
and
it won't do what we expect. There could be
a bug in our understanding of the service,
and
that's why these are called contract tests,
because they
define a contract between our team and the
other
team. Again, Conway's Law is coming in here.
How many of you have worked with an external
service where the, the Wiki page that documented
the
API was out of date? How many of you
have ever worked on a service where it wasn't
wrong? It's always wrong. And that's OK. Documentation
tends
to be stale. API documentation I think is
never
not stale. It just is born that way.
These contract tests are a way to, to, to
mitigate that. Because you're expressing your
expectations in code
rather than in words.
So we, on, on my, on my team, we
wrote contract tests for every single one
of our
dependencies. This was the most productive
thing we did
on this team is, in terms of improving efficiency
of, of us creating software. It really, really
helped
us nail down, whenever there was an issue,
where
that issue was. And it really helped us communicate
with, with our friends on other teams.
So, if you want to do these, you've got
a few different options for contract tests.
We actually
just did plain old RSpec. We just used standard
RSpec test runner to make network calls to
our
dependencies and then look at the results
and make
sure that things looked the way that we expected
them to look.
There's two more kind of sophisticated options
out there.
There's a gem called pacto and another gem
called
pact. And these are kind of like real power
tools. They're quite sophisticated. They're,
they're very fully-featured. If
you want to really kind of get into this,
into this mind set.
So once we had these bounded integration tests
and
these contract tests, we were left with this
kind
of CI dashboard that looked something like
this. So
whenever we checked in code, we'd run our
unit
tests, we'd run our functional tests. And
assuming those
passed, we'd run our kind of bounded integration
tests
up there at the top right.
Assuming those passed, we'd then run our end-to-end
tests.
So these were running, testing as much of
the
stack as we could possibly stand up. So, our
code, our team's code, maybe our team's dependency's
code.
So as much of the stack as possible. So
really verifying, from a user's point of view,
that
this, this system worked as we expected.
In theory, this was the picture. In reality
it
was almost never green. That was OK. So, this
is what things looked like a lot of the
time. Our tests were passing, the end-to-end
tests were
failing. If that was the end of the story,
we'd be left constantly fighting fires of,
why is
it not working in product- or, why is it
not working in staging? And is it the deals
service or the product service, blah, blah,
blah.
But we had these contract tests. So now we
can see here that service D's contract tests
seem
to be failing. So we've got some end-to-end
tests
that are failing. This contract is failing.
That's where
we can start looking for, for the cause of
this problem.
So this is what we spent a lot of
our time, not a lot of our time doing,
but this was a very frequent occurrence. The
build
would go red. We'd have a look at our
dashboard. Oh, it's service D, again. Service
D, you
guys.
So we go to our CI system and we
would look at the logs. We'd get the log
data that showed the request we were sending
the
response we, we got back. And we'd have a
look and say, yup. It looks like they've broken
it again. They forgot to turn on the database
after doing a deployment, again. And we would
write
an email to them saying, hey, I think it's
probably a bug in our code, but we've noticed
when we send this request we get back this
500 error from your service, I don't know
what's
going on there.
You can tell I'm a consultant.
And, things moved a lot smoother. It, it wasn't
all kind of rainbows and unicorns, but it
was
a lot better than if these tests hadn't have
been there. We would have still ended up telling
them and they would have fixed it, but it
would have sucked a lot more of our time.
So that's all the hand wave-y, let's all work
as teams stuff. Let's talk about how we're
actually
gonna build this, this inside of our team.
So I want to talk about this idea called
service gateways. The main thing I'm gonna
talk about
with service gateways is this gem called faraday.
And
in order to talk about this gem called faraday,
I need to talk about this other gem called
rack.
So, how many of you know what rack is?
Yeah, everyone knows what rack is. How many
of
you hate people that ask you raise your hands
when you're in the audience? I have all the
power. You guys have the power but don't realize
that.
So, rack is this awesome abstraction over
http servers.
And the main idea, the main thing that makes
rack awesome is, by abstracting over the concept
of
a request and the concept of a response, we
can kind of stack these middleware components
in between
our application, and the, the underlying http
server.
So, as a request comes in, from the outside
world, it travels through this stack of middleware.
So,
each piece of middleware can, as this request
is
traveling through, has the opportunity to
kind of modify,
modify the request and kind of transform it
in
some way, add some information to the request,
or
to kind of have some side-effect.
And then, a Rails app is gonna deal with
that request and then, and then send back
a
response. And, again, as that response is
traveling back
up through the pipeline, through the, the
middleware stacks,
again, each of those pieces of middleware
can modify
that request in some way, can add some information
to it or can have some side effect.
Rails loves rack. So this is the, the kind
of the stop stack of rack middlewares that
comes
when you, when you just do rails generate
new
project. So, yeah. Pretty, pretty popular.
And the reason
that this is popular is because the guys that
built rack are smart and the guys that, guys
and gals, excuse me, that built rack are smart
and, likewise, Rails. And they realized that
this is
a very powerful abstraction and so they're
really leveraging
this power.
So why was I talking about rack when I
was supposed to be talking about faraday?
Faraday is
the exact same idea of rack, but applied for
an http client. So, again, we have this abstraction
over request and response. This time in the
context
of making a request and receiving a response
rather
than receiving a request and sending back
a response.
And, again, we can stack these pieces of middleware
in between our application and the underlying
network library.
So, in this case, it's us making a request.
So, as we send the request out to the
network, again, that request travels through
all of these
middlewares, and these middlewares, again,
have the opportunity to
either modify that request in some way, have
a
side effect, add some information to the request.
Eventually
it gets on the wire. Eventually it gets to
our dependency. Hopefully not service D because
they'll probably
go down again.
And then service D hopefully sends a response,
and
again, as that response travels back through
the stack,
the stack is able to modify that, that response
as it comes through, add some information.
Have a
side effect.
So, how do we use this thing? So here's
a, this is a service gateway. This is a
class that represents a, a connection to the
outside
world. Here's us building a faraday middleware
stack. So
we're building a connection. We're saying
hey, new faraday.
Please use the instrumentation middleware
and do some JSON
stuff and follow redirects and do some logging.
And that's it. We've now got a faraday connection.
This is how we use a faraday connection. So,
we say, hey, faraday connection, hey, http
client, we
want to get this url, or this path. And
we get a response back. Pretty simple stuff.
I
would say this is readable code. DHH would
be
pleased with me.
And what's really nice, the real power of,
of
faraday, is there's all this extra stuff that
we
set up, this middleware, this technical junk
going on.
But our, the rest of our code doesn't have
to care about it. So we've kind of abstracted
over all of that stuff of JSON, following
redirects
and logging and caching.
So we used faraday a lot in these things
that, that I was calling service gateways.
So the,
as I said, the really nice thing about things
like rack and faraday is they allow us to
segregate the boring tech-y stuff, http, logging,
caching, instrumentation,
the stuff that computer people talk about
at conferences
like this, from the business domain, which
is the
stuff that people actually care about.
So, these service gateways acted as the place
where
we pushed all of the boring techy goop out
to the boundaries of our system, so the core
of our system, the core of our Rails application,
wasn't talking about JSON requests, urls,
caching, logging, deserialization.
It was talking about books and products and
prices.
Things that our application really should
be caring about.
So this is this idea of hexagonal architectures.
Push
all of the goopy boring techy stuff out to
the boundaries of your system, so that the
core
of your system can focus on the domain. The
stuff that you really care about. The stuff
that
makes your system valuable to other people.
So what kind of things did we put into
these? What kind of stuff, boring techy stuff
did
we isolate in these service gateways? One
thing that
we did was we isolated serialization. So,
serialization means
JSON parsing or, in our case, XML parsing,
cause
we were in an enterprise. Yay.
Comes down to the same thing actually. So,
when
we talk about parsing JSON or XML, we're actually
talking about two different things. And I
think often
we conflate these two. So, step one, is we
have this stream of bytes or this raw string,
and we want to turn it into this kind
of generic structure, like a hash of arrays
of,
of objects, right. So that's, that's something,
you know.
You do JSON dot parse or whatever and you
get this kind of generic data structure out.
But, if we are following the principles of
hexagonal
architecture, we don't want to deal with JSON
data
structures or generic data structures. We
want to deal
with products and books and deals. So the
next
step is to actually take that generic structure
and
map it into a domain object that we actually
want to work with.
Cause our goal here is to stop talking about
things like JSON as quickly as possible, at
the
boundaries of our system, and start talking
about products
and prices and deals. So this is two steps.
So, the other thing that you'll, I noticed
working
particularly in larger organizations, is these
responses that you
get back are huge. And really, often times,
you
only really care about a small subset of the
response you get back. So you get back this
big chunk of bytes. You turn it into this
big generic structure, and then you actually
just want
to pluck three or four or five or six
things out of that structure, that represent
the product
in your, in your domain.
You don't care about the, the short description.
You
certainly don't care about the response time.
Really all
you care about is the, you know, the title
or the author, you know, that kind of thing.
So there's some gems that can help you make
this easier. So, very popular one is this
thing
called hashie. Hashie will just make it a
little
bit easier for you to work with these generic
data structures. But at the end of the day,
they're still generic data structures.
The second step that we took was to take
all of that boring boiler plate that we were
doing of saying, you know, get this dot that
dot the other thing and get me the price.
And then this dot that dot the other thing,
get me the, the offer details. And turn that
into a declarative statement that we could
just make
at the top of a class that would make
these things.
So we turn that mapping, that boring boilerplate
mapping,
into something that was declarative rather
than imperative. We
actually ended up extracting that little library
that we
built into this thing called lazy_doc. There's
another couple
of gems that are very, that have very similar
goals. Embedded_doc is another one. And there's
this really
quite powerful one called representable, which
is very good.
It's, it's very powerful. It almost does too
many
things for my taste, but it's definitely,
definitely a
good option.
The reason, by the way, embedded_doc is called
embedded_doc
is cause it's, what we're kind of talking
about
here is this embedded document pattern. That's
the name
of the pattern. Sorry, now I'm talking about
patterns.
I'm really off-message.
So what else did we put in our faraday
stack? Caching. This is the most, for me,
the
most exciting thing to talk about. So let
me
talk about it. So, back to our example, let's
say we've got our Rails app. And we've got
our product service and we've got this pricing
service.
Fun fact that I didn't know before I worked
on this application. Prices can change, like,
multiple times
a minute in some of these systems. They're
really
trying to optimize for prices.
So, can't really cache pricing information.
Product information tends
to be pretty static. The author of a book
doesn't change very often. The title of a
book
doesn't change very often. But we're always
looking up
this product information, almost every single
request. So let's
cache that. Let's make this performant.
So, a lot of you are automatically starting
to
think about how we would implement this and,
well,
we would have a product cache, and then when
we need a product we'll go to the cache,
and if it's there, then we'll check the freshness.
And if the freshness is up to some configured
thing, then we'll get it. Otherwise we'll
go to
the network. And then when we get back from
network, put it in the cache, blah, blah,
blah.
All of this stuff, right. And we're, we're
back
to thinking about boring technical goop and
we're not
talking about our domain anymore. We didn't
want to
do this. I'm, honestly, bored with getting
caching wrong
over and over again in each of my applications.
And so, we just pretended to be a web
browser.
As web developers, we know that images are
very
cacheable, and we should put caching headers
on our,
on our images, so that the browser can do
the right thing and cache this so that every
time we want to get this image, if it's
already in the cache, we don't have to go
onto the network. Kind of very common practice.
We don't write JavaScript cache repositories
and then go
and check and see if the image is in
there and then, if it's not, we'll go to
the network and then put it in the cache
repository.
The web browser just does this for us. All
we need to do is set the caching headers
on this, this ping. So, my argument is, and
what we did was, just apply the same principle
to our API. So product dot, or product slash
wherever this is at - my pretend url for,
for this product. We had caching headers on
this
API call, that said this, this url is cacheable
for twenty minutes.
In our faraday stack, we had a caching middleware.
So, the first time that we requested that
url
for that product, first time we wanted that
product,
our Rails app would say to our service gateway,
I want this product. The service gateway would
say,
OK, it's at this url. I'm gonna make a
request through my faraday stack for that
url.
That request would go through our stack, and
the
response would go through our response on
the way
back, and the caching layer would say, oh
look
at that. There's this caching header on this
JSON
that says it's gonna be valid for twenty minutes.
Let me just put this response in my little
cache on disk here.
And, five minutes later, another user comes
in and
wants to, by chance, look at the same product.
Again, our service gateway, our code doesn't
do anything
different. It just says, hey, service gateway,
I want
this product. Our service gateway doesn't
do anything different.
It just says to faraday, hey, I want to
get this url.
The request comes through to the caching layer.
The
caching layer says, oh look. That's the same
url
I just pulled five minutes, and the, the caching
headers say it's valid for twenty minutes.
I'll just
return what I've got in my local cache. I
won't go on the network. I won't bother with
all that stuff. I'll just read it from the
disc.
This is what web browsers do all the time.
We can do this all this time with, literally,
a single line of code. Sorry. That's not a
single line. It's a single method call. Would
be
a single line, I guess everything could be
a
single line of code, right.
So, we've just said to our faraday stack,
hey,
add some caching middleware. Write it to disc
at
this location, and there we go. We, we've
now
got all the semantics of a web browser. And,
we didn't have to do any work apart from
this single method call. And what's really
powerful is
the team that knows the most about the data,
so the product team in this case, can define
the caching semantics of their data.
So, if they realized, like, you know what,
these,
this, the name of the author keeps on changing.
We need to drop down the caching freshness,
they
can just say, you know what, it's gonna be
ten minutes. And we just get that semantics,
we
just start, we change our caching rules. No,
no
code change. No configuration change. No redeployment.
It just
happens.
So, again, Conway's Law. The team that knows
the
most about the data has control over the caching
of that data. Really, really, really powerful
stuff.
This goes back to this principle that, that
I'm
really passionate about. I think a lot of
times
we, we, we, we think of ourselves as building
these systems on the web. We, we're building
our
stuff on top of http. I don't think we
should be doing that. I think we should be
building systems that are of the web.
So, we should be using principles like, like
REST,
like hypermedia, like caching, http caching,
because these, these
are the principles that have made the most
successful,
biggest distributed system in the world work.
It's really
messy, and sometimes it's a bit of a pain
to use, but it works really well, and it's
all done for us already. We don't have to
figure this stuff out ourselves. It's all
out there
and it's been working for decades.
We use it, in some cases, hypermedia is something
we're starting to understand more and more.
We can
use it in more places. Caching is, is an
example of that.
So, some principles. I could have talked about
all
this stuff for hours and hours and hours,
but
I don't have time to do that. So I'm
just gonna shove a bunch of words at the
end of this talk, and, and hope that, that
if they're new words to you that you go
out and, and research them.
Conway's Law is, is the big one. This is
something I'm really passionate about. If
you, software, building
software today is very much a team sport.
If
you don't understand how to work with other
teams,
then someone else is gonna do it better than
you. So this is important stuff.
Domain-Driven Design, I kind of touched on
this talking
about domain objects and talking about kind
of bounded
contexts. It's a really, really good book.
It's really,
really hard to read. Eric Evans is an incredibly
smart guy who's not necessarily the best at
kind
of succinctly expressing ideas.
If you do get this book, read the second
half before you read the first half. He himself
has said he got the order around wrong in
retrospect. The, the second half has loads
of really
good stuff in it. The first half does too.
But the second half, I think, is where the
real, the real, real great stuff is.
Postel's Law. I didn't really talk about this
at
all. But if you're building SOA systems, this
is
the way that you evolve these systems over
time,
without having to redeploy your entire enterprise
at once.
So, Postel's Law is very, very valuable. Another
reason
why the web has been so successful is Postel's
Law. html is incredibly permissive. It draws,
it causes
a bunch of pain, but it also is the
reason why html is the system that we still
use today.
Hexagonal architectures. Talked about this
a fair bit. This
is a really, really important principle. I'm
really excited
that the Rails community is starting to kind
of
get, to get excited about this. But it's been
around for awhile. There's loads of really
good talks
out there about hexagonal architectures as
they apply to
Rails. There's been a couple of talks at the
conference already.
There's a, there's a Birds of a Feather session
tonight about it, I believe. So there's loads
of
res- loads of good resources out there. Not
just
for Rails specifically, but just, hexagonal
architectures in general.
Because it is a general architectural principle.
Finally, we should be embracing the web. It's
been
around for a long time. The patterns are very
well understood, very well established. The
tooling is amazingly
powerful. We keep on reinventing wheels. Let's
not keep
reinventing this particular wheel. When it
makes sense to
make the web and the principles of the web,
we should be doing that.
Thank you.