 How many of you guys have had a chance to actually or even knew that the rails com tutorials calm was a thing? Can you raise your hand? Okay, so like a few people so just to reiterate them again before we get going You should have ruby 2.1 installed on your machine If you don't know how to do that or don't have it just hopefully ask somebody next to you Secondly at least have the first repo cloned from this slide the applications first framework second You can also clone the chassis gem onto your computer. We'll be using it later So just in case you cannot connect to the internet and bundle You can clone it onto your computer and point it against the local install then All right. Well, I guess let's let's get into it So my name is Adam Hawkins, and I'm running this workshop called applications first framework second The content of this workshop is mainly derived from the blog post and things. I've been working on over the past year or so They were linked on the rails com tutorials.com website Maybe you have heard about it. Maybe you've read it. I don't know but what a blog post a series titled rediscovered the joy of design Which focused on more hexagonal concepts domain-driven design separation of concerns Things like that. I feel that's something that we desperately need in the Ruby community itself So this is the first time I've done a workshop with this number of people I have presented this content multiple times also in workshop format the first time I presented this workshop was to a group of Java developers actually with no Ruby experience and it was a alternate introduction to Ruby on rails So today I will now present the same material to a bunch of probably well-experienced Ruby and rails programmers So I hope at least some of you maybe most of you have experience working with Ruby outside of rails Because well, that's what we're going to be doing today, and I hope that's not scary, but That's where we're going. So this workshop will mainly go through a set of Small predefined steps. I've done inside the repo that hopefully everyone has cloned by now So we're going to go through a I think 12 or 13 step progression Depending on how the time goes. Maybe we'll do some live coding or what you guys want towards the end So in the repository there is a branch for each step. I think their name like feature slash Step one or step two or whatever now Also when we get going I have the slides which encourage you to do the particular exercise in each step And if you'd like you can also look at the appropriate pull request on github for the same For the diff or whatever However, I do encourage you to try the steps on your own if you'd like to you can look at my solution or whatever But if you like you can try to do this whole workshop on your own following whatever things I suggest in your own branch or whatever But the workshop will continue based on the diffs in my pull request So I don't know if you have looked at the code already on github, but on master It's where we're going to end, but that's not where we're going to start so how many of you were able to actually read some of the content that I posted in the prerequisites Some okay, some people okay, so We'll just Start here. I guess so how many of you attended the DHH is Keynote I think most people If you connected strongly with that keynote then this probably is the wrong place for you. I Tell that to you not to scare you away, but to be honest with you about what you will get out of this workshop Because these are things that I desperately care about and have experience working with and I think are important, but Members of certain areas of the community may consider these ideas and these implementations Over-architecting or what they're using now as Architectural astronaut or whatever But I have applied these material like these concepts and these patterns over the course of a few years and they have been really successful When applied to problem domains of a certain complexity So if you're interested in learning about these things great but if you are interested in working on like small problems and Don't necessarily care about doing the whole TDD thing then just be upfront with you then you probably will not enjoy yourself here So just a heads up or if you want to be convinced maybe it is convincing I don't know but that's just to be upfront and honest with you guys about what you'll be able to get out of this workshop So this is the blog post or the blog series and in this series I talk about the ideas as kind of hexagonal driven design domain driven design separation of concerns creating boundaries around larger parts of your application and things like that so One I don't know if any of you had been to the talk earlier, but there was a talk on like views presenters decorators like help me choose or something like that and He had a slide where he talked to DHH about service objects and things like that and DHH has said I don't I think that's a complete waste of time. I have never seen a use case for that in the wild Well, I tell you that they do exist and I use them all the time with great success So the blog post talks about how to correctly arrange some of these objects So just to get on the proper terminology with all you guys You may have heard these things called service objects I refer to them as use cases, but since the vernacular during the conference has been service objects We'll stick with service objects So a service object is just something that actually does what the system is supposed to do So it handles the user interaction or whatever then that takes input from something. I call this the form object so it's just responsible for modeling the user input and the service object used that to do whatever Now difference in how I do things now as I use the repository pattern Because that actually creates a real separation between the domain models themselves and how they are persisted How many people here are familiar with the repository pattern? How many people have actually used it in practice? Okay, so You'll learn how to do at least do some of that today now Unfortunately in order to accurately demonstrate these concepts We need a really big problem domain and that cannot fit in a workshop It cannot fit in a day or anything like that So just to be more upfront with you guys the things that we're going to do here Will be over architecting for this really small problem domain because that's the only thing that we can actually work through in this context So if you think that is over architecting then great, you are thinking the right thing if you aren't Hmm, you should You should rethink yourself so the point of this workshop is to Demonstrate a certain way to solve problems so you can use them on a Larger problem. I don't know how many of you guys have experience trying to Build an application completely separate of rails or anything if it's a web app or a console app or even the gem But I know for me in the beginning was hard to actually think of what my core concepts are what my thing is actually supposed to do Separate from what it's supposed to look like or where the data is actually going to live So just things to keep in mind if you have problems Thinking like that then hopefully this will be a good exercise for you now during the during the workshop I Would like it to be more of an interactive experience So don't just feel like you should sit on your computer and code or whatever Ask each other questions ask me questions if you want to go through the workshop as pairs I highly suggest that probably just to cut down on the bandwidth on the internet But if you have like somebody you know next to you then you know consider consider pairing So We're going to do something. That's very dumb and very trivial in a domain that we all understand Where are we only gonna have one? Model actually there's nothing else. We're just gonna have a simple post object and that's it so People I found are also scared of patterns in the ruby community. I think people have been burned by Java and things like that, but Don't be scared of patterns. I suppose the use of patterns on Problem domains of certain complexity and we'll see that here and it's going to be totally test-driven from the very beginning We're gonna have service objects form objects Repository and my gem called chassis to kind of organize organize some things on the outside of the hexagon if you're familiar with The architecture we're gonna use active record for the persistence. We can get to the end and We're going to use action pack to actually put this application online in the sense So this will be our interface to HTTP and HTML and all the things that actually put the thing in front of the user And with that it's pretty much time to get started so If you go on to your terminal or your command line, whatever Just check out like step Well, yeah step one I guess or your own branch from the very beginning But the first thing that we're going to do is Well, it's actually kind of hard to start at this point but Imagine you have a clean slate and you need to make something run test so Can you actually is there some way to go back to like the initial commit or something like that and get I don't know Yeah, so let's just me get this off for you so you guys can have a clean a totally clean slate there That fact actually totally split my mind. I'm gonna get I'm getting a shot. Yeah Yeah, that would work. Did everybody catch that So if you check out this step one branch and then did get reset to head till the two you can go back to the very beginning So now you should once you do this You should be like at a blank state and your job is to now set up the rig file so that you can run a test so a hint for anybody if you've never actually done this yourself from the very beginning in Your rig file you'll want to use the rig test task to run a set of test files and Throughout the workshop will be using mini tests because it is built in their library. Nothing else to install. Yeah So just yeah at this point you'd be in a detached head my mistake from the planning process But after this it will get easier and once again if you don't know or you're interested You can see the solution to this by going into the github repo and looking at the diff for this pull request or just by checking out the branch again So this is just a simple placeholder test that you can write doesn't do anything But just some way to verify that your thing is working So the question was well, we have to manually add a gem file and the answer is yes And that's because you'll need to put rake into the gem file so you can do bundle exec rake Right then also to test your installation. You could switch this assertion to say assert false and you should see one failure So once you have bundle exec rake passing. It's good Give you guys a few more minutes And we can look at the solution and move on to the next step as you can see you'll have your test You'll need a test helper What I've done is I've printed also a placeholder file in the root directory just called app That will be used to load all of our future code and Then we just require many tests out of run to run the tests. Okay, just to scroll up a little bit This is all you need in your rig file To get this going just in case you guys haven't got it yet. So You need bundler. You'll need to rig test task and then just use the bundled task to run all the files inside test matching this pattern and then let's just make that the The default task And of course you can also just copy these files from get up if you wanted to on your on your branches Okay, I think it's time to move on to the next part. So if you haven't figured this out It's no big deal. This part is really basically boilerplate code I put it in here just so you guys would be familiar with what it actually takes to kind of get this Infrastructure up and running if you have never done it before but if you like you can keep your work or whatever But at this point it's safe to We can just move on to the next step So this step is actually the biggest and most complicated part of the I think of the workshop Because it requires us to introduce a lot of concepts in the beginning that we may not understand but are required to Actually do the whole TDD process. So if you if you check out Just step two, you'll be you know at the end of step one so what we're gonna do here is we're gonna start to introduce a Like what David has called a system level test So in his keynote he was talking about kind of not necessarily going full unit test and focusing more on the high-level test So it's actually not so hard to start doing this but What we're gonna need to do is create a high-level test that represents somebody setting some input to our system that going all the way Through and then testing on What comes out of this basically so I mentioned that we're gonna have a Service object a form and a repository and then we also need a Model class for this one But unfortunately, we don't really have these concepts yet in our in our head. So this Probably is challenging But if you were to Start by writing a blank just a blank empty test imagine what it would look like to say Send some data to something have something process that data and then actually enact the change Now I invite you to take a guess at what this will look like just open a new test file say for example test it should create a post and you send a hash with title and text to something and See what comes out And you want to have some assertions that there is in fact a post or Something like that So this one is actually pretty open to your interpretation The important thing is just to take a stab at thinking about what these concepts would look like how you would interact with these things You know, I doubt you'll come up with what I had and in fact if you did I would be very impressed And that would be great, but just take a stab at what this would look like So once again to iterate you're gonna have at least three different concepts represented in this test that are not actually there in the system yet You'll have a service object that represents this particular functionality You'll have a form object that represents the input and a repository that represents the collection of objects that are going to be Managed, you know So you have at least those three things and some interaction between those and if what you come up with basically looks like how you interact with the Things in rails, that's totally fine. That's an okay interface, but just you know take a guess at what something like that will look like So I just put the three different like classes or object types that will appear in this test You know just take a stab at how they might be arranged, but these are the things that should be present So I've just updated the slides to kind of describe How my solution works Without showing the code yet I mean at the end of this we'll have a failing test it will fail because nothing has been defined I mean there it will be some assertions, but We'll have a test that fails and we can just iterate through that until it's green Yeah, sure. So just the question was can you explain some about the repository pattern and why you would use it? so the repository pattern is an excellent way to separate data access and quarrying separate from how it is stored at the low level so In this case, we don't have a database yet. We have nothing like that We don't know what we will actually want to use so for now It's just safe for us to say we have something that perhaps just stores these objects in memory or whatever We don't necessarily need to know how we'll just create interface to access these things They'll make it implement something that You know Implements the interface in its own its own different way. Okay, I'm gonna pull up the diff here for this one We can start to talk about it. So actually the the diff for this fits on one slide completely Almost can everybody see that okay, or should I make a little bit bigger? So We have a class just called post repo. Let's just We'll use that as a facade to interact with Whatever data store we choose We have our published post form just initialize it with a hash of whatever data we'll want to use Then once to initiate this okay, I call it use case, but service object, whatever with the form and Then we'll run the use case and then this has a side effect of actually adding something to the repository Which we can test with Refute empty and at the precondition we can say a cert empty just so we know that that actually has in fact changed something And we can get the first object from the collection and then test on its values Okay, so That's yeah, that's pretty much pretty much it and then yeah Question No, yeah, I don't feel it's really worth it. Sorry, I don't feel it's really worth it to inject that dependency. Okay Well because you do to the Nate due to the nature of it That I can swap out the back another positive over the place so Like when I'm doing tests, I just use it in memory implementation of persistence So I don't necessarily care if it talks to that, you know, or even a null implementation. I don't really need to inject it Everywhere for me. It's just safe enough to say, okay I just want to access the collection of data and Searching kinds of tests I can say that data is just no worth in memory or it is data-backed or whatever So yes When the repo Well, we'll see it We'll get more into this and further further down but just for now It's just the placeholder for the thing that we'll fill it Yeah Yeah That's because this is also just due to the fact that you can swap out the back end for these things So what the constant is there for is basically a facade to a larger system So it's easier as easy as to just continually work with that facade as a constant and just use it Yeah I Had thought about that but not necessarily because sometimes this execute method takes is a different signature just in this case it has no arguments but Usually when I compose the source objects, then they may take a block or another object, but you can't represent with just a lander No So The full construction time rather than just passing it to the execute method, what's what's your sort of decision-making process? Yeah, so That's because usually what happens In the confectrophies objects, they take in two things one being the form and the other being state Which is like the contextual state which is most likely most often the current user and in some cases I found that there is some other Information that may be passed at execute time and not at instantiation time It's more of when if you have a use case where you have to pass these objects around You may not have the that information when you want to call it So what you when you compose it you can say okay? Here's this thing and then eventually you can just execute it So it depends on how you want to interact with the objects, but that's what I found works the best Investor here and in some cases. I've actually created like I just a class method Just called like post like published post on execute instead of having instantiate from then execute just depends on Yeah Yeah, so it's So the point of this step was just to create Something that represents the high level interaction and of course these concepts aren't there yet in the code and actually what you notice Is that the post object? Is old it's not actually referenced by names only comes out in post we do post repo that first Yeah, that's your question probably not actually Well, yeah, so this is what I mentioned earlier for this particular example I'd say it's not needed right like for this problem domain this level of separation abstraction is Over-architected but only a way to demonstrate how it work is in a very small example Yeah, I mean the main benefit of having this separation is that when you have say very complex input has to be interacted on And then multiple office has to be created or whatever This is just a way to see what kind of that arrangement will look like anybody asked there any questions No Okay So The first thing we have to do now is actually begin to create these concepts. We've run this test. Nothing will actually pass now There's implicit dependency between the post repo in the post class itself So that's the first the first place to start So your goal for this step is that you just check out step 2 which is this integration test now will exist Your job is to create a test that you can instantiate an object called post with a hash of Title and text right and then assert that those things are safe Once we have the domain entity now we can connect it up to the other things So if you need questions or help send something up just ask and make myself or Ed whoever can come over and Just put an example here on the slide how you can run a single test with many tests so The test you have by doing this will have one test for the post and one test for the integration test Naturally the integration test won't pass yet. So you maybe want to just run that test that test you've written is working So you could just say Ruby test So for this test or probably just have a test class name for example post test and then cite that one method that just instantiates this class assigns a hash and then say You know should have these things and now you have to decide how do you want to actually declare that this class should be able to encapsulate this data You know what think to yourself. What is actually the simplest possible way to do that? Yeah So the directive was to create of just to create a new test file That instantiates an instance of this post class, but you now have to define and that it is Nislized with an hash and then you just assert that what you had passed in and now it has those attributes, right? So post dot new title this you know assert equal You know whatever and then you can run your test file in the command line But just saying Ruby and then path to that test file I use keyword arguments when I know there's a small set of things that actually want but in this like initializing Initialization case. I don't go with the keyword arguments Yeah, and then you have just duplication and also keyword arguments and supported on JRuby yet So I don't know if I don't know if they support Ruby to yet or whatever. Maybe not completely but Ruby to feature I They were I think they were were Refined a little bit in 2.1. I'm not sure. I but yeah I'm gonna go ahead and skip to the end here on this one. Oh, we can just go to step Yeah, so this one I actually did in two steps So the first one was just to Let's see Yeah, just create this one simple test looks like this Lay quite trivial Next thing which is to make it pass and you can do this by redefining initialize with this hash each pair and with some Meta programming, you know, it's okay, and then just simple at your accessors You don't you don't really need anything else with anything else than that Don't need to think about like types or anything. It's just it's just data. So At your accessor is completely fine for this So the next thing I did this is where I start to use chassis now just for some little helpers look at the final diff from this and what Used to exist inside that custom constructor is replaced by this Initializable module and chassis so use that all over the place. So I put it in there So you write enough of these little classes you do that stuff all the time can be encapsulated in a module and just use it so Does everybody understand what happened in this in this diff? Yeah, so now this is the point where we actually probably have to go and forward out to bundle again now So hopefully the internet is working or you have a chassis now on your computer Locally So at this point at this point the integration test is failing because there's still no post report things like that you know, so If we look at step four We're gonna kind of punt on the post repo now because we need to go to need the Published form so at this point you need to create an object that that is this This form basically and it can also be initialized with a hash and it should be able to encapsulate the same The same data and at this point if you want you can write a test for it But I don't find that there's one anything so useful to test so Just create an object called publish post form and It should be initializable with the hash not necessary So the forms only have one code the forms don't have any other Collaborators, so the forms so this is kind of the unfortunate part about this example is that we can't necessarily Illustrate the full power, but what the form objects do or they encapsulate the user input and potentially do Coversion and things like that so for example like right now. We're working with just strings. Okay, but let's say that we have Like a date or a more complex object, right? This will come across as a string or a integer or God knows what right? But when we work with this we want to actually have an instance of time, you know So for example, if we just pass this junk into the form object and we call dot date We get out the date instance and that's all that we care about so that's what those things do And we actually in a few steps from now We'll see how we can do or how they interact with the validation of things like that yeah sanitize model user input for a particular interaction and The service object gets all of the like input from this particular object and that's a There's none Depending on how complex your use cases so in rails we talk about form objects as something that is Well basically mapped directly to an HTML form right because there's a lot of problems modeling complex data with HTML forms usually have an object that represents it and That just generates a more complex params hash maybe which just gets dumped off to a model or something like that So the slight difference is it how they're actually used because when I've how I've seen them used in rails Is they're really just to make kind of generating the HTML easier and Then that just gets you to the params hash, but you maybe don't interact with that object again, so In this case we only model all the input to our system with these objects Yeah, so this one is really straightforward so I Put a hint up there to include chassis dot form This is why I mentioned you guys should at least peruse the gems read me before and what this basically does if you haven't used it Is provide more a little sugar on top of the virtuous library Who has used the virtuous library before or know about it? So the virtuous library for those of you I haven't used it is a way that kind of does this Sanitization and things like this it basically gives you a way to declare attributes and what types they are and that they should be Coerced and things like that so for example here. I could replace this with say Fix-num or float and if I assign a string version of that it will come out as a float And you can write your own like coercers for more complicated objects, you know So if you have say complicated embedded object or things like that you can model those easily with with virtuous and there's nothing related to test because the Like the initialized initial initialization behavior is provided by the library so as long you just have this class It's you know, it's it's enough So we're getting to a point now where we can actually Start to make this Integration test pass so if you check out step four, you'll be at the yep. Sorry question. Yeah Okay, so this is a good question Now Reason why do the coercion there is because all input goes through those objects If you do the coercion and whatever like validation or whatever at that point Then you never have to worry about where the data is anywhere else. Yeah, but then yeah, potentially in this case it would be enough to To use this in both those cases if this is all the data you have So you're not necessarily have one form for both those interactions depending on what data is needed for those interactions Maybe use the same object. Maybe Maybe not so they're also the reason why it goes to this one place is because maybe you like You rely on the fact that the models if you notice before we had simple after accessors in the model, right? They don't worry about anything else. What kind of data types those could be by going through this one place We verify that at that point all the data is correct. So once the data enters our system We never have to worry about it again well now after doing this for a long time and kind of knowing what How of things tend to develop I just do this from the very beginning Because from my experience it always approaches the point where I would need to start doing this So instead of having to like retrofit it into an existing application. It's just easier to start The other reason I prefer to do it from the very beginning is when you have the repository You're not bound to thinking about persistence in any way. You can just work on actually figuring out the interaction between your objects and the public interface that you want and I Find that it works out. Well, I Mean even if I were if I were to write a blog I may not use this exact Things I might not have a form But I would still have at least an object that represents posting this thing and I would definitely use the repository The thing that might go out first is the form object because if you just if you really do have that one-to-one mapping between All the things then perhaps you don't you know need to have to Yeah, so at this point We're like one step away from me able to get actually to a failing assertion in the integration test And at this point the thing that's still not defined is the post repo. So if you had read The read me in chassis. There's an example of setting up the repository so the goal for this particular step is to create this post repo and You know set it up and you run the test You should actually get a failing assertion at this point and not a like undefined Object or Whatever So if you can't access the internet you can do bundle open chassis and you should be able to see the read me there What do you mean my micro test? Oh Well, it depends. So this is I think somebody brought up this point earlier about why is it a constant versus an instance? so internally the Repository in chassis is built on top of another concept called a strategy So the repository in chassis defines a very basic interface called, you know like First last all empty like create update delete whatever and by default it also generates a null implementation of the interface that just does nothing and Chassis also defines an in-memory implementation. So for example in in some tests I can say chassis repo dot use null and I don't even care, you know I can say chassis dot use memory or So depending on how I want to run the test I can also switch it out So I run the entire test suite against a database to see if that's coming incorrectly or or not Does that answer your question? Yeah, we're in the right place now. Sorry. Yeah, I hit the arrow key on accident Also, if you press the mouse button, it still advances the slide when No, actually When you include chassis persistence includes chassis initializeable as well But even so you don't necessarily need to implement that particular part to get this step passing Like you're once that you're a couple steps ahead, but that's that's good. That's okay So let's just look at the diff here if everybody's cool with that. Let's see number Five Yeah, so that's it just create this class extend with this module and I Called the pulse repo. Yeah, that's it. So What the chassis repo delegation module is just setting up some kind of helper methods to a more low-level interface. So we are creating a Fassade object for interacting with the collection of posts. So the next thing to do So at this point if you're to run the test you should hit to the point where there's no published post thing And now it can do the next step so the next thing is to okay guess now check out step five and Implement a version of Published post that instantiated itself with the form and has an execute method, right? And then you should get a new failing assertion All right, and just again don't worry about what goes inside that execute method Just get it. So when you run test now, you should get like Some something else. I don't know. I don't remember the next the next air or the next playing assertion in the Yeah, yeah, yeah Basically what we want to do is just you write write the test and then Maybe it fails for some class. We haven't defined. Okay. We just put that there We just keep going until we get to an actual assertion and not an error and then make that assertion pass So then at that point what you should see is expected a post repo not to be empty because if they use case Hasn't actually done anything to create this post The time is the workshop and is it 410 or 420 you guys know oh for 30, okay? Yeah, so this one is Particularly pretty easy the only thing that maybe you haven't seen before is this little micro gem and called Concord, which is basically a way to create Hmm It's the equivalent of say reading of writing in depth private form and setting an instance variable named form in the initializer And you're right do that 10,000 times. You don't want to do it again So it basically defines a private at your reader named form Just a heads up on court on concord. You can also pass an array or up to three different arguments So you could say Concord form and then current user or whatever what have you So now the next thing to do is actually implement that logic So if you were to check it if you check out step six now, I believe is that we're wrong Make it pass now Pretty much so you mean you have you have the date like so I'm glad that Ed actually mentioned that chassis persistence thing Because you will need that you have the form which models all the data Okay, you have the post object which has this initializer you can assign the things and By including chassis persistence now it responds to save an interface that you're probably familiar with Just go to plug in a few lines inside the execute method and You can check out step six if you want to oh Out of habit at this point because I have when you as you I don't know if you have a tent if you attended the sending mess talk But you know if you as you begin to create more and more objects more classes that encapsulate their own private state becomes annoying to have like Definitialize with the value of value and then assign an instance variable and then do depth private someone and so on So perhaps for this particular workshop it might have been a mistake But this is just now my habit at this point So you can also refer to the chassis read me for the things added by the persistence But basically what it will do is connect the post to the post repo and supply a few methods so at this point You should be able to run one lozek rake and all the test should pass If you've implemented it correctly Oh Yeah No Well, I mean actually you Yes, actually because like what you would which we the first thing that we would we had written the very beginning was Definitialized hash whatever that's still there. You can still just dump in your Yes Not with an instance of form because that would it doesn't know what that is right Right, but if you happen to if you if you do happen to know that Virtuous doesn't know about attributes method. Yeah, right. You could say post doc create form of attributes That would work in this particular case, but I don't I don't Vise to think like that No, it's not too racy. It's just in You have to be aware that the input that you collect from the user does not necessarily map one to one with how you interact with your Domain entities and what perhaps that what the service on it actually does, you know If it happens to be able that you could just like hash a hash around when that is just the coincidence So in some cases you could use like hashes But that's not necessarily a thing that you should consider like I should just be able to dump hashes everywhere Because it's not this way productive No, not so the post model sees right because it so this is the game like why this thing is kind of a bad example because there is that mapping You know, but let's say for example, we're talking about like a shipment order that perhaps has like three or four things And there's a bunch of coordination processes. Maybe you're creating like five months. Maybe you're sending emails, you know so Yeah, right. So like if you happen to have say a Like an address or something on a form, right? It's probably okay that you could pass it off as a hash but maybe you have some Like some permissions and maybe you can send emails like you need an index stuff in different services, you know, it's just Basically, it's domain domain specific by this step Are you explicitly declaring the title and the text That again so like in this step in this poor request, which one hello, let me just print up the disk So now we're on my number seven So it's the iterating so just do it instead of just doing the iteration through the attributes you declared in the form You're explicitly stating that here Yeah Yes, that's so that comes back to my point there about not necessarily Like yes, it'd be possible in this case, but not thinking about it So like if I were to if I were to say, okay, let's just use as we attach in this sign it there Then okay, then maybe that's what you guys take away from this But I do I pretty much do it this way now in all of the cases because there is not the direct mapping and and perhaps I need to interact with this data Beforehand before signing it somewhere like You just have to make the you know make the decision based on what you wish you'd need to do But the reason I put it like this is just to kind of show you that Don't necessarily think like that like just take the piece of the parts of data you need and then put them where you want Right Address Yeah Kind of right because that when you use the nested attributes you only get to hash like you you have Like an array of hashes or just a hash that gets assigned to Like the model of the thing receiving it responds to like, you know Comments attributes equals hash, right? But in this case you would have say a Like a comments collection or something a higher level concept so to give you an example to show you Something else here so this is a This is what I where I've worked now it's a classified site, okay, but when you actually Like post a class post an ad in our site you can send for account and where's the bunch of actually other models inside that so There's an ad there's properties. There's a contact card. There is accounts. They're just passwords, right? Now it may not look obvious like at this point But there's a lot of stuff if we were to fill this in you have to input all that different data And all of that data is encapsulated with one single form called post ad form Inside that there is an ad form. There is a contact details form There is a count for all these different things and then the use case then interact with those individual parts of the data and then You know, maybe it creates a record. Maybe it does something else Right and that's that that's the real thing to take away from from the workshop is that These techniques are really only useful when applied to a certain level of complexity because you will not see any You know real benefit if this is you know, the only thing that you that you're working with But when you do have like more complex data like nested things that have to be transmitted and you know Then this can only be powerful Yeah Do you mean like inserting them into a legacy application I have found that there is some there is some value depending on what people know about the application itself and It of course the answers it depends Sometimes it's just simply too hard to do it But I have found that there is some value in isolating the other parts of the things like if you if it is like for example You know in a rails application, maybe there's some gigantic controller. Maybe you know What happens at some point you need to say? I need to use the behavior for this one action this controller in some other place right you need to compose some behavior So if you're able to extract the logic out of that one controller You could then test it and then reuse it in another place I find that most of the most of the benefit in the legacy applications comes from Being able to encapsulate the data access that's I found in rails applications That's the thing that's most easily abused is you have like active record API calls everywhere or mongoid API calls Yes The question that you just asked was exactly what motivated me to kind of go down this road as well And the scenario was I wanted to share I was writing a new API pop-up of existing rails app Which had a ton of technical debt. I wanted to build an API and not have to Repeat all of the mistakes I made will build in the app in the first place I kind of follow these patterns and pulled pulling code out of the Legacy app and then we're using it in the API and having not moving the duplication so I didn't approach it with the intent of improving the legacy app, but I approached it with the intent of Using these techniques to pull out the common pieces and make them testable in higher quality code And you had success with that? It's still in that journey, but so far yet And it depends too because I get this question a lot and there is a certain amount of prerequisites That you have to have in the code base before applying these things kind of makes sense Because this assumes that you're able to isolate those concerns And in what do we call legacy applications? Usually that is not there So there's a bunch of prerequisite steps you have to do One really good example is my friend of mine is putting another book called Rails Refactoring And he steps through like refactoring controls and a bunch of these things So it kind of gets you into a point where you can start to apply these different approaches So we were, yeah, there, so that's it Like if you were to run the test now at this point everything passes Granted like it's really quite trivial, but it does pass Yeah, basically by default, like I mentioned earlier, there's a few packages and implementations But this is a memory based implementation that basically destroys everything in a hash So No, it's just an instance Yes Sorry, I must have missed something In terms of how's the post getting into the post repo? Yeah, so if you, so I did a bit of a different implementation Okay Where I actually created the new post instance And then called save on the repo Yeah, that works as well So the only difference is that chassis repo defines save To delegate to post repo So for example, when you include chassis persistence in a post class If you call save, it will look for the matching thing that has repo at the end of it And then call save Okay So that's it So, yeah, yeah, you did it the way the low level way Okay So applause to you, sir Well, yeah, because I was going through the document Like, so the read me doesn't kind of talk about how those Well, I guess it does Maybe I can read it pretty well Probably it doesn't Because I haven't been able to communicate all of my intro Sure Yeah, I just opened up the delegation class and sort of saved me Yeah, so now that you saw the delegation class You kind of understand what that's doing Because the public interface to the repository Like everything either has an instance of something Or a class and an ID So for example, repository find me post with this ID And what the repo delegation thing does is I have named post repo So I will just insert post in all of the correct places So I can say post repo dot find And not have to worry that there is this other argument being passed around I'm interested in your design decision on that In terms of why not sort of show explicitly that they are adding it to the repo Because it gets really annoying Like when you, it depends on how much data access you do Like if you just have to do say find for example The word has become really powerful Which unfortunately we won't be able to get to in this workshop Is we need to find queries, right Like custom queries So for example, in my blog I talk about if you say I want to find all the popular posts, right On your post repo you could define a method called Like popular or whatever Which then makes a little little call To do, you know, to do the interaction Whereas if you didn't you'd have to say Okay, now I need to go in my use case I need to go to the, whatever the repo is I need to call query with this class And this like query object That just kind of eliminates that boilerplate And recently I had to do some I read a repository to interact with the legacy data source And I needed to interact with the low level During the test And after writing a bunch of tests I got so sick of that But it's there But it's much easier to work with like this facade I found Does create accept a hash Yeah, yeah, so So you've gone kind of like a solicitor But you could have called form.actual To pass into the create Right, yeah, I mean the initial So basically initializing bold Makes things behave the same way that like Active record or active model So you're going to pass in a hash And then you're going to pass in a block Which yields itself Yeah, so the next step So if you were to check out step seven The next thing to do is we're going to handle Bad input case So implementing validations So this is one place that I found We're having a form object So it starts to shine Because as your application grows We'll have more and more complex Validation concerns, right That may be like context free validations Like is the title more than three characters You know, or whatever But then perhaps you have more context Like, okay, I am the current user They're logged in, they have some permissions Like maybe there's these other things You know And you can kind of encapsulate that stuff in the form And allow the form to be manipulated by A service object which kind of encapsulates this stuff So what we're going to do in this step Is take the existing integration test case Add another test that says You basically call this thing With an empty form And that some failure mode should happen You get to decide at this point What that failure mode actually is But the fact of the matter is If I try to put a form that has nothing Into this service object Either there should be an exception There should be something But nothing should happen So a hint here for this one I'll just put it on here You have to take a stab at defining What the validations Like what an interface for validations Will look like And remember at this point You can't think of, say Active model validations or anything like that It's up to you You have to implement this particular functionality Yourself and whatever interface that You know, you see fit So just to reiterate on the structure The form encapsulates the validation The service object will ask the form Hey, are you valid or something And it will do something That's up to you to decide Yeah, but I added that If you had checked out my branch It's there Or if you just add like Deaf teardown, you could say I'll just put it on the slide here In case you haven't done it So that's like total reasoning Yes Because for this case This is what I mentioned The difference between context-free And contextual validations In all systems There's always some context-free validations Like for example This post form always requires A title and a text The form encapsulates that validation That's there all the time And then in the published post Perhaps you check to say Okay, maybe there's Maybe you have an example But there's too many published posts right now You can't access the information on the form So my question is like So the way that I've been thinking about The I guess published posts More or less access Some type of Bottles, like then Right where you can do the execute You can like exercise it So like in Rails You would put most of your model You would put your model validations Inside the model So we're exactly So if you're trying to put the validations How do you stop it And actually don't get it into the published post Like because you can just You can just pass it whatever form you want In the published post right Where exactly do you put these validations And have all the posts on that That's for you to find out But if you're thinking about Say instantiating this object With a different form In terms of the real application That should never, ever even be possible Right because you're never To say that you were too exposed to the web Right it's not possible for you to Like create some form And it's going to be a different object And pass it into the web I mean the point of adding the validations Is that the behavior that The published post object should do Should not happen if the given form Is invalid right So you're going to need at least Like you need once So you need the integration test That says okay I'd send this blank form To the service object You know something should happen Then that creates a need for the unit test So you need a unit test for the form That says this is an invalid case So for example this You know if the title is given But there's no text Should be invalid and the opposite You know the opposite way around So like in the integration test You don't necessarily have to be concerned About all the potential different ways Validation can fail You just can create a Failure case And then specify those behaviors With unit tests Alright so you have a few options Maybe inside your Publish The published post class You can say okay Hey form are you valid Then return null or something right You can treat it as an exceptional Exceptional case Perhaps it returns some sort of Air object I don't know right But you just have to determine Some interface for that So yes question Yeah I'm just thinking from like So this is kind of like Validating attributes What about What about actual business rules What's your sort of approach to that You still put those In the actual domain object Yes in some cases So You've mentioned The third validation case Okay so you have the context Free validations You have contextual ones And then you have these sort of Business level violations Like for example Let's say that you had an order Or a class that cannot exist Without a billing information Or something like that Inside the Well actually maybe Like maybe like when you try To ship an order That hasn't been paid for So you're Yeah so you're kind of triggering this Ship on Yeah so then in that case I'd have this kind of contextual Like this either contextual Or whatever you want to call Business Rule validator That would exist in the concept Of the ship order Sort of subject And in the ship subject Yeah so you have So you have the Validations on the form And then Whatever kind of business rules exist For that particular thing Right A class inside the service object That Encapsates that information But then you like Really don't have the domain model anymore Just have a Data structure But it's not the object Well not necessarily It depends Because On how those objects Interact Like for example I had a A case where You have An object that has Like an An action block For example all of the things That had been done to this And there is a defined A defined Set of interactions So this was like A review And it had a log object And the log object Implemented those methods To call this person Approved it This person received it So on and so forth And that begins to Create a more richer domain Model to interact with Which can be used by The service objects And the other things That collaborate these objects So I tend to Call less a lot of Like that kind of object That you're talking about Inside the service object Used for that Particular interaction So the Model classes are usually Usually just data And then more Higher semantic Access to the data So what sort of Do you end up in What sort of custom methods Do you end up adding To your domain To your domain So like Potential state transition Things Associations Go there Like interacting with Like a comments collection Or associated Like billing information Things like that Basically Things that operate On the data Promote it And then Something else Will control the access To that Like if you're Pulling out the business rules Aren't you From the business From the From the domain model The business object I mean you're essentially Sort of breaking Encapsulation At that point, right? I think it depends on Where you want to define I think it just defines Where you want the information to live I mean I have found that I mean If the business rules Validate Business rules typically You know I mean They can shortly Validate attributes But more Other objects Again coming back inside here Of Of shipping an order This shouldn't be Shit that's what it's paid for The order object Knows if it's If it should Right, so Sorry Because then You would sort of Have to ask, hey Order, are you paid for And You are Okay, then I can Shift Shouldn't you really Just say, hey I want to Shift this order And the order In that case Usually I do Put that logic on Those objects themselves Right So Kind of confused there So one of the other things That Comes up is that You have some Also domain level Like business level Invariance Right Like you can't Have an order without a billing So inside the Those objects I will just check to see If those things are set Right And it's still anything else You know Because in some cases You Like they have The public information That is like Assignable or whatever And then perhaps What should happen To eventually Create some objects And then those objects Have their own invariance Which are not Publicly accessible So you have to put In some checks Into those objects To ensure that The things that are Collaborating with them Do in fact Instantiate them The right way Right Because it means Like an order Like an order should Have at least One order Right, exactly So that kind of stuff Yes And I mean That's a great question And wait Having gone down I'm not nearly as far along As Adam is But in down this What I found And I was asked Bob Martin the same question I think you just asked And what he's noticed I think it's a lot Like what Adam's saying Is that The The domain entities You will end up Being somewhat anemic In terms of behavior Other than say Data type things And then When you have business rules They tend to evolve into like Policy objects Or other things So the business rules Are still in the domain But they may not be In the specific entities And that's not something That I intentionally did But as things got refactored That's kind of where The design In my case Seems to be headed And it kind of makes sense So if you've got Business rules around No, it should be You know You can't order it And have it shipped In the past Or something like that Then You know That could be a policy Or access Particularly users Are able to do one thing But not another That would be a policy And that kind of makes sense So the responsibility Of enforcing that business Rule Is really like a policy Decision In your domain layer Rather than being In that entity Yeah But I guess What I'm saying is though That the order should be Responsible for enforcing That policy Because that policy Might change And all the other Business objects interacting With that order Shouldn't know Shouldn't know if that Shouldn't know The reason for The order Not wanting to ship Right Because it might That might change over time Right So yeah So one example is that Well, you shouldn't ship In the order I'm sorry You shouldn't ship In the past But you shouldn't Soonly not ship That It shouldn't ship If it's A badly paid for Right But that policy might Change So the And the order knows Yeah And actually Of course it depends On the complexity of such Policies If that's the only rule Then of course You know, Perhaps you can live Over it if you have More complex policies Then maybe You need a policy Object And now What are they getting more Until like DCI Right But I guess It would be like You could sort of A policy object But the order Should be delegating To that policy So yeah A policy That represents What the thing Can and can do And that has passed Around to the Like To the very apartment System That need to be aware Of these things Okay So Let's get Back on Trek So where were we We're now On this one So Almost like Half on our left So I think Want to Pick it up now Kind of take More control Over where we're going To have this Integrates with rails And I don't know If you guys have The Like Low level experience To kind of Hook wire these Kind of things up So For this one For these Validation cases I prefer to Handle these As Invariance Kind of in a way So I treat Validation Failures as Actual Air Air conditions So for example In the Post form Define Something called Validate And then Just say Fail Validation Air Title blank Less title So on and so forth Very trivial Implementation of what It looks like And then Up inside The App The RB file Just to Clear this Validation Air Concept that I can use And then The Service object Just calls Formed on Validate So This sort of Raises this particular Air And Go on about our business The reason I prefer to do this Is when you create Like the delivery mechanism It's easier to capture the Different failure Different failure modes Of the particular interactions Also I never expect An interaction to Fail Like if I Were to instantiate this class And call it I don't want to be aware That there might be a Particular Failure thing that could happen But of course You have to be aware That if you're going to Say compose them But say for example In tests Or when you re-use this Class in different places Having like Validation errors And things which are Like false For example can be Very problematic In the long run That's why we have things Like save bang Inactive record So if you just Need to make sure Something's there You always have to be Sure that You do this Otherwise it just Will not happen Silently Pretty well across Multiple applications And multiple applications Yeah So then There is your Okay and set up Yeah We did it here Because at this point When you have two tests You do have to actually Wipe the state From the previous one So at this point If you were to check out Yeah Step nine You would have Like a Fully functional system So you could create a post Then you could have Handle a potential Aircase Now at this point We could connect Our application Up to say The web Or anything like that So this is where it Starts to get More complicated So I did it In Step In Step nine So this is like a really Big commit because Rails is introduced here But what happened is Due to the nature That Rails takes over So much of your project Sure And things like that Instead of fighting it I basically just gave up And accepted it So what happened Is all the files That we had in the app Have been moved into Lib Slash domain And what was app Is now Lib Slash domain And there is an Initializer That requires Lib Slash domain Right So all of our Domain covers Just loaded At Boot time And then Let's see here So yeah Require domain And then if we just keep Lib domain Right now we have Lib domain And we have just Moved those into Lib domain Things continue to work Now the one thing To remember here That if you do do this That code is not auto loaded Right You have to require it Up front So that does also Create something You have to be aware About If you're going to Separate it like that One option would be To say Put these like Create some say Like App slash Posts Would be auto loaded However the reason Why I didn't do this Is because you may need Some classes that Now exist in the framework Context only To say kind of Adapt and connect your Classes into However it is You want to serve them up Which is what we'll see Going forward So Yeah Just Add rails Nothing has changed You can still run the tests And they still pass So you could check out This branch On Yeah in future Check out Step 10 You could bundle this like Rake And it would still be the same So the next thing To do Is Add a failing Acceptance test For the user Interaction So at this point We can say Okay Now I have this form Object I need to be able to Go to some web page Type in the title And the text Publish And then You know My post should be Safe And practice Do you Other way around Other way around Other way around Yeah So I have My We'll see this In the next In the next step So What I've done in this Particular pull request Is just Test that I can visit some URL And type in these things And it happens And this happens With capybara So How many people here Have used capybara before Anybody Okay so You're Familiar with it So basically Some things And like That's pretty much it You know Just require capybara Rails And insert the dsl here Right Now we could run this test And you would hit a phone Insertion Because This I should Oh I'm actually on my computer I'm sorry I thought I was looking at Yes Okay So Sorry about that So we have our Published post test And then just Visit this thing You know Like you would expect Fill in these things We should just see What we filled in There On the page And then just Require capybara Rails And the test helper Also note that The previous test helper Was erased By the Rails one So That's there And then just Include the capybara dsl So You run this It fails Because this thing Does not exist Right So This is where it Starts to become More interesting In terms of what you Have to do That interaction Inside Rails So Okay So we're moving Some things So Create the controller Inside Now we're going To instantiate This form object So we can Actually In hindsight I didn't use it In the view yet But the important thing To pay attention to Is the create action Which basically Looks like the same thing You've had in your test So What We're talking about Rails as a concept Of a delivery mechanism So in the concept Of like Exogonal And the separation Of these things You have your domain And then something That is used to Make that accessible In some particular context So In this context We're using Rails For this So In here The post controller Is our delivery mechanism Now Of course The publish Post has no idea What The particular User interface Should be like It isn't to decide that So in this case We just said Okay We'll redirect to Post path And then Use the repository To find it And render Now Here I have just punted On the Rails form stuff Because Rails Does require you To insert a lot of Conventions Into the objects To work with the form Helpers So Just kind of Went around that And added The low level stuff So No form Which is Writing the HTML Ourselves And then We have the show template Which just renders The post Information to the screen Okay Routes Had to Change those here But that's That's Really All it took To get that passing So you could check out this And run the test And it would Pass But we've only Actually At this point Only implemented half Of the application's Because we know that They could only They could not fill in Those things And of course The domain That would raise an exception Which has to be handled So that's what we do In the next Over here So for this one Same thing Yeah So this one Creates a Exceptions test For the delivery mechanism Such that it can handle This particular Aircase So just visit the thing Press the button And then just say that Okay The air should be displayed You know So This actually Exposed an interesting thing What I continually Forget about Every single time Interact with The HTML forms Is that if you Fill in a If you don't fill In a form You don't get Nailed in params You get an empty string Right So Found That out Because for us We just say Return unless Tight up But an empty string So it passes validation So in this case Updated the unit test To say Okay now this particular Validation case is handled And update the form Do I do it in this one? Yeah So you can say Title.2s.strip.empty This happens to work Because nil can be Coerced into an empty string Strip removes all the White space And empty checks to see This is pretty much Exactly what blank Is doing in this case You know So Found that out And It works So hopefully You wouldn't actually Have to change the domain In this case But since we have found A new failure case We have to account for that Now Yeah So Any questions About this stuff So far Okay So I will Show you There's Two things left We have to cover And I did The reason I did it Like This Was just the basic Yes Yeah So When you're validating You raise an exception Of the title's not blank What about The title And the text is not blank You won't It'll short circuit that Right You won't get a Neurocapacic So this was The most basic Particular example Okay But when I do it In practice I use a more complex Like a validation scheme So you can actually Collect The failure So not just Abort at the beginning Yeah What are your thoughts On the inclusion of Like If that's how you want To implement validations Then That's good You know Go for it You know See That part I disagree with Like if you want To implement the Validations Let's say I'm not going to Be demanding And things like that Then I disagree Because then The domain Is aware Of a particular Delivery mechanism Concept Not exactly So that's what I'll show you Now So the reason I did this Was the simplest thing That could work without Having to Understand that All the things You have to add To get it To work With the Railsform Helpers So I don't know If you guys have Done that before I would prefer To use that If I could Because the problem With this Also the limitation Is that Those values would be You know The user interface Would display Nothing So Um And this has come Back to Your initial question About name spacing So instead of Name-tasting Domain I name space On the delivery mechanism So for example The Rails stuff That is particularly Used to Connect these classes Is now The web names Is now in the Web name space So I've created this Um Web Published post form That is implemented As a Delegating class Right So what it does Is wrap the existing Like domain Constantly used And add all of The Rails-specific Wiring To get everything To work So I'm not sure If you guys Have seen the Delegate class It basically creates A copy of Just the public instance Method to Fund that particular Object And exposes to them And you have to instantiate It with an instance Of that object So Instead of sub-classing Right If the particular object Had a bunch of Functionality from the Superclass You don't pull that in You only get The title Equals And the text Equal things So then you Include the active Model Naming thing To make it all work I don't know Some reason But Nail is good enough for us Something to deal with Some I don't know Generating URLs Or something like that But since we can't Generate those manually anyway We just have To pass it in here Right And now we can call F.text-filled And F.text-area And whatever The only thing Missing from this Is that you don't have The active model Areas However You could If you wanted to Like Write an adapter For your domain things And translate them To this If you wanted to Depends on the use case Like for us Right now it's okay And we just have Simple error message And That's all But Yeah And then This also changed Because now it's inside Web And it's called this The IDs are this And then up In the Controller Now We have to say Web Published post form To work Like I haven't done this So much In the context of Rails But you could Probably encapsulate That particular Thing In some module Or something Like that You know I think it would Work out Well The only thing To do is The Potentially The errors But that depends Particularly on The application How you want to Display them And what kind of Requirements Are The Air collection Is limited Because if you have Nested objects Which I tend to work with a lot You can't say Pass down an air Collection Into a nested thing And kind of Collect all of those Things Active model errors Expect each object To have its own Air bucket But that doesn't Necessarily work For a lot of Mindless cases So Anybody have any Last questions About This? Okay So we have The last remaining Like bit of this thing Which is now How to connect this To persistence Right Now this will be Like even More over architecting And even more Like duplication But the point Is just to illustrate That yes You can do it And I have A bunch of information And a bunch of topics On how to do this Particular bit This is a whole Another topic So Yeah So this is Actually the first The first time For persistence For a repository Using active record Usually I use SQL Because I don't Work in set of rails And I find that SQL is actually More powerful Than active record In terms of The core interface So There is a lot Of boilerplate Code kind Because you have to Know internally How to create Your own adapter Or your own Repository Implementation Through chassis And some things Like that But basically How to boil So What I have to start With Is define a class Called post row And then just Self table name Equals post If you Don't need to have Post rows table And database And also Do it here Because If you Active record Assumes that all Of the objects Are in the Global namespace Oh You got Dammit Oh I'm so Sorry Thank you Maybe I should just Like mirror Something out But we're almost done Anyway So you have This class Post row, right? So it's just A distraction With that one Particular row And database And say Self Table name Equals post Because You know Don't want to Have a post Rows table Now I would prefer to Implement this Like And since we have Our own concept Of what a global post is We have to call it Something else So this is Starts to have Where kind of the What magic happens But I wouldn't Recommend doing This kind of implementation So We have Our active record Repo Which subclasses The chassis base Repo And There's some Boiler plate To kind of Get all these Things wired up But Essentially What it boils down to Is you have A source And I've kind of Just short circuit With that Because you only have One In this particular case So we have Clear Which we'll just Do and destroy all Just work everything And we have Create Which will just Take the Attributes from the Post And create a new Post row And save it And the most Important thing is Now you have To sign this ID Right So it makes It makes sense So you have A source And a database And all So kind of A sort of Circuit here Just loop over All of these things Call my favorite Thing Bag of Hashes Pass it around And instantiate A new Domain object And then Happens to work And you have To implement Like first Those kind of Things because By default It will just Call all That first So you can Do this Post.new Attributes And then Some boilerplate code But essentially What you have to do Is something That instantiates Right to row To a database And then With the right data And then gets it back So then here In the initializer We can say I want to register An implementation Of the repository Using my Active record Repo And then We're going to say I'll just Use that So swap An implementation For the Active record Based persistence And that will Just affect everything As I mentioned earlier You could say In CI I will learn To get Subpected record Or whatever It is That you wanted And then Now we actually Have to create a migration To do these Things To add this To the table And then We get the schema Stuff And clear And if you Were in the test Everything And the whole system Is none of these Just the Definition for the Active record Repo? Yeah, sure Oh, okay, right Yeah Oh, but that That's Specifically For Products Right, so This is what the Mapper does So This is why The class Bargainers Passed down to the Repo Because then the Mapper could say Applement a RDMS Mapper But if you had more than One model What would it look like? Would it get like Because you're Configuring it saying There's only one active Repo Right Yeah, so Yeah, that's The purpose of The Mapper So you would Oh, okay Right, so you could say Given This comes in I use this thing And I use that So in practice Depending on Like your Particular notation Say you might have A Mapper For each particular But for the In memory Mapper Just Is a hash Just in For a new thing Do a hash Based on the class Right, so It's simple, but In practice I've found that You end up creating Like a Mapper For each particular Type of object You want to persist Which is Just how I've done it But most people Have been asking me Okay, how do I Create Like Say I Want my post Like that Delegation thing Uses There's nothing That says You only have to use One instance of repository This is just How I've been using it And that Actually That sums up All of There is So I mean At this point You have everything Like it works We have Active record For persistence We're using Rails to deliver it We use the Rails form helpers And I mean Granted It's kind of janky This is not Good code, right? But it's just A way To kind of show you How this would be arranged And the one thing I do want to caution you Against Is that In terms of the duplication That if you do Implement Stuff Like this And then you have Your Ugh God Like your migrations Like things You have a lot Of duplication So there's some strategies I've found to deal with That I might be happy to talk To talk about them Later But Does anybody have any questions About this stuff? You just have a few more minutes Yeah So You're using this Kind of Yeah You're using this In a real production application Oh yeah What science team Are you for your new Because one of the Issues that I'm just You know Kind of running through My head is like All of this stuff Is like very brand new To me And I wouldn't exactly Know Like the right way To integrate this Into a whole team Unless everyone Is kind of on board In the same pattern If you Like introduce it slowly Or You know If it's something Well in my current So to give you Some background On what's going on Currently I'm in the process Of breaking out An extremely large application Rails application Into a bunch of smaller Applications And Some requirements That come in From the business They want to create more Things Which we haven't been Able to add Into this existing model Which I've done in this Style Which comes with The education thing You know It's just What does your team know I mean The only reason it works On Rails Is because They all have the documentation Right So Have them read Some books On hexagonal stuff Have them read Some blog posts And it's You know It's okay And if you If you Look at this Like the spectrum Of the architectures Usually the more Complex applications Have different parts Of all of these Like the Blog posts By Brian Bellacamp The Seven ways to Factor the Active record models He kind of Introduces some of these Concepts You know Like Horry objects Form objects Things like that But they're not Just say Arranged in this way You know One of them Is also like Extracts for this Object So If you Were just to dump it Say on a Brand new person Using it I haven't released I haven't released A public Version of yet But I've been using In production now For a year and a half I'm just I've been Refining the Extractions that are in there Mainly the one thing That's remaining Is how easy Is it to implement Customer repositories And like Nappers And things like that How stuples Go to the stories Depending on the area The only thing That's going to change Right now Is the repository I haven't really But I am planning to Take a good look at it Because now I'm sure To get more people using it Then they're going to Use some feedback But The public interface Hasn't changed It's only the Internal implementation That's changed So if you have created Your own adapter Based on some Knowledge of the internal state Then You might have problems But the public interface Has not changed at all George and Shassi What is that Offer on top Of purchase Yeah Right now The only thing that it does Is It blows up If you try to send That thing junk So I've taken that position That I want to be very Bitchy About things Like If you send me shit I will treat you like shit And I will blow up It's easier Right You don't have to worry About like These random player cases So if you do Like at virtuous If you don't have An attribute declared And you try to send in Say foo It just So if I If you send Foo to me I blow up Right And the reason I do this Is because First of all You don't have to worry About say Like these mass assignment Problems Right Because there's no Private state Directly exposed Anything So I like this approach Because it forces you To keep the clients Honest The things that are Sending Have to actually map To what's allowed So if they do Try to send you shit They get shit back Like so Like cases Where you really need The clients to send you Correct stuff So I can just Capture the error That's raised Say like an application controller And just say 400 Dad requests Not allowed to send This parameter I don't have to ever Worry about Handling Jump Or anything like that At the moment That's really The only thing That it does And it I think it defines Like a One other Method But that's That's it Learn something And maybe you'll have Some confidence Try these techniques Out in a Larger Larger domain I suggest that you do Read My series of blog posts Called Rediscovering the Joy of Design Which you can find On my website At hawkins.io And also My series That I'm working on Right now On implementing And using repositories So it comes Covers Pretty much Like private Internal implementation What's it like In a larger application What's it like When you implement Your custom adapters You know Per class Persistence requirements Just What's the stuff like In the real world Not in this Little micro Aquarium And if you have questions Feel free to From me After the conference Or on Twitter I'll be happy to Answer your questions Thank you Thank you Thank you Thank you Thank you Thank you Thank you Thank you