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.