ERIC SAXBY: Thanks for coming.
So, I am Eric Saxby. Today I'm gonna be talking
about iterating towards service-oriented
architecture. I may have time for questions
at the end, but I may not.
This might go forty minutes,
so I'm just gonna get started.
So, if you're like me, you can't really pay
attention in talking about programming
unless there are pictures
of cats. So really, we're going from this
to
something a little bit more like this. But
working
together, as a family.
So why should you care? Why should you listen
to me? So you may not know this, but
I'm kind of a big deal. But, but really,
I've, I've actually not been doing this for
that
long. I've been doing Rails for about six
years.
Before and after that, I had been using various
different technologies. And I have been fortunate
to work
with some very smart people and be able to
learn from them and to break a lot of
things really quickly. And right now I work
at
Wanelo. Also, I'm trying to collect all of
the
buzzwords on my resume. I have more. I have
more than just this.
But, so, why is Wanelo important? We're like
a
social network for shopping, but really it's
because we
have many millions of users, active users,
and databases
with billions of records. And we've gone through
the
pain of getting there and keeping the site
actually
running. So, you can save any product from
any
store on the internet into your own collections
and
have your own wishlist. That's what we do.
More importantly, we've gone from having this
as one
main Rails application, doing all of this,
to a
central Rails application that's still fairly
large, but supported
by a lot of services. We've done as much
as we could open source. Some of the, the
business domain logic, it's really hard to
open source.
But, but we try as much as possible.
We've done almost all of this in Ruby, including
some things that people who prefer other languages
say
can't be done in Ruby. And we've done this
with a very, very small team very quickly.
If you're like me, though, you're really not
so
interested in the success story as you're
interested in,
how did you screw up, how did you, how
did you break. So, let me take you on
a journey to another company that a friend
of
mine once, recently, called "The Anti-Pattern
Goldmine." Completely hypothetical
company. Not naming any names. That I may
or
may not have worked for. Some of you in
the audience may or may not have worked for.
After some of this story, you might think
you
did. Come in, it's a startup. It's new. Small
team. And come in and say, wow. For a
startup, you have a lot of code that's really,
really tangled. It's all Rails 2 code base.
You
know, if you remember vendoring Rails, we,
we did
that. If you remember how vendoring Rails
can go
wrong? Yeah, yeah. Yeah, that was there. That
was
there.
And I think a lot of this might have
come down to the fact that at least early
on, success of a product, success of a feature,
really was launching it as quickly as possible.
And
no, no, no, no. Don't worry about that stuff.
Don't worry about design. And we have thirty
engineers
doing that as rapidly as possible. Like, five
or
six teams all doing that as rapidly as possible,
trying to get it into production. And releases
were
a mess, you know. I'm sure a lot of
you can relate to this. Deployments. Multiple
hours with
all of this engineer, all these engineers
trying to
put all of this code in as quickly as
possible. Invariably, deployments went wrong.
And eventually this got a little bit faster
from,
from monthly releases to weekly releases.
But then we
would have code freezes, where for three months,
everyone's
trying to cram in all the features without
deploying,
and you can imagine where that goes.
And, over time, really, things are just getting
worse.
We, our rough estimates that we're trying
to give
to see how long things are gonna last come
back, and we say, oh, that means we were
deploying on this date. You know, hey, we
told
the board, great. That's awesome. You're gonna
deploy on
this date. Ah. Whoo. With a deadline like
that,
the only really way to meet it is to
make serious shortcuts. And then as soon as
a
product finishes, because we're invariably
missing those deadlines, and
there's the next project that is supposed
to be
out in, in a week, based on the estimates
that you were supposed to do. Team gets dispersed.
Finish these new projects. And no matter how
worse
case we are in our estimates, it's just never
worst case enough. It just, it just keeps
getting
worse.
So some of you might, might be familiar with
this story. So, during the course of this,
I,
I, I, I think I've learned a lot. You
know, programming is one of the most fun careers
that I've, that I've had, and when it's not
fun, you know, you know something's wrong.
And keep
reading about service-oriented architecture,
and, you know, a lot
of us latch onto this. This is the solution
to all of our problems. And you know at
dev ops, that's pretty cool over there. You
know,
dev ops is the answer. That's how we're gonna
do services. It's just gonna, it's a done
deal.
All we have to do is do services, dev
opsy, and like, we're done.
So around this time, I move into the operations,
not, not the operations team, cause dev ops.
Not
the operations team. Not the team over there
that
you just throw the things over the wall and
they just make it work. No, no, no. Not,
not the operations team at all.
And certainly me, a number of other people
in
the engineering team, I, I could say, really
decided
services are the only way forward. And really
quickly,
product, and, and I don't mean an individual
project
manager or anything like that. By product,
I mean
really, all of the people, all of the teams
going into designing the product, planning
the product, really
how it was going forward, they quickly come
to
the conclusion that services are really just
that, just
that, that thing getting in the way of us
cranking out these features. Cause features
is success.
But at first, if at first you can't succeed,
I have, I have, I have learned, you know,
there's, there's a few things. You can take
a
firm stance, breathe deeply, and become the
loudest person
in the room. Really, really helps. Also, if
there's
anything that I've learned from my cats, it's
throw
shit, you know. Done. It really, really helps
in
situations like this.
So, we, we have a few things coming up.
A few products. These, these aren't necessarily
concurrent, these,
these features. These projects. But we have
a new
login feature and login, in this application,
is as
homegrown as you could possibly imagine it
could go
wrong. And it's this core, core login functionality,
and
we're like, no, no, no, no, no, no. No,
no, no, no, no, no. That's not going in
this code base. That's gonna be a new application,
we're. That's the only way we're gonna do
this.
Otherwise we're just not gonna do this. It's
gonna
fail. We know it's gonna fail. So let's just
skip to not doing it.
And, also, we have this enterprise software
over here,
and we have this homegrown Rails application,
and all
the data really needs to kind of be synced
between it in order for the company to actually
work. So a lot of iterations on this, but
really this time, we're gonna do it right,
and
it's gonna be a, a data service. We're gonna
have our Enterprise software in our Rails
app and
that is totally just gonna make this an Enterprise-Rails
app. It's gonna be amazing.
And I remember saying this a lot to a
lot of different people. Like, we're gonna
screw this
up. We're gonna fail. I know we're gonna fail.
But it's the only option that we have. It's
the only way that we're actually gonna be
able
to get to be able to do this and
succeed at some point in the future.
OK, so on, on a side track, hopefully this
is not new to very many of you, but
really there's a lot of different ways to
do
service-oriented architecture. It can mean
a lot of different
things. Read blog posts. You get a lot of
different ideas. It can be synchronous, asynchronous.
Use a
message bus. Maybe some services require actually
hitting them
over HTTP, TCP sockets. You know, there's
a lot
of ways of different doing, of doing this
kind
of thing.
But why would you really want to? So, you
know, scale the organization. You have a lot
of
different teams. A lot of different engineers.
Maybe you
really want this team over here to just have
their own code base that they deploy separately.
Also,
maybe you want to outsource this to a different
team, and you really don't want to give all
of the code to the other team. You really
just want to isolate this and say, you know,
you guys over here, you know, just, here,
here's
this. Sorry. I'm, I'm actually trying to explain
it
all gendered pronounce from my vocabulary
but it's really
hard. Sorry.
So, you can also scale the code base, you
know. Performance of this thing over here
might be
completely different than this thing over
here, and that
might actually be easier in a service. You
can
really tune the code to the work load. You
might have this really complicated code that,
for various
reasons, needs to be complicated. It might
be really
complicated functionality. But you can, you
might be able
to hide that behind a, a clean interface.
An
API.
And tests, usually, not always, but a small
code
base can mean fast tests. And if you're sitting
around for hours waiting for tests to complete,
you
know, that can be, that can really eat into
your productivity. But it, but it comes at
a
cost. All of this comes at a cost.
And I think one of the things that, that
I've been learning is that sometimes the cost
of
not doing this is greater than the cost of
doing. The cost of the infrastructure, new
servers, how
they talk together. It's really complicated.
Things will go
wrong. But sometimes not doing this is gonna,
is
gonna mean that your productivity is going
down and
down and down and, and it actually is more
costly.
OK, so back to these projects. We have this
data service. It's sometimes, I think six
engineers, sometimes
eight. I don't, I don't really remember. And
nine
months of, of work. It's really complicated,
like state
transactions, and this is really critical
data that really
needs to be done right. And there are, so,
there, there might have been, when deploying
it, some,
some slight data things. But they were fixable.
Really
quickly. It was fine. There were actually
no major
data problems.
And there were some applications that were
built on
top of this data service. And depending on
who
you talk to, they, they were more or less
successful. Some people using that, these
applications are like,
oh, thank you, this did exactly what, what
I
need. It's actually helping me with my workflow.
Some
people are like, oh, OK.
But engineering, you know what, this was really
critical
data. It was really hard. Totally new for
us.
This was a success. We did not break anything.
Product is like nine months? Nine months.
Eight engineers,
nine months. How could you possibly call that
a
success?
OK. So different application. Login flow.
Depending on the
time period, two engineers, four engineers,
plus the dev
ops team. Dev ops. Three months, you know.
You
know, we were figuring out, like, the system's
automation
was really tangled and in, in a few weeks
we had some staging servers. And about two
months
later, someone comes up to me and says, hey,
where, where, where are the servers gonna,
gonna be?
Can we get those? And I'm like, deep breath.
Deep breath. Which servers? Oh, this, those
staging servers.
But it went, we worked it all out.
Something that I learned about dev ops. Everyone
actually
needs to be invested and it's new to people.
So, and it was released with a feature flag.
Only a small amount of people were actually
running
through it. So it, we had some really good
time to break it in production and really
figure
out how, how it was really gonna run.
And we launched it to all of our users,
and it was actually, I would say, very successful.
It worked exactly intended. It was very resilient
to
failures. We had to do some unexpected database
maintenance.
Restart master databases and we're like, you
know what,
just do it. You know, just, just restart the
database. No, no, no, no, no. Don't turn off
the service. It's gonna recover. It's gonna
be fine.
Maybe like one user will notice.
And the company's actually sort of figuring
out that
user metrics might be more important than
dates as
metrics, and the user metrics were generally
successful. So
engineering, like, this, this is good. This
is good.
This is, this is how we do this. This
is, you know, the next project, this is how
we're gonna, we're gonna have to figure this.
And products is like three months? What are
you
talking about? Success? That's not success.
We have these
other product features that needed to be done.
And
we have these four engineers that are sitting
in
the corner, not able to do these things.
OK. So I would say that this is a
really important question to ask. What is,
what is
success? If engineering says it's a success,
and product
says it's a failure, who really wins? So,
this
is actually a trick question, because it's
a zero-sum
game. Like, nobody wins in this interaction.
So let's go a little bit deeper to ask
why we needed SOA in the first place. And,
I, this is really complicated. There's lots
of moving
parts, but some of the things that, that I
think now were because engineering didn't
trust product, and
we actually didn't, what that really means
is we
didn't trust that we could do our jobs well
given the shortcuts that we needed to do to
actually do our job and actually meet our
metrics.
And product didn't trust engineering to meet
the products
we were given, and we, we couldn't actually
meet
those promises. And, again, over time, this
was changing,
but product was accountable for features,
not or quality,
and, and the actual how users interacted with
them.
And this is probably the subject of much more
discussion, and would love to continue this
and, and
learn more myself, but I think that a lot
of this comes down to trust. If, if, if
you can't trust that you can do your job
successfully, how, how can you actually do
your job
successfully? If, if product, if different
parts of the
company don't trust each other to do their
jobs
well, how can they actually do their jobs
well?
So, what did, what did we learn? You know,
fuck it, next time it's SOA from the beginning.
Like, before we even do Rails new it's gonna
be RabbitMQ. We're gonna have a cluster. It's
gonna
be amazing. So, no. No, no, no. Not, not,
not the right answer. I almost went here,
and
thankfully I worked, then, with some very
humble, empathetic
people, who were also very convincing. No.
So, I think what I've, what I have really
taken from this, is Agile's not just one sprint
after the next. It's like four miles is great.
You just break it up into a hundred meter
increments and you just, each one is a sprint.
It's gonna be fine.
What this really is about iterating. Deploying
things, small
things, really quickly, using the data that
you get
from that to figure out what to do next,
and refactoring. Refactoring is really, really
important. You might
be able to do a small thing quickly, and
with some shortcuts, not really needing to
know how
it needs to be designed. But when you see
the pattern, you, you have to fix it. And
SOA's not gonna solve larger organizational
problems.
It's not gonna fix your code. Really what
it
is is another tool at our disposal to solve
our pain points, and our, and our organization's,
our
company's pain points. And how we do that
is
through iteration. So, small changes deployed,
deployed quickly, using
feature flags so that you can actually get
code
into production as soon as possible, knowing
that it's
off and it's not gonna affect users. And prioritizing
this when it's necessary.
So when might it be necessary? I would say
performance. That's a really big thing. This
is actually
driving a lot of what we're doing. Code complexity
might be less in a service than it would
be outside of a service. So if you have
these two things and you're like, this is
actually
gonna be easier to do over here than to
put in this tangled mess, maybe, maybe it
is
better.
May, and also maybe, sometimes you have a
new
feature and it is completely unrelated to
everything else
that you've already done. With the caveat
that you,
in the short term, you might be able to
put it in with all the rest of that
mess, trusting that when it becomes a problem
you
will be empowered to fix that problem.
OK. So, performance. As I said, this is driving
a lot of, of our work. So, Winelow is
getting slower. We're running into some problems.
We just
got ring that the databases are becoming I/O
bound
on disk. This is a really, really bad place
to be. But our user growth is increasing dramatically.
The, the activity is increasing dramatically.
We're starting to
see exponential tendencies in our graphs,
and if you
see exponential tendencies in your user graphs,
it's kind
of like giving a talk to hundreds of people.
You're like, why are you all looking at me?!
It's, it can be scary. It can be really
scary. But we have, so we have one table
that's really outstripping the others, and
that's causing problems.
That's, it's, we discover, because of our
data, because
of our graphs, that it's really one table
that's
really destroying the performance of the rest
of the
table. And we're in the cloud, cause we have
all those buzzwords. So there's really a maximum
size
of a host that we can get. So there's
really, like, an upper limit of how much we
can actually solve this with one database.
Even after read-write splitting, we've already
done that, and
we, and, and pretty soon, we realized that
the
site is gonna break. If we don't do anything,
we're just not gonna have a company anymore.
It's
just gonna, it's gonna fall down. But, we
have
really, really, really active committed users
joining us right
now. Now is not the time to stop feature-development.
Now's the time to really learn from what our
users are doing, double down on it, really
tweak
our features and figure out what is gonna
make
our business successful.
And we only have ten engineers at this point.
We don't really have that much, that many
resources
to, to, to work with this.
So, our first step of iteration is realizing
that
this is one problem. How do we solve this
one problem? And this is maybe going to be
a service. How do we get to a point
where it can be a service? So first step
is isolating the data. So ActiveRecord gives
you these
really nice things. Associations, has_many,
has_one. Things that really
make the joins between your tables easier.
When you have a service, you don't have joins.
So these need to go away. These, these just
don't exist. But it's actually really easy
to get
rid of these, honestly. A product has saves,
you
know. You save this product into a collection.
You
know, we could just take that where clause
that,
that ActiveRecord was gonna sort of do for
us
with, with a join, and just pull it out
as a, as a where.
Really not that hard, actually. And you know
what,
ActiveRecord also gives us ways of talking
to a
different database. But, you know, we can
actually use
this to just pretend it's in a different database.
Establish connection allows you to have this
model live
in this database and all the rest of your
stuff live in your main frames. It's really
not
that hard.
And, one of the key things is that each
step of this, each slight change, is deployable,
and
it's testable. And you can deploy it to staging.
You can click around to see where, where your
test coverage is maybe missing. Figure out
where, where
it breaks. And one thing is that, that I
will say, is you might be doubling your database
connections at this point. And when you database
hits
the max connections, just everything stops.
It just stops
working.
So, we've learned this lesson the hard way.
But
now that we have this code deployed that pretends
like it's in a different database, we can
make
it a different database. Without actually
that much work.
You have a Postgres - we love Postgres -
we have a master database. And we spin up
a replica over here, and we put the site
into maintenance mode. If you have more critical
interactions
with your company that maintenance mode might,
might not
be possible, brain tree has some really great
blogs
and, I think, talks about this. But, for us,
the operational overhead of making it so we
can
do this without the site being down was way
more than it was worth.
So we just take the site down. Push in
new database dot yml, saying now this connection
is
talking to this database. And we just promote
that
to master and restart everything, bring the
site back,
and now we have two databases. Five minutes
of
downtime. Not, not that bad, actually. And
you know,
after the fact, you can clean up. You know,
we have a redundant table over here. A bunch
of redundant tables over here. You just truncate
them
and delete them. Very carefully.
Not that hard. And actually, you know what,
at
this point, you might not need a service.
You
might be done. Your site might just be working.
It's fine. For us, we, we knew, based on
how things were going, that we were gonna
have
to horizontally shared this data. Now it's
in a
different database. That is gonna have to
be many
databases.
And we want to hide that complexity. We don't,
we do not want our main application to have
any of that code. So, we know we're gonna
have a service. Now isolate the interface.
And now
what this, by this, I mean, how are you
actually accessing this data? And what is
your long-term
goal? You know, ours is sharding, and Wanelo
is
saves, and anytime we're actually getting
saves, we're either
looking at by product - a product has these
saves - or we have it by user. A
user has saved these things.
So, this is actually really helpful, how to
plan
out what, your DSL, what your API is gonna
look like, you know. We know that things are
gonna have to get to it via product or
via user. And so, you have some where clauses,
you know. Where is ActiveRecord? We are not
gonna
have ActiveRecord.
So, instead a save has a by_product method
that
is also. Oh, so one thing I will say
is, at this point it's really helpful to remove
redundancy. If you have different ways of
accessing kind
of the same data, do you really need that?
You know. Can you change the product to mean
that you don't actually have as many of these
fingers as you have. And very soon, things
are
gonna break. So if you don't have tests, this
is a really good place to add tests.
So, now, we have a, a small sort of
Ruby DSL. How do we actually pull that out?
And I would say, right now, it actually doesn't
need to be a service. Really what you need
is a client. And how do you build the
client out? And that's where adapters really
come in.
So, we use the module. This could be a
base class. Some of the reasons why we thought
we needed a module. Maybe we didn't Maybe
we
could have actually done this as, as a base
class. But now, a save is a SaveClient. And
that SaveClient is where your fingers go as,
their
class methods. And one thing I would point
out
is that that, that finder is calling through
to
an adapter. A database adapter.
And really, that's what's wrapping up all
your database
calls. Hiding them from, from your application.
And really
one of the core pieces of this is that
your database, your, your adapter is your
feature flag.
It's also deployable in place, you know. You,
you
can have this in your lib folder. You can
actually start a gem now. And you can just
deploy it and it's, your main application
is still
talking directly to this other database. But
you're starting
to build out your client. And later, when
you
have a service, you can replace it with a
different adapter.
So that adapter gives you back, when you,
when
you call, like, a, you know, you get save.by_product
and you call all on it, that's actually, when
you call by_product, you're getting back a
relation. And
this is something that we thought we didn't
need,
but turns out ActiveRecord does this for very
good
reason, and that's because threads and because
state.
If you say I want this type of data
and you save it away to a variable, and
now you call some other method, order.by_this,
and it
changes state, you might do something else
on this
variable over here, not realizing that you've
altered its
state later. So any time you make a change,
a state change on these objects, you really
want
to get back a new instance. A different instance
with different state. And when you call, you
know,
all, first, or pluck any of these things,
what
you're really calling it on is your relation
instance.
And the, the key thing that we learned is
that that relation is sharable between all
of your
adapters. So the actual work done to get the
data is on your adapters. So the relation
delegates
back.
So, in our database adapter, the thing actually
getting
the data, is ActiveRecord. We've just moved
our ActiveRecord
class into the library and hidden it from
our
application. We, in this case, we were using
ActiveRecord,
so you could just, we'd do ActiveRecord. If
you
have another favorite database adapter, great.
So you call Save.by_product. You, you get
an adapter
that, or so the, sorry, that calls through
to
the adapter and gives you back relation. You
call
Relation dot all and that just delegates back
to
the adapter, which calls through to an ActiveRecord,
gets
to your data, takes the attributes out of
it
and gives you back an instance of, of your
core class. Because you're hiding ActiveRecord.
You don't want
to get back an ActiveRecord class.
And I would say it's critical to deploy at
this steps, because you've made mistakes.
I guarantee you've
made mistakes. And the cost of fixing this
is
really low right now, as opposed to spending
a
lot of time trying to design your server,
how
that's going to interact, and realize, whoa,
whoa, whoa,
whoa, we screwed up the client. All of this
work we've done on the service, we have to
through away because we did it wrong.
Now, you have a client. Now you need a
server. And it doesn't matter. What, whatever
you want.
It's fine. It's actually the, the cost of
writing
this is really, really low. Because the server
is
the simplest part of this, and if you did
it wrong, if you chose the wrong transport
method,
mechanism, you know what? You build a new
adapter.
That's actually really quite easy.
So let me take a moment to just reiterate,
why should we have deployed by now? And I'd
say it's because the client is much, much
more
complicated than the server, so your bugs
are in
the client. Your bugs are not in the server
at this point. And the server is going to
be dictated by the choices you've made in
the
client. So if you've made wrong choices and
you
build your server, you've built the wrong
server.
We used Sinatra and Oj, just cause it's awesome.
It just, it really just works. It's small
and
it's useful. We thought we would need to move
away from HTTP, but we've grown a lot and
we haven't had to do this yet. It just
works. Things that we thought we would have
to
change immediately, you know, it's almost
a year later
and it's just.
OK, so now we use the service. And that's
really a feature flag. You just write a new
adapter that talks to the service instead
of the
database. So now you call, you know, by_product,
you
get a HTTP, it calls through to the HTTPAdapter
which gets you back the same time of relation.
When you call all on it, you know, it
calls adapter dot all, which now goes to an
HTTPClass that actually gets the JSON and
takes the
attributes out of it and gives you back your
save class. You're getting back the same object
you're
getting back as save.
So, retrospective. Great. We've isolated the
data. We've isolated
the interface. We started to build our DSL.
We've
pulled that DSL out into a gem. Now we've,
now that we actually kind of understand what
that
gem needs to do, we can launch the service
and then just build a new adapter to switch
to this.
If, I would say that if we hadn't, if
we had realized that this was the order that
we needed to do it on, we, we would
have done this in two weeks. Instead. So that
first part of it was like a day worth
of work. That second part of it was like,
three hours worth of work. And deployed immediately.
The, the harder part was realizing that we
needed
an adapter. And at this point, people, we
didn't
really see anything about hexagonal architecture.
This might have
been before some of those talks and papers
have
been coming out. But, but it's actually really
useful.
Tests. We, we use Sunspot for some of our
Solar things. And we're already used to spinning
up
a Solar instance using a gem, trap-it-up.
You know
you can do that for your integration tests.
But
for unit tests, you know what, we have tests
around all of this. So we can have tests
around a fake adapter that proves that it
behaves
the right way, and then that just saves, saves
data in, in memory, in your application.
And redundant tests, you know, you might say,
eh,
do I really need this test? Yes. Because one
thing, you can delete your tests later that
are
redundant, and you want to be really confident
that,
that when you do switch over, it's gonna work.
Foreman and Subcontractor are, are really
helpful for this
kind of thing. So subcontractor is a gem that
really says, for this service, change directory
over here
and run this command in a completely isolated
Bundler
environment. Cause you really don't want to
mix your,
your dependencies. You don't want your server
dependencies and
the versions to be conflicting with your main
application
dependencies. You want to be able to, to change
those separately.
OK. So what about a new app? I'm spinning
up a completely new thing. Not extracting.
Totally new.
How do I do that? How do I iterate
on something that doesn't exist yet? And I
would
say that some of the lessons that, that we've
learned from this, and actually from just
doing our
product development in general is iterate.
Find a way
to get to the smallest deployable thing as
quickly
as possible, and whatever tool you use to
deploy,
to spin up infrastructure, one of the sort
of
heuristics that, that, that we've found is
really focus
on organizing that code around being able
to change
things easily, and understand how this thing
is different
from this thing.
You know, the Chef makes it really easy to
define a giant hash of global state over here
and then just run this thing over here and
it's magic and it'll just do it. When you
actually start to spin up different services,
this thing
is gonna need to be slightly different than
this
thing. So how can your code make that as
easily understandable as possible?
So feature flags, also, on or off. Do customers
see this, or they don't. But you know what?
Maybe it's just kind of half on. Maybe everything,
every request that's gonna actually call through
this, use
Sidekiq to just every time, just spin off
a
job to hammer your, your service. And if it
breaks, you've learned that before you've
launched it to,
to your users. There's a lot of other ways
you can do this.
On to these five years users, and let's see
how we can break it, see how the interaction
feels. It's, it's really useful.
Also, one thing that we found is, it's often
helpful to inter, integrate very deeply before
you go
widely. So, if you have a code-interaction
that goes
through all this process, do it kind of once
through all the process, without worrying
so much about
the edge cases or the errors, because those
are,
you're gonna find those. Those are gonna,
those are
gonna come up. But it's re- really useful
to
kind of go all the way through the interaction
knowing that it's really kind of sketch and
doesn't
do everything, and really let that drive the
design.
And this is also a thing of like letting
the feature kind of drive the design and figuring
out, what is the pattern for how you really
need to organize the code, before you have.
Don't
just like whiteboard everything and say this
is gonna
be perfect. You know.
Production is going to destroy every single
design that
you think you have. Also, if something seems
clever,
it's bad. If you're like, eh, this is kind
of cool. No. No, no, no. It's bad. Complexity
is gonna come to you. Don't, don't seek it
out. It's, it's, it's evil.
So if there are any kind of take aways
from this, I would say you know, hexagonal
architecture
is really cool, but you don't have to design
it from the start. If you have trust, if
everyone in the organization has trust that
you can
do your job and that you're all going, working
together to build an awesome product, an awesome
company,
you can fix this later. You can actually let
the needs of your product determine where
your boundaries
are.
So, thank you. I actually have a few minutes
of, of questions, to answer questions.