Creating a Clean Architecture Worker Service Template

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
alright happy Friday everybody let's get started surly dev welcome ok plan for today is to take this clean architecture sample which has been fairly popular it's got 3,200 or whatever stars and leverage the new asp.net core 3.0 project types that are available yeah you gonna watch the stupid ads sorry twitches lousy with them the worst is when you're like trying to raid somebody and you can't even jump in to talk to them after you rate them because you have to sit through a minute of an ad you got to get it a get-out-of-jail-free card for the ads I have to go after a raid wonder if all the Rangers have to sit through that - they probably do all right so I let's see let's create a new tab here I don't think I have a github repo for this yet well it feels like a minute I don't think they're there really a minute maybe they're 30 seconds they're not short it's not like 10 seconds all right so this clean architecture yeah 20 30 seconds longer than I need if I'm just trying to jump in because you know when I raid somebody all the people show up if they're gonna say anything about it they're gonna be like oh thank you or jealous for you they're gonna say it within five seconds it's not you know I mean it later when I finally walk in 30 seconds later or whatever alright so I don't already have a repository for this so in the next hour and a half two hours my goal is to have a fully working repository for a worker service using Donna core 3 out here in github for people to use so step one is create a repo so we're gonna do that so and I'm gonna clone it so I'm gonna create a new repository and we would call it clean architecture worker service because I think that's what it's called let's make sure I match the template and if I wanted to create a new project and I said I wanted it to be a worker Service Worker service yeah that's the one so call it that I mean architecture dot worker service sounds good description and a solution template using clean architecture for building a net or what their service boom all right I'm gonna have it read me and we get ignore that's gonna look a lot like visual studios we're going to say steal my stuff if you want and yes please we'll set up an azure pipeline alright create that Shirley Debbie left dude no I'm just talking to myself alright so now let's clone this thing so come in here it says as your pipelines was installed but I don't know where oh there you are you're back alright you disappeared from the chat already so we're gonna clone this copy that and CD back and get clone that thing alright now I already have clean architecture cloned so the question is yeah you should you disappeared from chat for a minute I'm sorry I blamed a blamed chatty here's my here's my chatty alright there's you there's me and there's the stream element spot and he doesn't talk much so I was feeling lonely alright so let me pull up the clean architecture one so I have that as a reference point so we go back open that one make sure I've got latest now I've got latest ok eventually I'm gonna have all the same stuff over in the other one hello from Azerbaijan welcome it's probably mill the night there what time is it you get 10 hours ahead so maybe it's 10 p.m. 11 p.m. all right let me close all these EPN sense of it okay you're only +8 I have not been to Azerbaijan let's just start from a new solution template let's just do that so go here we'd love you man all right thank you I create a new project it's a empty solution I think it's not still thing blank solution there is blank solution next and we'll call this architectured worker so if it's I'll put it in the right place the hardest part about creating new solutions just getting all the folders in the right place I really don't make it easy so I want this I want that solution file to see to be in this route so let's create that ok and what did that do on my file system it did did it do everything of course not no of course it wouldn't do the right thing it says oh let me put this subfolder for you no I told you I want you in this folder so annoying all right now I can't use this anymore so all right and while we're here let's create our subfolders we're gonna want I'll have source I'm gonna have test and whole reason why I'm creating is template because I don't have to do this every time so that's the idea commander route Jeff Fritz still going strong maybe when he's done he'll he'll send some people my way all right I need some class libraries these are gonna be net standard libraries for things like core and stuff like that so we're gonna add a new project it's gonna be a class library done that standard c-sharp sounds good I'm gonna call this mmm yes what should we call this what do I call it and the other one I call it clean architecture core I do let's stick with that that way someone can just rename clean architecture if they need to and do that everywhere will say clean I can texture that core and now I'm gonna have more than one of these clean architecture things I might pull that stuff that in the other solution here that's a shared kernel all right there I might pull these things out into an actual separate shared kernel because this isn't meant to be something that you would pull out yourself not something that you'd leave their location should be in the source folder and that's fine and create alright let's create a solution folder that matches that so solution folder for source I'm gonna put this in there and I'll add a new solution folder for tests and while we're there let's create a new X unit test project I've seen it just project and we'll call this clean architecture unit tests location tests that looks good all right now this is gonna need a project reference on core so we can write tests for that eventually okay now let's add infrastructure up here I'm not really doing this in any particular order just eventually I need to have my three main projects and then some test projects this should be a class library and we'll call it clean architecture that infrastructure and we'll say that needs to go in the source folder and it needs to depend on core as well now we're ready for our namesake project type of the worker service and this will be I guess clean architecture dot worker it seems reasonable I'll put that also in source and create me as what I had docker support just went out I don't think we need authentication well yeah that doesn't give me an option anyway so ok so an empty template for that perfect great that alright so make this the startup project and it'll give it a reference reference reference to core and infrastructure it's gonna wire up some dependencies know know what those dependencies are yet but we'll we'll figure it out maybe a logger or something like that ok eventually I want some other kinds of tests but this is looking pretty good so that's let's do a commit what we get out and see if it actually builds and folks that are just joining our goal for today is to take this clean architecture solution template that is fairly useful and popular in my opinion and create a a similar one for worker roles ever sorry worker services in Donna core 3 so I just created this repo it's empty you can grab it from here if you want and then a couple seconds it will no longer be empty back here and go to the right place I'll just add all the things see if bills here ok so so far doesn't do a whole lot but at least that 10 minutes that I just spent getting everything in the right places or saving somebody that much time at least looks good looks good alright so clean architecture has at its core an entity for it to do item it is just really basic useful functionality what would be a really simple worker usually these workers want to like read from a queue or something like that and then through some work maybe they write to a different queue could write to a database I could throw in any framework in there I don't want to have too much stuff in there for people to rip out so I have a DB context in here because most done the core web apps are going to use that but I don't know about worker service what all should go in there so let's think about that anybody have any ideas for basic throwing functionality to start with those I do you think I'm gonna want an interfaces folder probably and I think I'll probably want logging and I am NOT a huge fan of taking a dependency on loggers from the framework in my core project so something I will commonly do is have a logger adapter in there so let's maybe think about that do I do that in 15 architecture I don't think I ever did so have an ilogger know it doesn't do any logging so that'd be a thing in configuration settings could also be another one I often see folks that need to do configuration what's and that's one of things we get with this I have this worker when this thing runs and it creates this host one of the things that configures with this default builder is configuration so let's maybe look at how we could have a settings file that we use and that could be in core so what would be would be some settings that we could have for this let's see let's first just run it verify that works and then it will add a logger I'm partial Sarah log that will make it so people can easily strip that out if they want workers running yes there we go oh and this is doing it with docker isn't it container tools because I said use docker mm-hm but I could also run it straight right so let's run it without docker then it still works okay awesome cool Aleksei more Kovan hello how's it going alright so I think I want to create a new interface for a logger adapter and I'll start with that so they had a new item interface no so I want an ilogger adapter and part of why I like logger adapters is because I don't like depending on Microsoft's ilogger of T it's difficult to test because it has all of its stuff is extension methods so if you try and mock it and all to verify that logging actually happened it's it's a real pain so when you Inc URL here to throw in to the sample in case anyone cares that's really slow my site is slow all right so add this right here and the kid actually while we're at it I can steal some code from that article which I just closed so let's look at this ilogger adaptor that I probably have in here somewhere there yeah I like right after of T even okay let's steal those then we'll steal that in a minute at do I need the T I don't know sure it's always a good time for tea I really hate that that drops down copy there we go that's in here we're going to say we want a what a log right after my writing when it takes in whatever I log R of T all right that's fine so blogger adapter of T like that needs that needs the dotnet stuff Microsoft extensions lawyer and I'm okay to have that in my infrastructure so yes install that okay so with that I should be able to add sirrah log somewhere and I could just have a sarah log logger adapter here but I think I can use this to push that in from the front so let's take this rename that here alright and then our worker this thing takes in an ilogger which if I want that to be an ilogger adapter that should just work shouldn't have to do anything except maybe change it in two places all right let's see if that works now well that needs to be a thing long information you take you took args now I know what happened to all right yeah take args so I'm gonna go over here and I need one of those on this and a my adapter it's not gonna work that's okay cuz I'm just gonna add this that that's fine okay no let's see what happens boom it blows up why cuz I didn't tell it how to wire that thing up alright my service worker doesn't know about my lawyer right after all right so we're gonna add that when someone says of T such as an ilogger of type t yeah there's referring to the code such as ilogger t yes when I say I like heard after of T I'm just pronouncing this that's how that's how I say that that's a lager adapter of T and if I wanted to be specific well I can't really be specific in this case T could be just fine anything let's say like this T it was actually a type of lager you know I could say of you know T lager right and that would be that would be fine all right so I gotta go in program and configure logging or configure services services a single tone type of log area adapter has done that type of well your adapter hopefully that works okay so I need a namespace for that a namespace for that all right one two three one two I can't see that was there there we go hey TBD gamer TBD to be determined gamer huh alright so let's try and run it again see if that did the trick it's doing some weird scrolling but it is working so that's cool let's see if I work are actually calling the lugger yeah so it might after is working perfectly so that's good let's do another commit done we clean up some of these useless usings and eventually we'll get some tests that's good that can be cleaned up this we don't need yet sorry about the ding all right so we're making pretty good progress let's commit this got some things all right now for me when I'm building something with this this is my UI right so I really don't want to put a whole lot in here I want the actual work to be done to live somewhere else and in this case that should be in my domain layer in my in domain layer in this case is the clean architecture core area so let me think about what would be a good thing to call that I mean it is basically the service that we're gonna do and I don't know what that is for anybody's random work or service so I have to come up with a good name for it it's almost like the entry point for the app folder we'll call it services and I guess I could call it entry point service is that horrible and then anyone can call that whatever they want right like they can rename it easily does that need an interface no no maybe probably wouldn't hurt I think you probably be registered as a singleton but what would it need to just need an execute method maybe so what does this worker call execute async so I can have an execute a saying that that sounds good let's do that I don't need a cancellation token because this thing is gonna cancel it's gonna loop so I don't need the looping logic I don't need the cancellation but I would do on the same execute a sync I think here right so it's casing and it'll create an interface that has the same thing and so say public interface I entry point service has a task executes a sync I can't highlight it like that and it looks good let's pull this into its own file and then make sure it's got all of its own using statements and it's happy I'll just snag that go over here and inherit it implement go and you need some stuff also that and then you should just wait on something or what when we await on I don't know probably want some kind of infrastructure II thing that I could listen to hmm is there a simple nougat package so it would be like a queue in a message queue that I could put in and then I could easily throw in a indifferent implementation that we using RabbitMQ and Azure queue but this would just be like a in-memory mock queue or something that's probably what this thing's gonna do every time right it's gonna be like read from the queue do some work all right that's probably it's its whole goal in life I do think we probably want to add some logging on this so let's give it a longer and longer adapter of me that and then in here we could say something similar to what this will say when there it's better to build the log stream like this or the other way it's probably better to the other way if I'm using like a structured logger maybe he wants to be able to filter based on the name of the service so let me not do what I was just thinking there instead let's do service running at time and then put the name of here that's supposed to be helping me out with entry point service there we go alright we're having them Q dot fakes early dev says library contains fake implementations of client interfaces these are intended to be used for testing not dependence on that could be a thing let's look at that thank you you didn't give me a link making me Google stuff just simple usage see use cases in the project all right don't see excuses so in the tests there it is these cases send or receive messages who aren't perfect I know it looks like a real thing okay yak two leaves that oh you did like yeah you did okay sorry my bad I'm an idiot all right let's see I can totally pull this in and use it we're gonna get back it's for this I like this idea let's go over here it's good this guy managed nigut packages browse around and Q dot fakes sounds perfect let's install that alright and let's add a new folder will call it messaging and I'm gonna want some kind of an adapter for messages maybe you have interfaces I can use not really your message fake connection uses an eye connection and my connection comes from RabbitMQ I'm guessing this was done at core notices full framework mmm there might be a problem so RabbitMQ what I just installed client I'd really like it to be core only yeah I don't think that's core that's full framework that's not standard at least maybe it'll work I don't know we'll see okay if it ends up needing full framework I'm not gonna be happy but I won't give it a try and I just want to use it let's try our use case I want to receive a message it's using in unit and your server configure binding send a message there's a lot of code here just feel like it messages back and forth okay but this is good because this is gonna have stuff i could configure and I want to pull configuration into this thing too so that'll be good and really I mean if this is all this thing is doing where's the server if the server is just creating a couple of dictionaries of of queues you know maybe I just didn't put this myself and don't pull the dependency on RabbitMQ because that'll get me out of needing to depend on full framework be nice if I had some compatibility with RabbitMQ though what I'm done that's a big interface maybe I'd do something a little simpler so that's gonna you know huge amount of stuff to have to implement so to send a message what I need is the message and the server to connect to the server I need what this has an exchange looking for all the strings I need I need the name of the message I need the name of the queue and username of the exchange is that what I need so if I had some settings that had the name of this queue in the name of the exchange that would do it figure cube binding where's that declare queue declare exchange bind the queue to the exchange all right that's probably probably sufficient again we're just trying to put in something fake so that we can verify that works and and have something that people could swap in so maybe I need an eye what are the odds that they're going to need to talk to a bunch of different queues all right if I come in here and I have like an i q-- receiver in your face right that works with anything whether it's an azure Q or RabbitMQ q QQ let's see what we did and you shop on containers because it has rabbitmq where we're smart enough to put in a nice interface for that I hope you found charts API gateway event bus we have another cue building blocks there I that's very specific to evident queue and your your face there yeah coming in best event bus I know what's consuming that thing all right so it's got a default connection and a default queue and they just hard code that in yeah that's still a lot of code I don't think I need all that code all right so for me to receive a message I could just say the message is a string and maybe I want to specify the queue that listening on but not necessarily the exchange so get message from queue string queue name something like that it could be something easier easy and then this could be IQ sender and this could be avoid a task this could be a task of string it's gonna want to be async I'm sure task of send message to queue string Q string message if I say message to queue does it make sense for us to be queue first and then message it should be messaging in queue message to switch um I guess I'll just adjust that later if you want all right so let's pull these into their own files all right talking if that anymore let's go in here now this thing might need to do stuff with cubes maybe needs to read from one cue and send to another cue right so let's pretend that that's what we're doing so we need an I do you receiver you receiver I'm supposed to complete that for me thank you and that an IQ cinder cinder like that like that okay so I was that was controlled out a couple times to make that happen and I have a tool that's I ran sometimes I can never remember the name of a tool called Karnak iconic here we go so now when I do something and I say told dot oh yeah shows up cool maybe that helps some people service running at time okay if you know how to make it not show every key no I did not configure it still show us every key probably makes a less than use for it but there's a configuration somewhere here so we got auto update where's it gonna store it only show display only show keys that have control shift alt or Windows I think that's what I want all right my show keys listed in a key maps folder I don't know what I have listed in the key maps folder so I think I think that's good so we saved that and we get this thing out of my way now if I just type hi this is just some and I say control dot then that shows you that so there yeah yes TBD gamer I did figure that out all right I need to add that to my list of things to do so add that carnac to stream checklist which I don't think I've blogged yep I need to blog my stream checklist alrighty we don't got another point we're rating any tests yet but we're getting there quickly I think that's what this execute async is gonna do but let's get back to where we can run things so I want to make sure this entry point service runs in place of this worker here and so I want to pass in entry point service entry point service sign it there I didn't call it here entry point service dot execute a sink no it's not that I'm so cute a sink and a little weight on that okay I don't need that and we'll still do this but maybe this delay could be coming from configuration as well so let's put enough to do comment there so I don't forget and if delay to app settings all right so my vision for app settings which aren't done yet but let's let's think about this is I think there's gonna be a logging session that's fine I think there's going to be a entry point service settings which someone can rename later and that's going to be right there and then I think there's going to be a worker settings like dance and that's going to be here and one of those is going to be the delay till they seconds milliseconds milliseconds yes that is what I want to pull into this magic string magic number here at some point so this logger I don't really need anymore so it's just that I guess you know what I do analog when it first starts so let's do this log area let's steal we had from the other place here and it's only run once not every time inside the loop but it'll say service starting that time time well it still needs the service name I call that for now I guess we'll call it clean architecture River service I'll figure out a way to pull that out so that magic strings not there I will do that and then let's also report when it's finishing what is it just ending is it finishing is it crashing that's what's stopping it so stopping starting and stopping stopping at time all right see if it still runs I probably have some more di to do then I do it so I need to wire up our entry point service to work you're unable to resolve a entry point service of course so in here I'm going to add in Cyrus's add via single tone I think there's only one of them of entry point service entry point service without the I there we go you know I could use JSON for my app config for private network you know solve some issues yes yes you talked about your checklist a few weeks ago yeah I have one I just it's not share it anywhere yet it's on my backlog to share I need I need people to bug me people bug me about stuff I'd do it nobody's bugging me about sharing the checklist all right let's see if that fixed it not fix everything what's your problem now some services are not able to be constructed I ain't your pointed services singleton implementation was resolved IQ receiver oh well that's because I don't have any of those it's me getting ahead of myself all right so let's add our services for that so I'm going to add a class let's call it in memory to receiver so it's good you accept that responsibility I need you I knew you would Thank You receiver that's how you spell key right boom and what are you gonna do when you get a message from the queue absolutely nothing for now we could probably log it maybe use a return something return no return native task you're trying to ask us J so test that result just up from result and T result is strange I don't run that'll run will build and then we want the other one right of a class in memory G we send her IQ sender and you just do nothing supposed to be a sec I think I know wait this I can and then this can just do nothing all right any warnings probably right yeah look at that let's say a wait you receiver topped get message from there hi River warning cool this one wait what task completed task so the thing was I mean wait that I mean I can't all right good I'm just getting rid of warnings just whispered you about blogging alright I'll listen for that whisper I don't see it anywhere though I wonder where that goes apparently I'm immune to whispering um alright so this can go in its own folder as well its own file as well good there's that all right I know I guess wired them up so back to program yes let's configure services getting count along I probably ought to pull that out at some point everything's a single tune which I don't really like I may want to change that at some point like you see first that's in memory cube receiver there we go that and that single tune that doesn't go there it goes there perfect know about the sender okay oh you tweeted me too okay fine and I will check I'm all about the attention on Twitter okay so that builds can we run it though we can all right so everything is working and we've got some Q's set up we don't any tests yet that'll be next on our list but that salt looks good so let's do another commit what did we do here what is staged we get an entry point all right so we move the work to an entry point we added some queue implementations all right so that's starting to look better now I think we do you want some tests and so we need some behavior to test if you don't have any if statements there's not usually a lot to test and so or some kind of conditional logic right maybe this thing really ought to have some check that that things are not blank right that could cause an error and if there is problems in here yeah a tests that's right we want to raise an exception from here probably that we would log all right we'd like to log that air somewhere so I think we could probably throw this whole thing here into a try block and then catch the exception here and then log an error before throwing it further and it might be that we don't want to throw it right this is a worker service we might want it to keep going or we might want it to crash and then let asher or whatever we're running this thing in spin up another one I probably I would probably want to let not let it blow up right I would probably want to just log the problem I hope that somebody was actually paying attention to the log so I think I'd leave this is coming it out and put up to do here to do decide if you want to breathe through which will crash the work their service okay but in our case we want to log it so I'm going to say log r dot log error and we're gonna pass it in the exception and the message which is I don't know I can't really add anything of value here necessarily then any object args that I have access to which I don't think is going anything too useful I don't have any parameters that came into this method so really I think I just want that and the message give an error simple error here saying what is it entry point let's do this that's a mean of entry point service dot I've executed I don't know had an error right raise some exception leave an exception good enough good enough for a template you can always change that to whatever makes sense for you alright so in here I think I want to try and read something off the queue so that was this logic hold that up here put that up here and then do some work would also be up there okay now a little bit premature with this line because that's what I want to test so let's write a test and that test is gonna go over here and we're gonna add a folder called core and then we're gonna do the test in there and we look at this test in this test it's gonna say entry point service execute async logs exceptions encountered all right so de John Calloway I think that is the John Calloway it's kind of a big deal rename this to that and I'm gonna want to fake a logger of T which I happened to have already in this blog I think right adapter or did I just use mocks I just use mocks alright so I'll just use a mock that's fine but that means when I need moq which is fine add you I accept all the things I clearly read everything that that License Agreement pulled up just like you all do it yeah I'm not sure we're gonna keep rabbitmq fakes let's let's take that out for now I don't think I need that it was a good idea but it's not done at core alright so in here let's just do everything in the test for now so logger equals and what we need no queue we just control dot and this in particular is an ilogger of this thing I need here that's this ilogger adapter actually of that so I need that I don't need that I don't mean let's get rid of some things I'm not using alright so here's my test and this is my thing I'm mocking that all right control dot all the things we've got amok all right okay now at my service it calls a new entry point service with and that logger right the logger down ok ok and then I also need mocks of those other things probably and get away with I should I do it with null totally right here right do that and then this can be an async task because it's exeunt it supports async tests and then I can try and run this thing I could say await service execute a sink and then I expect an exception from that no actually I expect a logger from that so I'm going to swallow the exception so I'm gonna call logger to verify logger it is it fair expression action right well L dot right bug air that's what I want it is any really it's not any it's really a null reference exception but it is any in all reference exception that'll work I don't need it to be a specific instance of na reference exception I just needed to be an all reference exception and the message I don't really care what the messages if there's any string because I don't want to changes in the message to break this test and I don't pass anything else do that this is always current to see how that goes there that goes there verify that dot was wearing Tulsans now that's annoying topi paddy being paddy six-figure devs a good podcast you should listen to the one that has me on it cuz you know it's me I'm joking all right well how's this networking why read out verify that that thing right now I want to say it was called so many times that like comma I always forget this is how it does it options that's right so how many times right a funk of times times dot once so I want there we go alright see if that works task it's not know and thinketh mock right it or if you're not used to mocking in your test it's like you need to get one of these working you get one of these working and then it's just copy-paste your way to success so they're not on some things see mock doesn't have a consistent way of doing this because when you do a set up and you want to say like what it returns it's on the end of this thing you say dot returns right so I'm used to doing like this whole chunk and then at the end of it saying like dot returns whatever in this case it's inside of it with a comma so it throws me off alright so the moment of truth does this thing run I totally didn't do this with TDD because I should have written this first but I don't always do TDD obviously you test Explorer which you know nice to launch for me visual studio and I told you to run the test but there it worked all right now seeing you test work that you've never seen fail you you really don't want to just believe that trust me on this one so I want to make sure I can make that fail so make that fail I just need to come in here I'm gonna comment out my log call we'll come back over here and say run this just again and like that it blows up alright so that's good so I can now prove that this line of code makes that test pass which is awesome how do you balance TDD when you're not quite sure of the design you're going for well TDD is great when you're not sure what the design is of a method right but if you're not sure what the design is of the whole structure then then it's a little more challenging and the thing that I do if I'm in that situation is I just try and start with the simplest stuff and usually it's like little things like how do I validate that that works right that throws an exception or that this input is correct and then I start building a suite of tests that are just doing simple stuff like input validation and and I start to think about it from the clients perspective so if I was the client calling into this library calling into the service what would I want the experience to be what would I call what would make sense and so I write the test as the client right that's part of a tester and design is you're letting your test drive the design of your public interface for your code or your API that you know you know likelihood it's for you you're about to write code as the real client of this thing but you want to use the tests as a way to you know very cheaply try out different things and see if it makes sense like I created this execute async call for for this entry point service and and named it and all those other things you know a few minutes ago I don't know if those are gonna end up being good names or a good interface they just seemed right at the time but now when I start writing these tests for entry point all right this is me starting to see what this looks like to interact with and if I had given this thing like 10 different parameters to call and I had to write a bunch of tests and every test I had to set 10 different parameters I'd start to feel like wow that's not a very nice design you know I hate working with this API and that give me a chance to refactor it in this case it's pretty short and sweet so you know seems like it's working okay so there's one test now I know as soon as I'd write another test I don't know what the next test is gonna be I'm gonna want to pull some of these things out and you know put them somewhere else I don't want to copy of a new statement in my code even in my tests any more than I have to remember news is glue hey yeah owner nice thanks for following so new is glue tells you that when you see the new keyword in your code even in your tests you're gluing your particular method to that particular implementation of that type in this entry point service I just talked about how this executes async doesn't have a whole lot of arguments but the constructor does it's already got three and I don't I have to rejigger all these constructor things every single time I write a different test and in later on I'm going to add one more and and if I've got 20 tests so I've got you'll touch all 20 tests and change them and add another parameter that's gonna be awful so I definitely want the construction of the thing I'm testing which in this case is right here in the test class name this entry point service I want that to be somewhere else I want that to be in one place so as soon as we have another test to write we'll take care of that all right so let's go into infrastructure let's go look at this in memory cue receiver and let's say that it really needs a cue name so I'm gonna take this opportunity to use a guard clause and specifically I'm gonna pull in my own package because I can do manage media packages we'll go find our Dallas stock guard clauses there install that and it's just going into infrastructure right so it's not really adding big-time dependencies to our system these are easy to rip out but now in here I can say guard against use that and then this is what again you sort intellisense null or empty or white space sure no white space I want an actual cue name right input key name and parameter name is game of you name like that okay now let's save that and then we can pass in an actual and memory cue receiver in our test there's not that's not going to hurt anything except for the fact that I don't have infrastructure referenced from here yet is that a problem no that's not a problem we can add that reference so we'll add a referenced infrastructure okay and that will give me something else to test now I'm a little hesitant about this because this becomes more of an integration test as soon as I do that so you know what let's let's not do that let's do this in an integration test okay so let's just build make sure everything's still green let's do a commit we're gonna add the integration test with a separate commit just explain the guard clothesline you edit there I will in one moment all right so get status a few things there that red on blue is so beautiful to read isn't it and all things there's working unit tests all right and again I'm getting ahead of myself by putting this line in here before I wrote the test but you know in these cases it's like it's doing stuff I know I've done it many times before so I feel like I can just do it but you can be a trap and that's why you have to be quick to to abandon that and fall back to test first if you if it doesn't work for you but if but if this works out you know 90% of the time which it does when I'm doing simple things like this I don't necessarily feel the need to write all the tests first all right so I need to do two things I need to create an infrastructure test project and then write a test for specifically the entry point service and how it works with the Q receiver as an integration and any other thing I have to do let's talk about what these guard clauses are so let's talk about guard clauses first so let me let me show you what this code looks like if we don't use a guard clause and specifically if you are testing your inputs to make sure they're valid you can say something like this if not string dot is null or white space space there of Q name all right then we do this and we're gonna do our work in here okay and then we say else and we throw an exception throw a new argument no exception if it's not null I guess we call it argument exception argument exception you know Q name are you networking system thank you your name message message message terminating all right now would use name of I'm gonna delete this code in a second all right so if you do this style right the style is bad in my opinion you should not do this style the reason why I say it's bad is because it results in your code getting more and more and more deeply nested as you check more and more and more arguments all right this is fine when there's just this one but let's say I've got four arguments I'm gonna check the first one but then I'm gonna check the next one no no check the next one I'm gonna check the next one and I'm gonna do my work right now my work is indented for if statements deep and I'm gonna say else this ones required else that one was her car else that one was required else that one was required right and I've got all these else blocks coming out and my thing is like 40 lines of code and almost all the code is just these if checks for the inputs that's horrible so what you want to do instead is fail fast you want to just immediately check if that thing is null and and blow up so you say something like what's the elegant way of doing this I've seen something like your name is no question mark through the argument exception no exception something like that you need that parentheses I think I do call and do whatever right I don't know that's not quite the right syntax like I usually use my card Clause thing because I can't remember the syntax for this it's like somebody you can throw it into the chat if you know it but you can do because you we have expressions now is it just that that's that's really close you name hmm let me google it for you real quick cuz I'm failing here I should probably throw a c-sharp in my search yeah I'm trying to get a ternary expression exactly throw expressions no no no that's don't know what this is that all right it's a whole stack overflow that doesn't even show the thing I'm looking for anyway there's a there's a short one liner that does that looks something like this and I can't read what it is but you know if we get rid of the me trying to find that super elegant way it just becomes a matter of do this and then swap these all right get rid of this it cannot either there this can now go there because the throw will short-circuit the whole app and the whole method so you don't need the else block all right you should try and pretty much always avoid having else blocks if you can or if there's a way to write the method without an else block do it alright so here this is now much better because I don't need the else blocks so things get shorter things were less nested but I can do it even better than that right I can take this now and say you know what this thing just takes it so I don't need curly braces this is like the one exception to the case that you should always have curly braces around you if statements is if you're going to either immediately throw or immediately return so in this case I'm throwing and so this which is a little long is a guard closed guard Clause is a pattern it's not like a name-brand or anything you don't have to use a particular nougat package to do guard clauses you can just you know just just use this pattern if you want but if you use this pattern all over the place at some point you might change how you want to do it right or people would not be consistent maybe they don't always throw argument exception maybe that sometimes they throw or you mean null exception or sometimes if they're exception or system exception or application exception whatever so for consistency sake if you want to use a library like our Dallas stockyard clauses or there's a few other ones out there you'll find now you can just use this everywhere and it's a little bit shorter and it's little bit easier to read and it's going to be consistent everywhere all right hopefully certainly do if you're saying that the one I get rid of is not very readable and not this one all right so let's let's think about this I want to add the infrastructure our site the integration tests and I do think I could write a unit test actually for for just this right for just visitin memory Q receiver so let's let's do the unit test first because it's easier so I'm going to add another folder for infrastructure and we'll add a class in fact we'll just copy this one it's a cheat and then this is going to be a very cute receiver and then what's its method called get message from Q get message from Q and we're gonna say throws exception given no or whitespace Q name right alright so for this one I'm gonna actually have it be a couple of different inputs string Q name we use a theory theory is an excellent way to let you pass in multiple different things so we're going to say in line data null never stay in line data empty string all right and then we'll save our receiver equals negative memory Hg receiver I can let me do that yet and it doesn't need any dependencies that's good and I want to call I want to verify I'm gonna get an exception and this is another syntax I always have to look up two things I got a today plus episode of that right okay cool yeah try the guards name equals name under Thunderer through oh that's it that is what it is all right so TBD gamer you've got the the one I think I was looking for which is this right so either assign it to itself if it's not null then do that yeah that's that's the thing we need is that assignment so this would be an alternative way to do it I don't like this in static analysis that Iran might catch it because I generally don't want to assign to inputs coming in here I would much rather assign you know if I have to change this value I'd usually pass it to a temporary like a local make a copy of it and then work on that because if I'm calling this thing I don't expect it to change the cue name on me right I don't most the time you're calling code if you're gonna change anything it's gonna come back right and depending on the pattern it using right but in this case it would surprise the end caller for CUNY and be different after they called this method I think and so this assignment is a code smell that a static analysis might catch and if I'm doing this all over the place it's gonna it's gonna you know throw a lot of false positives against my my rule that I want to see those but aside from that this is this is the short and elegant way all right this is even shorter than than what I have although the longer if it were the same exception argue and all exception right and also this one won't give you a different exception if it's empty versus null or whatever but but no that is that is what I want all right back to our test we want to record a run here we want to record the exception that was created and like I said I can never remember what that looks like so you know exception expected it's this code right here exception equals that so we'll steal that code and throw it here and we expect us to throw an argument exception when I call receiver dot I get message from Q with the Q name that's coming in on my test write this one so get all our parentheses right and then we want to assert something so what's wrong with this picture there we go I need the async version still need semicolon assert dot it's tight maybe no no it's good that's I can make this a var it's gonna have to be an argument exception or else it's gonna blow up I think that's that's what I need that's my assertion right there so I think I'm good do have any blog posts related to this I've talked about it in my Pluralsight course on domain Durand desire so see if there we go that stream elements to the shop and I also talked about quite a bit in the shop on web sample do I have that anyway no I just probably add a stream element thing for that but if you just google a shop on web there is a free ebook so that's what you want it has a long title name so it's architecting modern web applications with asp.net core and microsoft answer to that too additions three notes coming soon grab that book and then you'll be in good shape so get the e-book from here and it's free and it's a PDF it's also online so these links are right here to the different formats that you can get it in and that should help right now talks about clean architecture of course Uncle Bob's book clean architecture is useful too alright so let's see if this test passes run the test I should run it without the guard clause first and watch the test fail but here we go who's failing and it says I expected Mach let's run everything that one should be passing yeah that one's passing okay good one passed one failed that's neat alright so we got this year here that says value can't be null and it did in fact give me an argument null exception not just an argument exception which is more specific so what do I want to do about that I guess I'll just make it two tests that seems reasonable because they are doing different things so throws no exception given null you know I was gonna be so excited - no thanks Alexa I am sure what went wrong it's why I'm writing tests for it I don't need this so I was gonna try and show off theory but I guess always go back to fact and get rid of this right do this pass in there we go and Eric yeah he flem there is it's one of the contributors on the eShop on web 2 so if you have questions you can ask me or him about it alright so this needs to be null exception let's verify this test works should work now I hope it's green all right now we'll copy it and say throws argument exception given empty straighten that empty and argument exception and so this is gonna be an example of make it work and then make it right so like a lot of duplication here but I wanna make sure everything works first and it does okay so now I can make it right what does that mean well I was just talking about how I don't want to be duplicating this code so let's promote that up to a field and if I had resharper it would do that for me but visual studio isn't quite that cool yet so private read-only and then make you receiver new one of those do that do that and take this here now since its X unit not in unit I'm gonna get a new instance of this class every time I run this and so it's fine for me to just new it up here I don't need a setup method to do it if you ever go to someone's house and they have a like so say exactly like this remind me in an hour I'm always listening then after an hour she will say this is your reminder and I'm always listening it sounds brilliant if you're listening to music because it seemingly just stops randomly can you make it remind me every hour because that would be even more awesome because then I'd have to figure out how to stop it can you can you tell it to do that like I know how to make it do it once but maybe a awesome thing to do it all the time do this at random intervals alright so we've got that is in good shape let's get back to checking in code we added some more you know tests about half an hour left let's get some integration tests going added unit tests to in memory mm rvg receiver all right and I might want a way to like put some items in that cube but I think before I do that I want to get the settings and stuff working it's a how big a deal was it that I wanted to have integration tests so my integration test is going to be that when I pass in this empty string to that for real it does blow up and I get this error logged but what I really want is for that to be a mock and verify at the error locked and currently if I just pass it as null get the null reference networks and that's I'm getting the test of this currently I don't know if I need an integration test for that so I'm gonna leave integration tests for now let's do configuration work because I think that's more useful you can have Alexa learn your voice now that's nice and you have needed that forever because I have children let's see what that does Alexa Red Alert nice you guys gonna hear that out okay good it doesn't just keep going forever yeah so settings let's add settings I wanna have at a minimum we said they're kind of mock this out said I want to have some entry point service settings and that might be stuff like the queue name for instance I'd be a good place to put that but also this delay milliseconds we can do I don't think I need any tests necessarily for that one but let's figure out how we would push that in so currently in the worker its hard-coded right so I would like this to be able to take in some settings file and I think that settings file could totally live right in here so we like worker settings alright so let's go and say we have public class work there settings like int whatever I called it delayed milliseconds get set all right so push that into its own file and then we'll pull that into here as a requirement now you can either use the I options pattern or you can just ask for the thing and so I think I just want the thing I don't need any options so I won't work or settings settings put that there and then here I want to say instead of that I want to say settings dot delay milliseconds and get rid of my to do just onto doing it it's not quite done yet yesterday was spritzee day nice yes that's the equivalent of like day for a computer right where was I you know we're gonna try and figure out how to wire that up so if I just built this now or run it now it's gonna blow up of course it's gonna say hey I don't know what the heck this worker settings thing is so it's unable to resolve service of type worker settings while trying to activate your worker so we just want to go back in here and we want to add the configuration all right switch services dot add single tune worker settings where we get that tight frame I think have to new it up first some of our settings it will may work for settings and then we bind it and we say use the One Ring to bind them all and what is that that's toast context supposed to contact dot configuration dot find isn't it thought it was something like that so you VIX trawls this one just looking at this earlier this week and do that I'm you say that configuration depth behind all right so that's that's what I want I want that so come on Rick don't let me down do you have that capital configurations nothing because it's close to context dot the configuration dot find so is that a extension method or is this the thing that everybody said went away behind I got this working not that long ago yeah so I could load it up myself like this just do it manually I don't want to have to do that yeah so you can just do raw that you do that and do this all right so where is that it's Google for that where it is configurations find configuration binder yeah that's it Microsoft extensions configuration okay instantiate the precious that's right you must instantiate okay so using Microsoft tensions configuration we go so I didn't ask me about that totally show said hey do you want to add this no all right so I can fake that config is actually the section that I want no no that's my settings all right so that's this line that to that and I just want this name to match worker sitting no control to control tone gets me here I don't necessarily want that to be a thing really just be this cuz I'm gonna use a convention that I'm gonna name my class the same as my section and then add settings I think that does it so I don't need that anymore right so that whole chunk is wearing up settings at some point I'm gonna pull this out and a helper methods we're not quite David so let's get this working build success then doesn't like that What's it telling me different air get message from Q is blowing up because during exception Q name is empty but everything else works right I'm gonna see it's running every second so settings is working I just need to go in here and do it some random random key name totally random cool all right so we've got settings down and that's nice because I've actually wanted that sample code for some other stuff as you could tell so yeah that is nice that Carnac does that I agree surely does it's better than what I had before it was showing every single key control asses save yeah that's nice okay so I think we're ready to commit this and say that we implemented settings so we'll get a dot digest for worker settings now we're gonna add C ICD you know they're fun stuff like that eventually I don't think a lot of time for that today but I think we made some pretty good progress I don't think we're gonna need functional tests for this but eventually I'm gonna want some integration tests maybe it would make sense to have a Adger sample in here as though as a separate adapter or something they even some different logger adapters I said Sarah log or something else and then if people use this template they could just pick which one they want delete the other ones or even just keep them in case they want them later so I think next I want to do the settings for the app itself right so these two settings files one was entry point setting someone was worker settings and I think I want an entry point settings type now so probably that'll be in its own folder for settings even though right now only has one thing add a new class called entry point settings and make it public and then I'll give it a property a string of input I guess it's got receive to it or see thing receiving queue name about that we give it two of those and this will be sending queue name so we're assuming that it's going to do some work and then say I finished the work and throw the thing on to the next queue for some other work we're gonna deal with don't do that okay rid of that save that and then we have some entry point settings which you know the service could take you in I think I'll put it after the lager make sense to name three point settings settings and where that up look at that even put it in the right order all right so now this then becomes settings dot receiving cue name and of course that needs one of those for now that should work let's build this is totally a best practice just passivating as Nolan's but I think the test will still pass let's verify our test pass so I don't have continuous integration doing that for me and it does all right now let's run it it should blow up and it does and it says hey I don't know what to do about that type all right entry point settings unable to resolve ok question I have an MVC app working I was ok to have a detail that passed an entry form and completely different detail that popular entries from that form into for passing for my repository layers book at multiple d2 yeah you know as many details as you want frequently at a minimum I'll have DT O's well first I usually don't just call them DT O's usually I name them based on what they're doing right so a view model is a DTO so I would call it a view model if that's what it was for a binding model which is what I call the things that come into MVC that uses model binding against I'll call those binding models if if they're not also view models right if it's already a view model I'll just keep it keep calling it a female but like for an API where I'm accepting in models to the API I'll call those binding models or API models as opposed to just DTS because I think it it's more expressive about what the intent of those types is okay so now if you start thinking of it that way if you think of it as a binding model for a post API endpoint it's really easy to say that this is only for that end point right it's not a general-purpose anything anywhere could use this DTO for whatever it wants no it's the you know customer create binding model and and so then when you want to take go from that to your repository well the thing that you're passing in your repositories should be an entity not a DTO typically so you're gonna want to have your customer create binding model go into your controller action and then through some mapping or some other work you're gonna create a new customer entity and populate it with whatever values it needs and then from there call repository add or repository that insert or something with your entity now with your DTA alright why is this showing me this error when all my tests passed yes I just need to click around more right there I'll still get it cool but I have now in app settings this thing and I said that it needs a receiving QA all right so it's control KD to format things and then ctrl s to save it ctrl a just by accident alright that looks good and sorry so I just need to do the same work in here to bind my other settings so this will be my let's call this setting I will just copy this whole chunk and now this will be entry point settings and I really have to the side of entry pointers capital host I'm doing that consistently it I always capitalize the P I guess idea alright so I'm doing it consistently that's good it's gonna do the ones above no it did none of them all right okay manual copy paste it is and this also goes there alright so we have an entry point settings of type in turquoise settings we're gonna bind it to the joint settings and we're gonna add it as a singleton that should run no no no oh we're back to value cannot be null cue name shouldn't be no should be reading it from configs appsettings is working note to self 1847 or no we're way past 1847 okay appsettings receiving keaney all right why is that networking entry point service because i said that enter point settings there's quite service settings are not the same so that's my fault just delete that they build and i expected error detected what's the air succeeded don't lie to me visual studio just just work alright no it's gonna work yes alright everything works we have settings for the general you know just work or process looks like how long should i sleep we have setting this for the specific worker that we've defined as this entry point service and we have this thing now somebody watching this is going to come along and say haha look this is the complete over architecture of a hello world worker service and really they're not wrong i mean if this thing is not doing anything but what it's doing now of you know spitting out a log message then yeah this thing is totally over architected and it's not needed if you're gonna do some really crazy stuff right here and the important do some work thing then having support for settings and logging and tests and all that stuff out of the box when you just say file new solution i think it's helpful so if you do if you can write more than one of these or even is just gonna write one you want to start off on on the right foot i think how in a template like this could be useful so if you agree you're welcome to clone this thing from its repo so and I'll take pull requests and I'll take issues so there's you know good chunk of you watching this if you found this interesting and you want to me to do something else like hey I really want to see you do this with it you want me to wire it up to Azure would that be helpful or does that make it too tightly coupled to a jerk do you want me to have dbcontext in the database never talked to a database is that helpful or is that you know adding too much I want to make sure I stop where it's useful but not so much stuff in it that it's like more trouble than it's worth just to rip all the crap out you don't need and I'm not sure where that is because honestly I haven't written a whole lot of these worker services yet myself they're they're kind of brand new so I know I'm gonna need to write some real soon now for some clients and so I'm kind of doing this work here on the stream to set myself up so that when I go do the work for clients I'll I'll have a good starting point and I'm sure as I learn more from those client activities I'll roll those into the github repo as well but yeah if you guys if you want stuff here's what I want you to do go here and add issues so right now there are zero issues give me some issues to to work on and if you feel like helping out you know this isn't a super complicated open-source project feel free to grab an issue once somebody adds it and do a pull request and you know maybe we can work on merge and a pull request you know in a future stream and you know if you're here you know on the stream at that time we can talk through it together and see you know what makes sense or what doesn't and and pull it in it might be that you know just snap your fingers and I say merge right but if it's more complicated than that we could have a conversation about it all right so let me commit this this stuff here we've got the entry point service what do we do we wired up the entry point settings that's what we did get add that and wired up entry point settings to say and by the way all these settings we've been doing can also totally do from environment variables so when you deploy this thing out to Azure and you have it run in an azure worker role or a docker container or whatever you don't have to have an app settings file you could totally just set these things as environment variables that's the point all right we're doing pretty good on time I think I'm gonna finish on time this week so open question time we got like five minutes before I find somebody to just send you off to Java BBG dbcontext do you want to add an issue you have a github account if you don't highly recommend you get one feel free to add that issue here if you want if nobody adds that issue here and in the next a little bit I'll I'll go ahead and take a note of it but I do want you folks to have the opportunity to kind of build up your your github cred by opening issues yourselves and you know doing pull requests ourselves it's it's very useful in my opinion for you to be active on github how to use a DB context in the worker service because it's a scoped service right well that is a good point so yeah let's talk about that how would you do a DV context since its scoped and I can certainly show you that type of code for here's a good one to steal this tab will go back to a shop on the web and look at its program dot CS so if we come in here and go here I'm looking at programs yes this will show you how to create a scope right here really it's this using statement actually creates a scope if you need any services like your DB context you can get them from the service provider off the scope right so basically inside that worker role that worker process I would somewhere have one of these guys to create a scope and I'd probably do this inside of my well I would do it inside of an infrastructure service because that's what would know about it and I would do it probably once per call to entry point service right so entry point service this is my scope right if this is the equivalent to an asp.net request right so I'd either I wouldn't create the scope actually here because this thing is in core and I don't want it to know about such things but the scope of it would be scoped to this so somehow I would I would pass a service into this thing that would be responsible for the scope and it would do the work you know in here so maybe I'd have to have an adapter for scope or something like that the actual code to manage a scope when you don't have asp.net core doing it for you it looks like this alright you create the scope and then you can get your context from it and go from there so help nobodies definitely something that we could look at and see how that works because yeah talking to a database and using db10 text is probably a pretty darn common thing to do so so I don't have to say your name are you Joe of beat to your tower sorry but if you want to add that issue I'll definitely take that into consideration to do Joe I was it's fine all right so Joe if tell me are you gonna create the issue yes or no yes all right you create the issue here's the place to do it and then I will look at it next chance I get maybe next week anybody else any other questions thank you guys for spending some time with me today I hope it was a good use of your time I'm gonna go off to twitch here somewhere let's see here there go find twitch no but where should we go people who's online Clark you like here's always online chef Fritz has done though right it's a twitch TV slash teen slash live coders who's online we got insta fluff clarkey ozera tar Nick Larsen these people doing Monte Carlo tic-tac-toe game that sounds fun Sarat are super short stream okay he's offline I always send stuff to Clark yes well it's try something different let's do Nick Larsen let's do that we're gonna send some people over here is he doing he's even doing c-sharp Wow it's not even JavaScript also and CP ed is there all right will do do Nick Larsen so Nick underscore Larsen I even following him I should totally follow him Nick I'm just gonna person with seven people following we're gonna raid the heck out of this guy so raid and I gotta get that going I just totally closed it so the trick that I have to remember is I need to go in there get past the ad first and then hit raid that's got to be the trick so there now I'm in there and Sarah tars in there too apparently so that's why he's not streaming and now I get on my other tab and I hit raid now and I'll send you all over there so thanks for coming talk to you later hey our Dallas everybody from our Dallas is right
Info
Channel: Ardalis
Views: 4,658
Rating: 5 out of 5
Keywords: twitch, games, .NET, .NET Core, Worker Service, DDD, Domain Driven Design, programming, software development, code, coding, windows service, worker role, cron job, stream, ardalis
Id: _jfnnAMNb94
Channel Id: undefined
Length: 112min 18sec (6738 seconds)
Published: Fri Oct 25 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.