Placeholder Image

字幕列表 影片播放

  • Decoupling Applications from Architectures - Jeff Hoffer

  • Hello, all right.

  • Thank you everybody for coming.

  • My name is Jeff Hoffer, and my talk is decoupling applications from architecture.

  • I gave a talk on this side last year and there was literally 10% of the people in the room

  • that there is now, so thank you all for showing up.

  • I really appreciate it.

  • The lights are really bright so I can't see anybody's face, which is probably a good thing.

  • All right.

  • So a little bit more about me.

  • I've been professionally developing software for 20 years, and I recently joined a company

  • called bluebeam.

  • It's for the design bid and build phases of projects.

  • You can find me on GitHub at @eudaimos, it's a word I made up, kind of.

  • It was inspired by Aristotle's eudaiminea.

  • The inspiration is my son Eric who's here with my wife this week, if you see us around,

  • he's nine now, please say hi.

  • So it's appropriate that I work in a software company for construction.

  • I notice that as human beings, we've been in the practice of building things for a long

  • time.

  • We built some amazing things that have stood the test of time, beyond which most of us

  • can even conceptualize the length of that time.

  • And with software we've come up with a single-most malleable thing which we've ever had to build

  • anything, and it's been pretty great.

  • But still there's something not quite right.

  • When I worked in Santa Monica, there was a lot of construction nearby all the time, and

  • as we were walking our VP of Engineering, my boss used to point out how quickly they

  • could build these buildings versus how long it took us to deliver software.

  • [laughter] So how do we keep ending up here?

  • [laughter] We either build it too slow, we build it wrong,

  • or both.

  • And how does that happen?

  • We get asks from people who don't really know the difference between building application

  • and building it well.

  • But they want to make sure that we don't build it well, sometimes.

  • That' d be great.

  • So we end up in this Kobayashi Maru scenario and for the younger folks out there who haven't

  • seen Star Trek II.

  • It's designed to be a no-win scenario.

  • It's there to determine how we will respond, and unfortunately most of our responses are

  • this.

  • [laughter] Where the needs of the many outweigh the needs

  • of the few, right?

  • And then we get back to our brittle code.

  • So what do I mean exactly by application versus architecture?

  • So we should probably define this.

  • And we can take a step and define it based on who defines each for our software.

  • Product team will define what the application does, engineers will build it, QA validate.

  • Engineers work with software architects to define the needs.

  • They build the architecture, QA validates nonfunctional constraints.

  • So I'd like to take this and define these as layers.

  • So we have an application we call that the development layer and architecture is the

  • architecture layer.

  • And if we can organize these into layers, then we can separate them like what Docker

  • was able to do for apps in DevOps.

  • There's also four aspects of software.

  • Taking another view here, what an application represents to a user, how it does its job,

  • where it executes, and when it does what it's designed to do.

  • Unfortunately, when working between the development and architecture layers, we commingle these

  • four aspects into a kind of a mess.

  • So let's go back to our layer definition and define them using these four aspects.

  • If we say the development layer is the what and the when, and the architecture layer is

  • how and where.

  • We can organize them this way and if we can organize them this way, along these layers,

  • and make them orthogonal to each other, then we have the decoupling we're looking for.

  • So if we take these aspects and graft them on to our layers, the development layer has

  • what the context of the application is for a user, when does a user go from one context

  • to another.

  • architecturally how will the app move from context to context and where will the code

  • reacting to this actually execute?

  • So if we get into the details of that so that it actually matters to us who have to build

  • this stuff, we can borrow some concepts from computer science where we say the what these

  • contexts are signals, when is triggering and the reaction to these signals.

  • And the how is -- and the where is a signal network and the implementation of where that

  • signal network will run.

  • So I want to introduce a few things for the demo first.

  • There's RealWorld.

  • If you haven't gone to realworld.io, it's beyond a standard to do app.

  • It involves conduit which is a Medium-like blog platform and there's lots of concepts

  • which are integrating different front ends and different back ends all doing basically

  • the same functionality as this Conduit app.

  • I also wanted to introduce TAO.js.

  • There's a project that I've been working on as a solution for this.

  • It has a meta language for defining signals that end up in the code, using trigrams.

  • It provides interaction primitives to determine when to interact with these signals

  • and it implements signal networks.

  • So a trigram, the library TAO actually comes from term action orient, so we want to describe

  • these contexts with these three dimensions.

  • So term is something, action is an action taking place, and orientation -- orient is

  • a perspective.

  • Three ways to interact and respond to signals is inline, do them in order.

  • Async, do it in parallel as a side effect.

  • And intercept is do it first and optionally you can interrupt the flow.

  • And implementing signal networks, it abstracts that away from the application code, and it

  • also has the implements a signal chaining, so that if you are reacting to a signal from

  • the network, you can provide it with another signal that will chain itself, so this gives

  • us very small bits of code that we can implement now as it -- using the signal network as the

  • medium for the interaction.

  • So taking this back to our notion of aspects to layers and now to TAO.js, what we're able

  • to do with the development layer using TAO.js is the powers that engineers use to define

  • these trigrams and define the desired behaviors when these are signaled in the signal network.

  • The engineers implement these behaviors in the code using these interaction primitives

  • on the signal network.

  • And the architectural layer, we allow the architect or whoever's implementing the architecture

  • to choose the signal network, and implement using that, and decide where that signal network

  • will run, so we've now abstracted away where the code has to run in order to interact and

  • provide the development layer with what it needs.

  • A quick note about trigrams versus an application context, so think of a trigram, it's a 3-dimensional

  • signal, also an event.

  • You can subscribe to trigrams on the signal network and it's like a class in an OOP where

  • ar application context would be an object in OOP, and so it's a specific context and

  • so it combines this trigram with the actual data associated with the event that's happening

  • the signal.

  • So when going through the real world conduit application, what we'll do first is define

  • the terms.

  • We have an app, user, article, comment.

  • We'll define some actions, init, load, find, exit.

  • We'll define the orientation so we have a portal and an anonymous orientation, so portal

  • is when you're logged in.

  • Anonymous is when you're not.

  • And then we'll define some paths.

  • This allows us to understand how to react to signals on the network, and then throwback

  • new signals in order to keep this chain going.

  • And this is why we also develop or define very granular actions, so that we can have

  • more granular chains and we can hook into these at any time.

  • So I'm going to go into the demo portion.

  • OK.

  • So we're going to start with our Conduit app.

  • And -- of course! [laughter]

  • OK.

  • Oh, I understand why.

  • All right.

  • Um, so this is working with their -- with the default API, which is using a service

  • somewhere.

  • And we're going to -- oops, wrong one.

  • Sorry.

  • Of course this all worked in the room.

  • (Whispers) now completely broken.

  • So I'm going to skip showing it as a ... because it doesn't seem to want to behave with Redux.

  • So it was a Redux React based application.

  • That still doesn't want to play nice.

  • Very sorry for this.

  • AUDIENCE: You got it!

  • >> Thank you.

  • I can't see who you are.

  • But thank you.

  • All right, let's just turn all of it on.

  • Anybody know which screen I'm on?

  • I can't imagine what changed.

  • Oh, I, yeah, now I know.

  • This is the best!

  • OK.

  • [applause]

  • Getting the applause for code you didn't write, it's, thank you!

  • [laughter] So this is Conduit.

  • This is the basic React Redux example I think probably the first one they did.

  • So we're going to modify this, time willing.

  • To use TAO.js.

  • So this is actually hitting the API for that, we can sign in, go to home page, so you see

  • there's all this functionality.

  • There's lots of ...

  • so this application has a bunch of reducers that we're used to, all the Redux boilerplating,

  • the components are React, they have a lot of baked-in Redux, so we've sort of embedded

  • all of this together, what these -- how we call the API, what to do on various -- within

  • various components.

  • So if we go ahead and -- I'm going to turn off Redux logging.

  • We're going to switch to using some alternative components and not all of

  • them are necessary.

  • So we notice, still looks the same.

  • Still works.

  • I didn't get that tab thing working yet.

  • We see the results change.

  • And the way this is implemented is -- so for the home, the original home is here.

  • It's home page loaded, home page unloaded, applying the tag filter, we now take and add

  • a handler.

  • We import a TAO signal network that is the default signal network, and in order to chain

  • a signal into the network from a handler, we use this app context constructor to return

  • that as a new signal to follow, and so when we receive the signal to enter home, we want

  • to tell the application to view home.

  • Alternatively, we use a data handler from the React library to capture data from a signal,

  • and store it where we can utilize it again in our render handler, and this -- you provide

  • it with a context to say any data handlers above, they create this context for me, I

  • will now have these available to me in my handler that I use.

  • It's a function as a child component.

  • And so when it -- this will react when we reach the trigram -- in the application context

  • that reaches the trigram of home and view and we actually don't care about the orientation.

  • So it allows for wild-carding, so if you don't provide a term, it's a wild card on that term

  • -- on that attribute of the trigram.

  • And so when we render the home, we actually want to use our home component.

  • This one's new.

  • We pass down the token, the app name, we get from the app data, which tabs are active,

  • a tag, and then what to do if they click "All" or click on the feed.

  • So this is a -- just a standard React component.

  • There's no logic or anything in here to interact with the signal layer, signal network and

  • we can treat our components completely on their own, makes them easier to test, easier

  • to design using storybook, and this works for many things, so this uses a main view.

  • Vue, and you notice that the interactions are -- there you go.

  • We pass down this "Click all" which will then --

  • this will create a signal into the network.

  • Actually, this is not implemented right.

  • So going in here and signing in, I come back here and see the signed-in view and we did

  • that with using a different header.

  • Nope, wrong window again.

  • So we have our login component, which is saying if I'm trying to view -- if I'm trying to

  • enter a user anonymously, I want to view that user anonymously, so that's going to render

  • -- use a render handler, user view, anonymous, and that will give us our login control.

  • When we submit, it's going to generate a user find action anonymously.

  • Because this is just working with what's already here, we have these handlers all defined around

  • users.

  • So we find a user anonymously, we have a handler for that, which will grab the email and password

  • out of the data -- out of the user portion of the data passed in the application context

  • to our handler, we will leverage the agent and do a login, and then based on how that

  • responds, we'll either get a user or it will catch an error.

  • If we get a user, then we want to enter that user in the portal orientation, and provide

  • the token so that that can be used.

  • So what's nice about the ability to have these wild card handlers, when we pass the token

  • and we're in the portal orientation for any of our signals, we make sure to set the token

  • on the agent every time based on that.

  • So we don't have to call this anywhere else, but it will always be accurate.

  • If we are going anonymous, we change -- we set the token to empty.

  • We also can react to initializing the -- so our initial application context will be appinit

  • anon, we can grab the token from local storage.

  • If there is a token, we'll switch to the portal view.

  • If there's not, intercept sends nothing back, it will chain to the next appinit anon.

  • That's when it will call load.

  • So using this, we now can refactor all of the application logic into these handlers

  • that are small and bite-size and easy to change, and we don't have to worry about how we're

  • making calls necessarily to move the user around the application.

  • On the -- not sure how much time I have left.

  • So going into the API side -- so if I switch this to using the local API -- let me sign

  • out first.

  • Clears the token.

  • And we also see, through logging these, that these chain to each other, -- now, let's ...

  • We'll use the local API.

  • Now for this, with the same user, we set up -- we convert these routes from the API where

  • instead of doing what it was -- what it had here, gets the user find by, it's going directly

  • against mongo, we can instead create a transponder on our signal network and what a transponder

  • does is just provide us with a promise when we set the context that we can await.