I am a die-hard Visual Studio person. I love working in an IDE. But I've been trying out the Copilot CLI and really enjoying myself, so let's build some stuff together in the terminal!
As with all livestreams, I'm looking forward to answering YOUR questions! So join me live and ask in the chat, or you can comment now, and I can try to get it answered while I stream.
View Transcript
Cool. I think we're going to get going here. Let's just poke around a bit. Awesome stuff. Okay, welcome to the live stream. We're going to be coding today, which is super cool. Um, but hopefully we don't have to do much coding at all and we can let co-pilot do it all for us. So, that's the goal. We'll see if that actually pans out. I I'm trying to find something. Give me one sec. I just want to pull up a couple things so I have access to them. So, I wrote a little bit about um Copilot CLI over the weekend. So, just putting that into the chat if you want to check out that newsletter. just touches on some features from the co-pilot CLI. Um, and then I did, let's see, I think last, not this past weekend, the weekend prior, I recorded uh some videos
on on my my usage with Copilot CLI, kind of moving from Claude over to the Copilot CLI. And then I put one video out today on my main channel, which is just Dev Leader, and then I have another one coming out. I'll put it out later this week. My voice is going to be all weird. It's been happening all day because I'm getting over my cold finally. And yeah, so in those videos I just tried to highlight like how I've been using it. I do a like a very brief comparison to Claude. Uh, and I just wanted to kind of mention at the beginning of this like um this year in particular, I'm trying to do a little bit more poking around trying different AI tools. I am a big fan of using uh GitHub copilot like the cloud agents. So submitting you know issues
in GitHub and having agents work on them and almost like that became my default mode and I just want to make sure I can I can challenge myself to break out of that. So um as a Visual Studio user like I love using Copilot and Visual Studio. I'm not a terminal person. Uh I've done videos and stuff on Claude before so I'm not like against it. It's just not my natural way to work. So, uh, forcing myself to use Claude and C-Pilot on the CLI has been, uh, it's been fun. It's been really helpful. So, we're going to code today. I'm going to spend time building stuff in Needler. Um, Needler is a dependency injection framework I have. So, one sec. I'll go full screen. Um, and let's see, where do I I have it somewhere here. So, there, that's the right tab. So I
have Neidler which is available to download if you want to poke around or just see uh the code on your side. It's open source, right? It's this is an opinionated framework uh that I have for doing dependency injection. And so the reason I stress opinionated is that like I built it the way that I do things. And if you don't like the way I do things, that's totally cool. You don't have to use it. It's not my It's not my goal to build, you know, the thing that you and everyone else want to use at the expense of me wanting to use it, but I figured it'd be a good thing to kind of make into a package. It's available on GitHub if you want to poke around and see. Means I can make videos on it. It means that I can have other people
uh who are interested, if they want to contribute that kind of stuff, they can. Um, but yeah, it's been kind of fun to build. So, I use Needler in my my product called Brand Ghost. And the reason that I have something like Needler, I'm just going to go back so I can talk a little bit. I have something like Needler so that um my my plug-in based applications. And if you're familiar with stuff I build and like my videos on YouTube, like one of the things I love to build is like a plug-in based architecture. But most of the time, the things I'm building do not need plugins truly to be dynamically resolved. So it's not like you've been running your product or service for a few hours and you're like, "Oh, let me let me load in plugins now." Uh like let me switch
these on the fly, that kind of thing. Um I think that's super cool. I just I don't really have uh much use for that. A lot of the time I build plugins because I like forcing myself to have things that are decoupled um in ways that plugins provide. But a lot of the time I have that kind of stuff available uh at compile time. Okay, so that's a big thing that I want to call out here because over the past couple of weeks I had Claude and C-Pilot take needler just to go back to it one sec. I had Claude and Copilot take needler and convert it from being reflectionbased. So this is a net channel uh primarily but I had it uh go from being reflection based to source generated. So if I go into the source folder um just to kind of point
it out we have this needler injection and then we have reflection and then we have source gen as well. So when you're using Needler, you can actually pick between these. And if we jump over to an example project, let's go over to I don't know, we'll pick the source gen one just to to start. There's a console app. And then we'll go into the program CS file. You can see that when we're doing, let me zoom in a little bit here. When we're setting up our application to run, um, you make a syringe. It's just a a fluid builder kind of pattern. Um, and the syringe is the thing that allows you to build a service provider. But you can see one of the things that we can do with the syringe is we can say that we're using source gen. And if you're using
reflection, as you might expect, you're not using source gen, you would say using reflection. And so as of a couple of weeks ago, or I guess not this past weekend, but the weekend before, needler was only was only reflection based because that's how I've built things. it's always suited my needs and I kind of wanted to I've had this goal in mind where I wanted to learn more about source generators. I wanted to build something with source generation and so having Needler converted over to source generation I thought would be a lot of fun. So those those videos are going to be well one is up on uh my YouTube channel right now and I figured we could talk more about this. We can build some features with Copilot. Just wanted to give you a little bit of background. So, if I pull up this
Let's see. So, I have Let's see if I pull Okay, looks like Oh, that's a different branch for the GitHub pages. I was like, why is this where's this branch? Why is it out of date? And I can explain that, too, because I built that with with Copilot. So, I think, man, this is going back a while now. Um, I built a whole bunch of stuff. So, where did it even start? Like, I'm going like this is seven days ago. You see how many commits? Like, there's a ton of stuff in here. And my my goal is not to show you like, oh, like AI just runs the world. It's no, like it actually helped me convert a bunch of this stuff. And so, man, we're going back pretty far. Um you can see like here's a commit from eight days ago that says like
this is where source gen became the default. So you know leading up to that right like that many commits eight days ago were me working with claude and co-pilot CLI to to get this all converted over to source generation. So everything past that. So, right. So, if I scroll back up through this, all of this is me kind of delegating stuff to Copilot in the CLI and having it build the rest. Um, so Baron Bite is asking, "Is that all AI generated code?" Yeah, for the most part. Um, so what's really cool is like I built all of the reflection part myself. Like it was literally code that existed in Brand Ghost that had been migrated from previous projects, right? I like kind of like built the skeleton for this, moved it into Brand Ghost and used it and then pulled it out of uh
Brand Ghost to be its own um package that I could reuse because I was like, "Hey, this would be cool to to repurpose it." Um so I had all of this reflection stuff built by hand. Maybe a little bit of help obviously from uh like using co-pilot and stuff like but me building and having co-pilot assist kind of thing. And then um everything that I'm showing like on my screen right now as I scroll back up, this is all AI generated, right? It has because I was doing it uh on the CLI locally on my machine, it has my name and sorry, I realize it's kind of hidden behind my my dumb face in the chat. Um but like all these commits are basically co-pilot building stuff. Now I have found the development in the co-pilot CLI um I'm doing a lot of planning mode
and then you know getting on the same page and then saying cool okay like go execute on this. So talk a little bit about how it's kind of screwed some stuff up. Uh it's it's almost like things were going so smooth and I'm like I know they shouldn't go this smooth. And so like over the past uh over the weekend actually I spent a couple days this weekend going you know what like you're you've been lying about some things. So uh let's see if I can find a good example. Um like this one here says sorry the the text is tiny because I'm uh I'm using one quarter of my screen to to stream. Um but this one says fix uh remove. Let me just pull this part up. Remove non-existent register as and autoregister from resolution analyzer. So like it was inventing things that
didn't exist and then writing Roslin analyzers to like enforce proper usage. So like those analyzer rules would never do anything. They would never be applicable. And it had tests that were because it's a ROS analyzer. it would it would create C code as a string and it would run the analyzer on it go see yes it's detecting the problem and me being kind of stupid uh and I talked about this actually in a code commute video I recorded today but I think from moving so fast through this stuff through some truly unfamiliar things for me it made it so that when I was reviewing code there was a lot of little things that I just missed along the way and so I was was reviewing I was looking at it but clearly not Well enough um just to kind of see if there's a little
bit more um remove non-existent one. Um this one it says standardizing test infrastructure but I think this one had Yeah, just to kind of show you. You can see all the red text on here. Right. So just to explain a bunch of these things can I zoom in on that? I can. Nice. A bunch of these things didn't actually exist. Um so this is a test right circular dependency analyzer tests. Um because this is an analyzer it's going to be operating on strings. So um it will go run the analyzer on this string which is is C# code inside of a string. And these attributes didn't exist. They just simply were not real things. So the analyzer was checking for things and it literally built an analyzer that would go assert this behavior and you know give you warnings if you were using these things
wrong. So like the thought around it was very helpful. I do think that it was uh like was good analyzer rule sets to be looking at. But then I realized like this singleton attribute for example um the only place that this existed was in test code and in test code inside of like strings. It was it was never real. As a user of this library, you could never use singleton attribute. It just it didn't exist. And same thing with scoped attribute, transient attribute, register as attribute, um, autoregister attribute. None of them existed. They just they just weren't real. So, um, a couple of things just like to quickly comment on before we jump over to actually creating some code. Um, a couple things to comment on are like when I looked at this, I was like, okay, well, I actually think that these are attributes
we we could use. I'm not like against them. So, I actually had it introduce these as um as attributes you could use as a developer to kind of override default behavior. Then the analyzers made more sense. And then I realized that this code that's all in red here was duplicated across like four or five tests. I said, let's not do that. Um ideally, it would have been really cool if that um that code could have been generated from real classes to prove that like there's something real going on. But anyway, um was a bit of a bit of a surprise to me and shouldn't have been a surprise because things were going so smooth as you can see from like all of these commits that were going in. Um I was really on a roll building stuff with uh with Copilot. So, let's jump over
to the CLI here. Uh is that text? Can I zoom in a little? Cool. Um hopefully that's legible. Um Whoa. Whoa. We went way too far. What happened? It went to like the top. Okay, that's not supposed to happen. Um, okay. So, if can I scroll up just a tiny bit without it going nuts? Okay, let's talk about um something I kicked off before going to work today. So, um, and sorry, I realize some of the text is cut off, um, in the window, but it's not super important. So, before I went to work and some of the stuff that carried over from last night when I was working with Copilot, um, for folks that are familiar with dependency injection frameworks and .NET, there is a popular one that uh, well, it's way less popular now that the Microsoft built-in stuff is really caught up,
but there's something called Autofac. And autofac is a dependency injection framework that I have used for many years. I really like using autofac. There's a lot of really powerful functionality. And the reason for using it, like I said, um, historically was was just that it was way more powerful than the built-in stuff. Now that the built-in stuff has come a long way, I would say there's a handful of features that are kind of interesting in Autofac still. And because I'm not using autofac anymore and there's another uh popular library called Screwdor which does assembly scanning. Um I don't use either of those two things and I don't because I don't really rely on their functionality and I have Neler to replace that. But there's still a couple of cool concepts from Autofac and Screwor that I might try to pull in and this what we're
going to talk through is one of them. So, it's kind of weird to explain, but um I had asked Copilot in planning mode. I said, you know, do an analysis of the codebase. And this is what I've been kind of uh repeating as I've worked with C-Pilot CLI over the past week and a bit. Uh and I'll show you plan mode in just a second, like how you uh switch into it, how you get out of it, how we can I'll open up plan. It probably opens up in cursor. Um so I have been having this like repeated conversation where I once I make enough progress I say great like do an analysis of the codebase and when I have a plan already and I'll say and like review the plan let's get an analysis of the codebase plus uh opportunities that we could continue
to build the framework out uh especially compared to other dependency injection frameworks like Screwdor, like autofac etc. Okay, so basically I'm looking for some inspiration. I'm relying on co-pilot in this case to understand my codebase, understand what's popular out there and go, hey, where are some feature gaps? Maybe there's some cool stuff to build. And so in this conversation um I was told by co-pilot hey autofac has like these factory delegates and can I explain a factory delegate easily? Um basically when you're injecting your dependencies into your classes you can call like a like it sounds funny to say you can call a funk. So you can call a function that will is basically a callback and that way when you want a new instance of the dependency you can create one on the spot. So it is giving you the factory method to be
able to create a dependency on the fly. So, it has this there's some cool things that you can do with it, but basically co-pilot said to me, "Hey, you should you should have this." And then it came up with a little proposal and I was like, "Well, you're not like I said to Co-Pilot, I don't think that like I don't see the benefit, right? Like what you're proposing if we put that in, it's kind of just pollution. it's not really giving a developer any more access to things that they couldn't already really do. So, I thought this was kind of interesting because um it almost pushed back on me and it was like okay well and then it asked these questions like what's your actual use case? It said to me what's your use case and I'm like I don't at first I'm like I
don't really know man you're suggesting this not me. Um and then it's like what should get reg uh registered? Do you have a concrete example? So I was sitting here going like okay co-pilot proposed this to me now it's asking me to clarify and I kind of challenged myself and I said okay can I come up with a simple example which I did right here said can I come up with a simple example where this is where this applies and maybe if I give it enough kind of push and a direction it will come up with something interesting and so uh and sorry Baron Bites has a question do you think these agents provide better response if you give them JSON formatted questions. Not sure to be honest. I have not tried um it's not natural for me to type in JSON. So, uh what
I would say is if if that were the case, if it were and I don't know, but if it were the case that JSON formatted questions work better, um that is a level of indirection that I am not willing to participate in. And to elaborate on that, the whole benefit for me as a human is that I can speak human to the agent and it does things. If I as a human have to speak JSON, we're moving in the wrong direction. So if it was able to do better with JSON, I want a tool that's going to take whatever I'm saying and format it into JSON to give to the agent. Um I think any anytime we are trying to optimize agents and have to get rid of the human element to do that um we're we're moving in the wrong direction. So we need
to build tooling or change the interface to things so that we can ideally as as drivers of these things in the situations where we are the drivers we can remain as human as possible to have the least amount of friction. It's one of the reasons like um it's not showing on my screen or my stream, but like I I use whisper flow. Uh not all the time, but I I like having it and I have a foot pedal so I can just talk to the agent, right? Like if the more things that we put in the way of us interacting with these things more naturally, the more steps back now again to your point, I actually don't know if it is more effective with JSON formatted questions. And if it is, I am not going I'm not giving into being the one to be the
translator into JSON. That's that's a machine's job to translate my question into JSON. I'm not doing that. So, um, hope that I don't know that's my opinion on it, but I've not actually tried to see if it does better. Be curious to see. I'm interested in knowing, but I hope that if it is better, someone builds a better interface so we don't have to do that. Okay. So in the example that's on the screen, this like super quick one at the top. I'm just going to elaborate on this a little bit because it kind of explains some of the the followup. If you were to declare a class like this, and I realize this is a very useless class, but if we had a class like this, and we had a dependency that could be automatically resolved, and another one that could be automatically resolved,
and usually like I wouldn't recommend you go register a string onto your your service container, your service collection. like a primitive type on a on a service collection to me is not like a good idea because you're saying I want to resolve the string like which which string do you want to resolve like it's the same if you had an integer or a long or a double or a gooid like you want the gid which which do you want um it's it's really weird but it's not uncommon to have a class or something where you want to pass in a string or an integer or maybe a couple of these right So when you run into situations where you have something that's resolvable, something that's resolvable, and then one or more things that aren't in my code setup, like one of the unfortunate side effect
is like needler is supposed to automatically discover and register everything. And when we have a situation like this, it's unable to. It's unable to because like it's going this is a primitive type. I'm not registering primitive types like this on the container. So if you wanted to automatically resolve my service from the container, I literally can't give that to you because I never automatically registered this thing. And it can't because of this parameter right here. Okay. It kind of throws a wrench into the mix. So what would happen normally and what I have in Needler is I have these plugins. So can I pull up some code? Maybe. Let's Whoa, there's too much stuff going on. Let's get that. Let's get that. Okay, there's a whole lot going on on my screen. I'm sorry. Let's get this down. Let's get that. Okay, so let's maybe
go to an example. I have this example folder. um console app plugin plugin types just a holder. So I have different plugins that you can have. You can see here's an example of something where I'm saying do not autoregister it so we can override it. But here is an example of a plugin. It's kind of hiding behind my face. There we go. So, in a plugin like this, what I would have to do with the example that I had in the console, let me see if I can just pull it over so it's a little bit easier to to play with. Let's take that. Okay. So, if we were to take that code, let me pull it onto a couple lines so we can see it. Okay. So if we had something like this, what I'm saying is that needler cannot automatically register this. And
so what would have to happen is we'd come down here and I would have to go register it. So I might do something like um I don't know if this is going to cry at me, but you can get your service provider and then you can say I want to like it's a call back, right? So I want to make a new my service and then off the service provider I would resolve. So um get required service and obviously these things don't exist because it's just from my example but I would do this which is really a pain in the butt and then the one thing that's not coming off the container. Okay. So you could do this kind of thing. Need one more parenthesy. There we go. So you could do this. It's one way that I play around with this. But it sucks
because then like instead of the needler way, which is everything's automatic now you like you're manually resolving these things. You have to have a whole plug-in class like this is gross. Um but the other way is like you might say, well Nick, well what if I don't know what the string is? or if I know it like this, why isn't it just like why is it a parameter here? Why isn't it like a constant or you know like why do you have to pass it in? And good question. So um the other way to do this is instead of having this I would put do not autoregister and then I would probably make my own factory class. So I would have something like my service factory and then the way to oh actually co-pilot just did it come on right like it it knows this
is the pattern that I would usually do and it would be right some argument whatever it is and then so when you want to go use this you just call the create method this stuff is already passed in and anytime you want to make a new my service, you only need to give it the string. Okay, so instead of this down here, what I would have actually you can get rid of the whole thing because this factory thanks to Needler, the factory gets autoregistered because both of these are discoverable. Needler would register that. Needler would not register that because it has the attribute on it. And then anytime you want a my service, you just use the factory. But this is gross. In both of these cases, it sucks because we have to go add that, right? Or we had to go do that other
registration. It means we have to go type a bunch more code. And guess what? We have source generators. And I wanted to see if we could build something that maybe either one automatically generates a class like this for us, which I think would be super cool. Right? If you detect things like this or maybe we have to mark them, if it automatically just made a factory for you, I think that would be so cool and then you just have it to use. You never had to type it. We don't have to do the work. And if we can't make that happen, and I I don't know the limitations for what we're going to run into here, then automatically um putting in a funk so that we could do something like this uh public seass uh some thing that we have and you could have a
funk that gives you a my service my service factory and then what's the we need a string to be passed in. So if you could have my having something like that get automatically registered onto the container. I mean that is the functional equivalent to having like a class to do it, right? The signature is the return type and then some argument is the string. So it just gives you either a delegate or a class. I think that would be cool. Um, I think probably like the delegate is the easier thing because we're not declaring a whole type. It's literally just a funk. It's built in for us. I think like I'm kind of fascinated by this. I think that's kind of cool. Um, not a I'm not a huge fan of just having like random callbacks and stuff like this. It feels kind of gross.
Um, there's some trade-offs, right? So, if we're thinking about the trade-offs, one of the things we could do is we could go ask co-pilot to talk through the trade-offs. But the pros of this approach, right, number one, we get the functionality, but uh number two is like there is no new type. It's kind of nice. We're not doing anything extra. Um I don't really know other pros like it's simple, right? It's just a it's a call back if we can automatically figure out the parameters and it's registered. But one of the cons for this is like if you were the consumer of this, you don't actually know perhaps what the signature needs to be, right? You may not know that if I want to go make a new my service that all I have to provide is a string. You might go, I don't I
don't know what it needs. So, you'd have to guess at what funk to ask for. And that's kind of a pain in the butt. If you knew if you knew that it only needs a string to be passed in, then then great. But if you don't know, it's kind of hard to discover. If we used a class, um, again, first pro is that it solves the problem of being able to resolve it. So let's do this just to illustrate something too. And I would have my service factory, right? like I don't have to guess at what the signature is. I just ask for the factory like the whatever the type name is factory. So easy to find. Then I know if I want to go do something with it. Um obviously that's not going to work. I need a method. Okay, there we go. Right.
So we could go check the create method and see what it requires. But at least discovering the type is totally possible. So, that's nice. I don't know how complicated it is to actually go do this with a source generator. When like when does it actually generate? Is that going to work? Are we going to be able to write um a class like this? I don't know. But might be kind of neat. The other thing is um maybe we don't want a whole class like this. Maybe we can use some type of proxy class. Maybe we need something else. But it might be handy to have an interface on this because if we're thinking about being able to build uh things that can be uh maybe unit tested or mocked out, maybe we can get an interface. I know some people are already going, "Whoa, what
do you mean interface? Younet developers are always putting interfaces on things like yes but or we should say yes and yes and it's kind of convenient if you don't have to go type it because it was source generated like that's kind of cool right it's a pain in the butt if you're having to constantly duplicate things and whatever but when it's automatically made for you what's your complaint I don't know there's probably some complaints you can come up with keep those to yourself but anyway I think there's a couple of paths forward. Um, and like we could do both. I don't know. But I might see I might see if we can do this pattern first. Not because it's necessarily my favorite, but because this is actually closer to what autofac. And I think this might be easier for Copilot to go figure out. So,
I'm going to go delete all this code that I just messed up in here. I think that's up to there roughly. Okay, we're going to go back to Copilot, but this is kind of what I was explaining here in this uh mess of text. I was just kind of giving it some background about what I thought. And so it said, okay, here's a revised design. So it came up with these ideas. Okay, approach one. Then we have this. You can uh label it with generate factory. So you have a type where you know this thing here not going to work. So we label it generate factory. And then what we get is this registered. Okay. So option sorry approach one that they list is one of the options that we looked at. This also said generated factory interface. It says like maybe it can do
this. I don't know like I kind of like that. I think that's pretty smooth if it can make the interface in a backing class for us automatically. Oh, I don't know. I I do like that. I think that's I think that's nice. Okay. And then it lists some key points and some more questions. So let's see. This is where I left it, right? I did this before work. Uh and I typed my response and then I left. So kind of reading this part for the first time. So key points generator already knows which params are injectable versus not. This is true. Um generate factor attribute opts into factory generation. So it's an explicit optin. I think that it could get pretty crazy if we didn't opt in. Although based on my own experience, um it might it might actually be feasible that if it detects
stuff that is a mix of um if it's a mix of injectable dependencies and non- injectable and you didn't put a do not autoregister on there because if you put a do not autoregister and you use a plugin to register it yourself, you don't want it to generate a factory for you. You're kind of already handling that. Um, so it might be able like we might be able to make it even more automatic and not need an opt-in attribute. Feels a little scary off the top of my my head though. So I don't know. Uh, type itself is not registered. Only the factory is. And that's important because in needler if we would have registered that type that cannot be constructed purely by dependency injection. If you tried to ask for it, it will throw an exception. We want to avoid that. Um, and then
it says both funk and interface generated by default. Oh, so it's actually I think it means in both scenarios it would be generated by default. I think questions for your naming convention for the factory interface. I type name factory. Yeah. Oh, and then it asks both funk and interface by default or opt into each. I don't know if we could do both. That's pretty cool, too. Um, yeah. I don't know. Maybe we can make this configurable somehow. Um, I could ask, right? And that's the the beauty of this. So, I'm going to ask if we can make that configurable. This is factory lifetime always singleton. Good question. The fact yeah the factory lifetime I think needs to needs to be singleton. The things we create are not going to be singletons. It's being created from a factory. Um but the factory itself I think defaulting
to singleton is totally sensible. We don't have to worry about state. It's literally just a function in a class. So, my answer is I'm going going to type back. Um, and you can see I am in plan mode. If I hit, you can't see my hands on my keyboard. If I do shift tab, see how maybe it's hard to see, but it's going between blue and not. Um, ridiculously last weekend, not this past weekend, the weekend before, I recorded my video and there was no plan mode. I was just kind of planning with it and then it released the video and I was watching it today before I published it and I was like wait a second there is a plan mode but you can see in the video I tried typing slash plan it doesn't exist yet so they just I just got it
updated and it's there. So um naming convention looks good. Uh I really wish that I could do shift enter but I think we still got to do that which is annoying. Uh yes, do both by default and three. Uh yes, always singleton. So it's going to go update the plan and then I'm going to see if I can just flip over to uh implement and and watch it go. Um, we'll see what the plan says because I, like I said at the beginning of this, I've seen it do some stuff where it's very confident. It's convincing me that it's doing all the right things and then I end up looking later and I'm like, "Oh man, we're like we're 10 commits from when it last did this and like it totally tricked me that it was doing the right thing and I just got too
excited." So design decision locked in factory interface naming generation mode both function factory. Oh I forgot to ask it. Um can we have an optional parameter parameter? There's a weird um bug after a little bit of typing in copilot CLI and I've noticed this for for claude. So maybe it's a PowerShell thing, but um my keystrokes to backspace don't get registered. Uh can we have an optional parameter or configuration to change the generation mode between funk factory and both default being both. So we'll see. Um I think the answer is yes. Um especially because with source and I need to clarify this too with source generation um there's a lot of stuff that it's figuring out at compile time for us. Oh I don't I actually wasn't thinking about it on the attribute. I was thinking about it on um on the project level, but
maybe yeah, maybe that's cool. Um both is naming convention wise, both is terrible because if there was a third thing that came up later and everyone was using both, both doesn't make sense for three things. Um so uh let's both um as all instead. Okay. And what else did I want to say? Um do we need this is an important thing in needler now. Do we need to consider any differences between reflection and source gen? Because I've been thinking about this from a source generated perspective. I don't know. I don't think it can do the interface thing that I'm talking about with reflection unless it brings in a dependency on like castle proxy. I don't want to do that. Um, okay. Recommendation. What does it recommend? Generate factory source gen only feature. I agree. I I kind of reached this point where like as I'm
building more source gen stuff into Needler, I'm okay doing that. And if someone was like, hey, I'm using the reflection path and like I want these features, then maybe I come back um and do this funk kind of approach. But yeah, like reflection stuff is starting to be kind of crappy now. So let's go with that approach. So um let's make it source gen only then for now. Okay. Also, there's a cool feature that I had it build. Uh, so I had decorators built in with source generation. Now there's interceptors, too, which is super cool. Um, cuz when it was explaining it to me, I'm like, you're just describing a decorator. Like, what are you talking about? And it's like, no, no, no. It's um it's not a decorator for uh like a an interface or a class. It's mapping everything. It's basically taking a
function and wrapping every other function automatically on the class. So um it's it's really neat. It's very much like a decorator, but it's um like a one to end decorator. Pardon me. Okay, so the plan should be good. I'm going to wait for that to finish. I'm going to see if I can open it up. Like I said, I think it goes to cursor. I don't know why cursor is the default that it's bobbing open. This is taking its time and obviously I've done too much blabbing on this stream already and we're getting near the top of the hour. Okay, so I'm going to you can see down here control Y to view or edit the plan. I'm pressing control Y. We'll see how many um business years it takes cursor to launch on my computer. I just want to show the plan and like
kind of look through it before we go ask it to go do it. But this is nuts. I'm going to give Okay, it it went I was going to give it a little countdown. Let's see. Session accomplishments. Wow, look at all that. Um, cool. Where is the new stuff? So, what's next? So, it's interesting because there's a bunch of stuff in here that is not uh for all of you watching this, it's not relevant, right? Like where where did this come from? This is all previous stuff that got built. Um I get a little bit nervous about having this remaining in the plan because that's extra context that has nothing to do with what we're about to build. Okay. This has nothing to do with what we're about to build. So, we're already like 63 lines in to this context with no relevant information about
what's next. I'm not a huge fan of that. Um, I'm not yet sure how much that throws things off for full transparency. So, something I'm kind of paying attention to, but you can see what's next. Um it says documentation updates like no and no like this is this was already done too. So we're at line 74 before we're talking about the next thing. So it's a source genon feature talks about this um proposed solution two complimentary approaches and you can choose um the mode. Um this is literally what I showed you in code. Sorry this is small. Can How do you zoom in in cursor? Is it control? Oh, yeah. There we go. I just wish the controls in VS Code were the same as Visual Studio. It's like I can't I want to control mouse wheel in like every other Windows program that's ever
been made and uh apparently that just doesn't work. So, this is literally what I showed in uh my example when I was walking through. Um we didn't do this part, but yeah. So, kind of cool. My service factory. Oh, interesting. So, we didn't talk about this at all unless I'm I'm blind. Didn't see it in the chat, which is possible, too. But on the My Service Factory, why did like it it's able to make my service, but you can also create it as an interface. I don't know how it's going to do that or know that. That's very interesting, right? Like, how does it know? I didn't think about this. I just figured we'd have this as the example, right? A create for the type that we're talking about, but maybe it's going to look at the interfaces that it implements. I don't I don't
think we need that. I don't think there's a benefit to creating it as an interface. So something feels off about that. Um I might correct that before we move ahead. Um basically my my rationale for that is like I think this adds a ton of complexity and no value. What I mean by no value is like if you truly only want my service but you uh want it as the interface I my service then like just assign that to a variable that's I my service done. Um, the reason I'm saying there's more complexity is like what happens if my service implements I my service and another interface? What happens if those interfaces are descendants of others? Like where do you draw the line? It just it's weird. It doesn't make a lot of sense to me and I don't think there's any real value. Um,
it talks about detection of non- injectable parameters which is important. value types, delegates. These are things that are inexisting rules for needler that it will not inject some edge cases. All params injectable. So yeah, we could do an analyzer warning. That's interesting. All parameters runtime factory with all params. No DI resolution error. I mean, is that really an error? This one, um, I kind of mumbled it. story, but this is a factory with all of the parameters and there is no dependency injection resolution. I don't think it's an error. I think it's not super helpful, but you might like there's nothing wrong with it. It should work. No constructors normal registration. Okay, this is the kind of stuff where like I'm not totally sure I agree with this, but maybe when I see it, I might have a different behavior or a different opinion on
it. Sorry. Multiple constructors use the best constructor most injectable params. So, this is a really interesting one and um I don't know the right answer. We could have a constructor just to give you an example where um there is an injectable service and then an int and another constructor. It's like an injectable service and a string. Which one should you do? Maybe the answer is it should have both. So maybe I have to take a note of that. Um so a couple things I got to tell co-pilot. I just want to see if it has something around tests. Okay, so implementation plan do this with the generation mode enum breaks it into some phases. It talks about analyzers coming later and then afterwards. So this is the the part that really gets me. It puts all these integration tests at the end and like I
I get it like it's trying to do like do all the work and then test it, make sure it all works together. I think that's going to be the third thing that I'm going to change here is I'm going to tell it to do tests along the way. Okay. So, let me pull this off to the side. So, a few changes to the plan. And so, do the tests along the way in TDD format when possible. Um, I'll leave it at that. In some cases when I'm asking it to fix things, I like being explicit about like red green. Um, if multiple constructors exist uh for possible factory usage support, oops, I have to backspace very slowly. Support, not both. All of them. And then the last thing was actually near the beginning I said we don't need this. We do not need just the
specific type. So after this I'm going to have it update. We're going to switch out of plan mode. We are going to go get it to run. By the way, um when I'm doing this on my own, I am going a little bit faster because I'm not speaking out loud. So, if you're like, "Man, this takes forever to get anything useful." Um the one of the problems was I was doing this fast enough that I was like not paying attention apparently to the tests. So, I'm not going to re-review the plan. We're going to we're going to let it go crazy. I want to see some code. Cool. Rock and roll. Start with Let's see. Um, I'm pretty interested in seeing how it does. I'm going to I wanted to talk a little bit more, but I'm going to let this thing go. I was
going to flip back over, but it's probably handy if you can see what it's doing. But um this is the kind of thing that like this process of doing the plan mode even before it had plan mode in my co-pilot CLI. Um, I would talk through a little bit and honestly one of the biggest things was getting it to give me some different options and sometimes it would give me, you know, four, five, six, seven options to go through with pros and cons and then I could read through and see like some brief example code and and some of the the tradeoffs and it would have a little recommendation at the end. And sometimes it would combine some options and say like we could do option two and four and like here's why. So I would do this for these different features and um get
to the get to the point we're at now, right? Where it comes up with a few phases to go implement um and then we just see it carried out. Um but I yeah I did this across the conversion to fully support source generation. Uh some analyzer rules. There was um there was some refactoring because some of the the calling conventions. You could write code that wouldn't work after things were refactored. So um I had to do some breaking API changes. Uh, sorry if you're one of the two people that use this. I'm I'm the biggest consumer and it's an alpha, so I I broke some APIs. Um, what else? We I had a I had someone request uh they actually they said they submitted a PR and I went to go check it out on GitHub, but the pull request they submitted was just markdown
files um to to implement a feature. So, I'm not I'm not really sure. I think I don't think pull request was the right thing there because there's nothing I'm going to merge. Uh, but they wanted support for the host builder, like the generic host builder. So, I had I don't want to block the screen, but I had um Needler, sorry, I had co-pilot go implement a full support package for um Host Builder. What else? There was already some semantic kernel stuff. Uh I had it put in some AOT example applications where we can do trimming. We can see the source generation actually work. We're getting we're getting somewhere here. Now I understand the structure. Yeah. Okay. Good job. Good job co-pilot. Now I have enough understanding. Okay. Add the factory related helper methods. I feel pretty nervous about this feature. Honestly, I'm not convinced it's
going to do an okay job. I've I don't know. I've been surprised when uh when it did the between Claude and um Copilot when it did the initial change over to use source generation, I was like there's no way this works. like it's such a dramatic departure. I'm like there just is no way that it works. And it did. There were a couple of gaps because it I feel like it built it actually intelligently. Um things that weren't yet fully supported in source generation would fall back to reflection. So it it wrote it in a way that was the most compatible that it could be, which is pretty interesting. It's just not what I wanted. Um, I wanted full AOT with trimming like compatibility. And so I told it like, hey, when you're using source generation, there is no fall back to reflection. Like it's
got to work. So that was really the biggest gap, but otherwise like it literally worked. I was blown away. um forgot a cool um feature that I had at build is like for some of the example applications that are in the needler source code, they're really trivial, right? They're I I'm trying to demonstrate some features like decorators, minimal APIs being registered, blah blah blah. Um, but for more complex applications, if you're like, I have this really big set of types that were registered onto the service collection, because it does it automatically for you. That's the whole point. If you're like, dude, I have no idea what's even registered on this thing or the dependency chain. I actually had it do a sourced generated documentation. So you can turn on a flag in the project and when you build with this flag on it will output
markdown files with mermaid documents or diagrams sorry and it will list out information about you know all the different dependencies and stuff like that. I really want to try it on brand ghost where there's a lot more complication with the types. Yeah, I wanted to to basically see can we build in some like debug tools so that when you have weird stuff going on, you can understand it because it um source generates decorators for you, right? You just define your types and if it is defined as a decorator, so truly wraps something else, we can detect that. We build the source generator for it and then it can show you that in the documentation and it can show you the same thing with interceptors and say like this interceptor is used across these things because one of the things that's a pain in the butt
is like magic stuff is really cool when it works, right? When you automatically wire up all these things and it works, it's like holy crap, how is that possible? Magic stuff really, really, really sucks as soon as it doesn't work. exactly as you expect because now you have to go debug magic. No one likes debugging magic because it's probably obscenely complicated behind the scenes and that's why it feels like magic. So I wanted to make sure that I could have some um some diagnostic tools. Uh analyzers were a big part too. So if we're doing source generation, I want to have analyzers to guide people from, you know, accidentally doing the wrong thing. Um, for some of the analyzers that are built, I'm like, is are there ways that we could we could look at that scenario and even prevent it from being possible in
the first place? Right? So to me, every every situation where we find an analyzer valuable is an opportunity for me to ask the question, how can we not even need the analyzer? But that might be some things over time to chip away at. Uh it might be reality that like it's not possible, right? Like you can't prevent every possible thing. So you need some analyzers to guide people. So, we can see that it's already building some tests. Some are failing. I'm not pulling up the code yet because I don't want to block you guys. Debug fact. Okay. I see the test is looking for blah blah, but the generary code might have a different naming. Okay. It's like messing up its own naming conventions which would generate dependency not dep. Ah yes, classic classic DEP issue. Um I posted on Twitter the one of the
funniest things I've seen co-pilot ask. So, it hasn't come up yet, but you know, it'll sometimes, the same thing with claude, it will ask permission to go run something. And so, I've been approving like, you know, if it wants to do a commit message or sometimes to edit files, it's like, oh, like, let give me permission even though I've granted permission. Um, and I had one scenario I I looked at I'm like, what the heck is this even asking me? And what it ended up being was that it wanted to add a bunch of numbers together. It was trying to count to make sure that the tests were all preserved. So it counted them and then it was like let like give me permission to go add these numbers. And I was like what the heck? So I posted that on Twitter. It's pretty funny.
Um what's this say? So the test expect uh expects that when all parameters are injectable the type should not get a factory. This logic is correct. Actually looking at the I love that right. It's like, oh, wait, actually, um, only include constructors that have at least one parameter. This looks correct. It's It's weird to see it go back and forth. Um, and it's kind of getting caught in a loop here, right? The test expects this to be in the output, but it's not. This means the type isn't being registered at all. Issues my fall through logic, and then it's like, wait, look at my looking at my code again. I check this blah blah blah. I do not continue. So, I fall through. But, let me look at the issue. Wait, it's I think it's getting a little bit stuck. So, I don't know if
we just keep letting it go. This is nuts. Like, it's really getting caught up here. Um, but then why isn't my service in the output? Actually, wait. I will wait. Please. Um, keep consuming tokens. I Yeah, just do that. Looking at the test source more carefully, IDEP 1, IDEP 2 are just interfaces with no implementations. So when determine lifetime runs, all parameters are injectable returns true and we should get a lifetime. Oh my goodness, this is still I see on line 63 checks has do not blah blah blah. So the flow for all injectable params should be has this. So, it's kind of just explaining its logic. Wait, there's no explicit fall through. But wait, actually, but if So, yeah, I think this thing is probably getting pretty screwed up. Um, and then at the end of all of it, it's like, oh, it's not
actually a problem. The issue is my assertion. How many liters of water did we just consume? Nice. All 14 factory test pass. We're going to look at these suckers because I bet there is something wild in here. U based on the conversation that we just read through, I am not confident in the slightest that any of this is going to be okay. I'm pretty nervous, but we'll see. I also love like um I think this is going to be so funny to reflect on probably new not too long from now. But I just want you to have a quick look at some of the tool calls that are on my screen. And um this has been an SLNX solution. So the new solution format. It has been this way um I think since when I created the repository. Okay. So, co-pilot in this particular conversation
has been operating here for quite some time like I mean before today even same uh same co-pilot like chat instance and I want you to notice that it's doing glob for an SLN file. No match is found. Glob for now it has two stars star SLN file. No match is found. Like why? Like what doesn't it feel so silly that it's just doing like these are things that it should have answers to from doing it a million times. Yet here we are. um you know, just some really kind of like dumb stuff that exists and I'm sure not too long from now. The dumb stuff that it does um will be a thing of the past and we can look back and giggle at it. So, I'm hopeful. Now, we have something asking for permission. Can it run the test? Is that what it's asking
for? I was going to say how is it how does it need permission to run the test now and it says it's been passing but I think it's because it's searching the output. It's a like a compound command. So let's see. Like I said I'm pretty nervous. Maybe it said let me get a count summary. Maybe it's going to ask me on stream here to approve running adding numbers together. I would love that. Do you get permission to add all of these numbers? Oh, I don't know. I don't know. Seems dangerous. Excellent. Wow. Okay, it's updating the plan. I want to see its little summary. Then we're going to go look at the code. And maybe it worked and we got super lucky. But I can't imagine. I'm just being fully transparent. If it works, I bet you there are some edge cases that were
called out in the the plan that are not being caught. Now, this is also doing phase one of the plan. Let's see what phase one actually included. What was implemented? We have this new enum, right? Funk interface and all. Okay, we agreed on that. Generate factory attribute with the mode property. We agreed on that. generate generator detection of this and parameter partitioning. We're going to have to see what it actually did for that generates this. So the funk where it returns the service. Okay. Generates the factory and a class says it did it. Types with factories are excluded from normal registration. Good. They need to be because they would not be resolvable otherwise. So that's required. Do we have a test that shows that? Like probably not. I don't really believe it. Maybe it did it. But usually there's some stuff like this where it's
like I implemented a behavior. It put tests on a bunch of other stuff, but there's some like really good scenarios like that that it really should write a test on. It probably didn't. Falls through to normal registration if all params are injectable. Interesting. So, it at one point it said that was Oh, we're not doing analyzers right now. It did say that there would be an analyzer rule that this one last part falls through to normal would be an error. Uh yeah, it's a it is an ask me anything. You can absolutely ask anything about uh career advice. Go ahead. We're just we're walking through co-pilot. We're going to look at some code. Um but if you have career questions and stuff like that, please Jeff feel free to ask. I'm just going to keep blabbing away here, but write your question and uh I
will do my best to answer. So, next in the plan, it says multiple constructor support. So, it didn't do that yet. Um, and then funk registration for each implemented interface. Ah, okay. So, it did it for the actual type but not each implemented interface. I don't think we want that because I said I don't want that for um I don't want that for the factory type. Maybe I missed that in the actual plan. So I'm glad it wrote that because I actually don't want this. I don't want a funk registration for each implemented interface. I want a funk registration if you have multiple constructors that are valid. So, if uh if this were just me continuing on, I would correct it before, but I'm going to jump over to the code and um we'll see what it did. Actually, let me jump. This is what
I usually do. Go over here. I go open this so we can see a little bit more about what's up. Um, I don't think I can zoom in in the the top. So, I'm really sorry because this text is probably microscopic, but um, we got a new file which is the test file. Um, just a heads up as I scroll through this couple things already drive me nuts, I have a region. So, automatically I hate this. I don't want stupid regions in here. I literally have a co-pilot memory that says never use regions. Apparently the co-pilot CLI memory is trash. Um I will tweet about that or post on LinkedIn. Someone's got to do something because I hate regions. Just make multiple classes please. Um so we have these types of tests which are writing C code to go run the generator on. So that
exercises the generator. But if all of the tests are like this, then I'm a little bit nervous that we don't actually see real examples of that showing up. And you might say, well, Nick, what does that mean? Like, isn't this real C code that could exist? Yes, but I want to see these types defined. And then I want to see needler create a service provider and then we resolve the things being registered. I want to see that or else I don't believe that it's real. And if I keep scrolling through here, I don't see that at all. I just see more regions. So what I would do, you can see run generator. So, it's actually going to try to make a uh it's going to compile the code and like, you know, it's it's pretty cool that it does this. So, it actually runs the
source generator. Um, but there's no other tests, right? Type discovery helper. So, there's some enhancements here. I don't want to focus on that that yet because the fact that there's no tests on this stuff is very distracting for me. Um, we got the mode as an enum here. We got the attribute. I like that it adds documentation and stuff like that. It's pretty verbose, but not enough tests. I don't believe that this code does anything like I want because I don't have tests on it. Let's jump over to this question that just came in. Um, okay. So, thanks for your question. Uh, it's a long one. 10 years of experience working as a staff level engineer. Engineer now. First four years of career was consultancy. Okay. Not real engineering according to this person. That's not my quote. Um, for past five to six years in
pure engineering role in banks. Okay. and product based no formal CS degree self-study okay but 10 years of experience doing this so trying to become that ideal engineer what's your advice for path to principal engineer two to five years timeline thanks in advance of course no great question um this is it's a really difficult thing for me to answer without lots of additional context okay so um the some of the things that you've called out you know there's 10 years of experience like that's great um I realize that you're saying first four years was consultancy and that's to you not real engineering Um, but like what what does it mean to to say not real engineering? Like were were you building systems? Like uh were you like I I don't really know what was involved in that because consultancy could be a a bunch of
things but um I I I wouldn't completely write that off. And then for five to six years in pure engineering role in banks I'd be very curious to understand more about the discrepancy there uh from your perspective and it's product based but so the next part no again that's not like you're already working and you are at like a at a staff level right so um that's fine you did self-study no CS degree that's not that's not the thing holding you back so that's okay still trying to become that ideal engineer what's your advice for path to principal engineer in two to five So, couple things I will mention if I don't answer your question in a way that you find is helpful. Um, I'm just going to mention it in the chat so you know, but codemute.com. Um, if you're comfortable and I'm not
answering it sufficiently and you want more detail, you can write in anonymously at codeccommute.com. Uh, and you can put as much detail as you want there. It's it's an email to me that comes from me, so I have no idea who you are. Um I will know probably from YouTube now, but um yeah, if you if you're cool writing more detail about some stuff that you don't want to write in the chat, that's fine. But I'll try my best here. So biggest piece of advice that I have to uh kind of put towards you right now is like depends if you are planning to try to go to principal the place you're working now or somewhere else. Okay. So if you're I'm going to assume that your path to principal engineer is you know maybe at the place you're working right now. And I would
say the number one thing and anyone who watches code commute would tell you that I would repeat this till the end of time. number one thing is like you need to have this conversation with your manager to level set expectations. Okay? Because your manager is going to be the one that ultimately is backing you on promotions. And if you're working at a place where you feel like you don't have a good working relationship with your manager, there's never been support that way. Either you try to help make that working relationship better and be more transparent about those expectations that you have. Otherwise, it might be time to to look elsewhere because if you're not getting that support, you're kind of it's kind of a gamble, right? Because you I could tell maybe you and I talk about this and we're on the same page. We're
like, "Oh, heck yeah, that would be really good things to focus on." If that's not aligned with what your manager thinks, it doesn't matter, right? Like ultimately, that's what's going to be the thing that helps you where you're working. Now there are opportunities to go switch to another company, right? And you could build up the skills truly that you that you feel are relevant for that next level that another company values as next level and then they hire you on at that level. So that's an option too. But ultimately you need to be able to convince someone of those things. So just the other context you said not building I was maintaining system legacy. Yeah. Yeah, I mean but like maintaining we're just running the systems like not coding anything because maintaining legacy systems and still having to code in them you have lots of
interesting constraints but okay but now for six years purely into design and building systems. So again if you're writing code in existing systems even if you're like maintaining them still lots of engineering work that could happen but we don't have the full context. So number one thing is align with your manager on expectations because they will be the person to tell you from where you're at now to expectations at your company for principal level what to be focusing on. I think some of the biggest things we see at that level band are going to be around impact that's more broad. Okay. And so what does that mean? Um I have really struggled with um this for myself but like I would be told like oh your work needs to be visible your work needs to be visible. I'm like, okay, like when I'm being told
go focus on thing XYZ, like this is expectations have been put on me from my manager, let's say. If those are the things that I'm being told to do and that doesn't translate into visibility, then I'm going, okay, well, are you telling me to work on unimportant things? Like that's how it ends up feeling. So visibility is kind of a a weird one to navigate, but the way that I've tried to rationalize this for myself is around doing impactful work at scale drives visibility. So if the work is great enough with enough impact, the visibility for and this depends on the size of the company you're at and stuff as well. I work at Microsoft, so scope is a lot bigger. Um lots of teams and things like that. If I'm doing work that is truly impactful for for my level in the areas that
I have responsibility over, that impact is noticed by not only like my skip level manager, but my skip level manager's peers because they work in areas that are similar, right? They're not the same as us. I work in the routing plane. There are folks that do like O. There are folks that work on deployment and change management. There are folks that work in like other areas of the platform. So if the work I'm doing is impactful enough, other parts of the organization will start to pick up on that. Okay? So it doesn't mean that you have to have one thing that is so huge that everyone in on the planet knows about it. It could be a handful of things that are of enough um enough impact that across a few of them you have people across the org that are that are noticing that
impact. So it it can look a little bit different but ultimately at least for you know from my experience getting to that next level is about demonstrating enough impact at that scale. Okay. So what does that mean? Well this will largely depend on the area that you work in. the responsibilities that you are sort of having right now. If you are looking at your team's road map, the stuff that you're kind of being tasked with, if you're looking at that stuff being like all of it's incremental, right? All of it's kind of like do the next feature, do the next, you know, uh refactor for, you know, improving the code base, whatever. If everything that you're looking at does not feel um Okay. No. And thanks. I appreciate that additional context. Um, if everything you're doing feels like it's small increments and not kind of
like what I'm trying to describe, like impact that's felt more more broadly, that might be an opportunity for you to try and create some of those opportunities. What are you noticing that's happening in your space that could be felt more broadly? Right? Are there things that you notice in your team, other teams where you're like, "Hey, we have this common challenge, whether it's specifically in the code, if it's part of the product, if it's uh a d you notice that a bunch of different teams or something are trying to move in some direction and you're like, "Wait, there's some overlap here and we're going in different directions." Are there initiatives that you can put in front of your manager so you can say, "I want to go lead this, right? make this as a proposal, but you're the one finding it and putting in front
of your manager to say basically like I want to dedicate time towards this because one of the tricky parts back to level setting expectations with your manager is if they have set some expectations for you and you go, uh, I'm going to not do all that stuff we just talked about and I'm gonna go do this other thing that's, you know, more impactful because some bald dude on the internet said that was a good idea. It's not what I'm saying. um because ultimately you have to work with them on what their expectations are. But I do think it's a good opportunity to propose like look for those types of things if they have other things like that that uh that are being talked about in the org like already like volunteer for them right but try to look for those those uh areas of impact
that are outside of just your team and can be felt more broadly. Okay. Next part to that is that um again depending on the uh size of the the team, the org, that kind of stuff is more communication more broadly about these things because sometimes you might be working in a space delivering on this kind of stuff and it's a project that's taking multiple months like as you are doing different stages of this communicating more broadly to different stakeholders about status updates about milestones being met. This is also opportunities for more people to potentially see it andor creating more conversation. So there's more um like opportunity is the word I'll use. There's more opportunity for intersecting with other teams. Um trying to think of a good recent example from work without talking too much. Um there's there's multiple proxies at Microsoft at least even in
the space that I'm in. And so there's multiple proxies and that means that sometimes we build similar things because we encounter challenges separately and then we go oh we should go solve this. So we had a couple of interesting scenarios where it's like uh we're working with a partner team and we're like oh like we really need a solution for this and then we realize just because of conversation and people communicating ideas like oh this other team is is doing this too. Great. like let's work together now. We can create, you know, we can create a bigger impact by channeling some focus and not only have that for the team that was doing it, we can get that for our team, too. And if we do it right, we can actually make that more accessible for at least a third, possibly beyond that team that
we're aware of. And so, we just kind of amplify each other's impact. But that all comes back to being able to communicate more broadly about the the things that you're working on so more stakeholders can hear. Okay. So hope that hope that helps at least to start. Um but delivering at that scale I think is is the move. If you like I said if you're comfortable um sharing more detail and you know you like kind of the direction the conversation's going but you want to give more detail just uh write in a message. I'm happy to to make a video on code commute. It's a whole other YouTube channel. I keep you anonymous and that way I can try to answer your question like this in a way that maybe other people can benefit from. Okay. So, hope that helps. Let's go back to the
code here. So, one of the big things that I want to go back and say is that these um Awesome. Okay. I'm glad that Glad that helps. Thank you again for the question. So here I'm going to take these factory generator tests and I want to say to co-pilot um I notice the only tests that were added are oops this. These tests only check the source generator logic but they do not assert real scenarios uh with autogenerated factories and delegates. We need coverage that shows resolving and executing these autoactories. Oops. Delegate. Any coverage that shows resolving and exceeding these autoactories and delegates from the service provider created from a syringe class using I should um type it this way using okay so I'm telling it like I see that you have the test but I don't I don't think that That's sufficient because what I
really wanted to do was go to the code and then we would go run something and then we would see that it works. But we can't even do that because it it only wrote tests that go take um you know raw C sharp as a string and go run a generator on it. So we'll see. Um, and then I'll wrap up the stream because we're a little over time. And I'm sorry this took a little longer to do. But yeah, this is um this actually a good example to call out because this is the exact kind of thing that was happening over the past week where it wrote a bunch of tests. It would run them. They, you know, they're all passing, nothing regressed, right? I could see that it wasn't touching old tests and then they were breaking. It's like none of the old
tests were touched. They're still all green. We're good. But it was doing so many scenarios like this where it's using code that it writes into a string, running a generator, running an analyzer on that completely artificial code and going, "Cool, the analyzer or the generator does what I expect." And I'm like, that's nice. Apparently, it fooled me a lot, but I want to actually see the real thing that's created from that in action. Awesome. Yeah, please. Yeah, if you're comfortable, submit a question on Code Commute. I' I'd love to to do a follow-up video for you. If you like if you take a couple minutes if you go to code commute on YouTube you can see like the format um and if you're comfortable with that then great. I really enjoy making code commute videos so I'm always happy to answer questions. Um you know
I do programming tutorials I do these live streams but my favorite thing is the code commute videos. Um they're a lot of fun to do so happy to happy to try and answer. Okay so ah what is needler? Yes. Build a C# monor repo 14 gigabyte project crawler. Oh my goodness. To build a dependency graph and DB for quering things. It's called Tangler. Oh, very cool. Um, so Neler, I'm just going to put the link in the the chat again. Give me one sec. It is a dependency injection framework. And I say framework kind of loosely here. So um I use Neler because I build a lot of plug-in based architectures and a lot of the plug-in architectures I build are not I don't have a requirement that I actually dynamically load plugins at runtime. That's kind of the side effect. Um what it what
most scenarios actually are is that I just like plugins as logical separations of things and I actually have all this information at compile time. So, uh, needler was entirely reflectionbased in C to go, uh, basically automatically register all of your types. So, in C, a lot of the time people end up writing extension methods to go register their types onto the service collection. You build a service provider from the service collection and then you can resolve your types automatically. And I hate doing that. I hate having to write an extension method or update an extension method for every type that I want to have. And so needler is opinionated in that it registers things the way that I like to register them. So almost everything's a singleton because almost nothing I create has any state. So um I only really need one instance of things.
Uh DTO's, you know, uh data transfer objects, these are exceptions. They don't even get registered on Needler. uh the service collection. But anyway, um it allows me to just create types and then they automatically just are usable. I don't have to go anywhere else to go touch things. I used Copilot and Claude to go change it from reflection over to source generated. So that means that because I do have that information at compile time, it will use source generators and literally write out all of the code automatically to go do all those registrations. So I don't have to do them by hand still. Um, and that means for things that are like uh using trimming for AOT and they trim out a lot of um of of code that's not being used, reflection usually breaks for that. and we can basically trim out all of
the stuff that's not used and uh all the stuff that's source generated sticks around. So, pretty cool. I like it. I use it in uh Brand Ghost primarily. Brand ghost is the for folks that don't know, it's a service that I use for posting all of my social media content across all the platforms. So depending on how you got here, um you might see my stuff on Twitter, you might see it on LinkedIn, or maybe only watch the YouTube videos or wherever, right? Um I post all my content to every platform. I use Blue Sky Threads, Tik Tok, Instagram, Facebook, LinkedIn, Twitter, what else? Mastadon if I didn't say that yet. Um I don't know. I use everything. Um, and so I I built Brand Ghost to be able to publish all this stuff everywhere all the time. And uh, so yeah, uh, needler is
the dependency injection like helper framework. I don't want to claim that I like invented dependency injection. That's crazy. Um, or that I built it from scratch. No, it's just the way that I I do the automatic registration. So you can see it's doing some stupid stuff again. The factory interfaces are generated in this name space, but the test file doesn't have a using statement for that namespace. So this is a potentially an interesting usability issue. If every time you want to use the factory, is it always going to put agenerated namespace on it or is that just coincidentally, you know, the the name space that it it built it? I I don't know the answer to that. So, little bit nervous that it's going to have some, you know, funky usability things, but I'm hoping we're almost there. Nice. All 17 factory integration tests pass.
Let's pull this up as it's going through some stuff. So, factory source gen tests are actually what we want to look at. Let's zoom in on that. Okay. So, again, I'm going to jump to the other test file. super slow. You can see that it is putting C code into a string and then running the generator on it to make sure that it could find if it generated some stuff, right? That's not that's not a bad test. I mean, this is kind of silly that it's only like some of these assertions are a little dumb, but the concept is not bad. I want also a test that does the real thing. I want to see that if I have a syringe using source generation and we build a service provider that I can just ask for this thing. That's pretty cool. Now the again the
assertion seems dumb but it's just saying is the factory interface resolvable? Okay. Simple service is the function resolvable. Right. Can we ask for a funk that takes in a string and gives us that? Right. This one is factory creates instance with runtime parameter. So it's kind of like the first test except once we have the factory, can we call it? So do we get a non-null instance? Did this parameter actually get set? clearly uh we haven't looked at the definition of the type but it's also checking we have a dependency that was passed in and that the dependency is what we expect right so there's more to this we could check and assert like maybe we need to make sure that you know was the the right lifetime used or something um and maybe that's in here somewhere but uh this says funk creates instance
with runtime param what did we just look at oh the factory three does it and this is if the function the function does it. So the test looks almost the exact same but one is using the delegate and the other one's using the interface. This is factory creates instance with all runtime attributes. Oh man. Okay. This did two parameters, right? Not just the one. There's a string which is not injectable because we're not going to automatically resolve strings from the dependency container. Awesome. Thanks for your question. Take care and yeah, feel free to write in. I appreciate it. So, we can use a string and an integer because both of these are um value types that we're not going to have on our container. This test is ridiculous. Uh funk creates instance with all runtime parameters. Okay, so oh that's just the name of it.
It's just really long. So that we have the interface and the function approach. Function is resolvable. Pretty boring test, but we had this for the factory as well. Funk only mode. Okay, so again this is important for us to see because this is a requirement. I I did ask that I want to have um an attribute where when we and we have to go look at the actual type that's declared but try to get the interface which shouldn't exist. Oh wow. Okay. Interesting. Let's we'll look at this in just a second in more detail. But I did say that if you have this mode that we can toggle it. We shouldn't have an interface if it's only the function mode. And so what it's doing is it's trying to ask for the type and this follows the naming convention. This test might be a little
brittle, right? It's a little brittle because just to give you an example, if it was automatically putting stuff into this generated namespace and I said, "Hey, Copilot, I don't want it in a generated namespace because that's not what I want. this test might not get updated and it's still going to pass. Kind of awkward. Um, it's still going to pass because even like basically if it actually did break and it started generating it now this name space we're moving away from. So these kinds of tests, like when you have a lot of them over time, you might have some tests that are lingering that aren't really adding value. But overall, this did a pretty good job. Um, most of this is just kind of doing the inverse interface creates instance. Okay, so it's it's basically just switching the mode and kind of repeating all the
tests. um factory is singleton. Okay, that's good behavior. I did say that the factory itself should get registered as a singleton uh when we're creating instances from the factory. They're not the same. We didn't explicitly ask or like we didn't this is the behavior I expect. I don't think at any point I said very succinctly to co-pilot like factory uh maybe you might expect the factory returns the same thing um I mean these are different strings if we had con one here twice should it return the same instance right I don't think so but it's also not exactly what this test is doing multicon this is a good one okay this is a a complex one multiconstructor both overloads available. Okay, so we asked for this interface, right? And this type, this is crazy, the naming uh the factory interface always starts with I and
ends with factory. the type that it's a factory for, get ready for this mouthful, is a multiconstructor factory service. Oh my goodness. So, because there's multi multiple constructors on this thing, this was a requirement I had. I said if there's multiple, I want all of them to show up, right? So, it it is doing that. I think it's really cool. Funks for both constructors. same idea but for the different uh delegates. So really awesome job on this. It it ran them. I would still run them myself because I don't I don't trust a damn thing this thing says. Um I'm just kidding. But you know I I'm pretty skeptical. And what was the other thing? Oh, one one thing and we should look in Visual Studio. So this is Give me one sec. It's in this file. I'm going to go look at this in
Visual Studio because I think there's a super interesting, you know, opportunity for improvement if it didn't already do this. So, hey Kenny, welcome. We're right near the end of the stream, man. But welcome. Um, one of the things that makes me a little nervous here, you can see that like Visual Studio doesn't see this generated yet. Oh my goodness, that is super awkward. If I go to build this, will it? Okay. Okay, now it's resolved. Awesome. Now, if we F12 it. Come on, do the thing. Feel like Visual Studio is being thrown off a little bit. I want to I want to see the generated code because what I wanted to before getting very curious about that. Ah, okay. It does do it. No, that's the wrong one here. These create methods, right? I would love if we had some dot comments automatically put on
here, right? It's going to go generate the code for us. it might as well document it effectively if it can. That would be cool. Um, but it's not doing that. So, I don't know if it's because Visual Studio is a little stale here. Uh, it might be just that by source generating this stuff. It's going to be a pain in the butt. You can't uh I'm I'll say it, but I'm pressing F12 so that I can jump to the definition and we can't get there. Um, it's simply just not going. Um, which is super annoying. If I Let me try unloading it. I'll reload. Be an unfortunate side effect if uh if that's how it goes. But what was the name of that thing? Here it is. Okay. Um, it might have just been a little bit of stale Visual Studio stuff. Nice. Okay, we
can jump to it. This is what I wanted to show you. So, all of this code might be hard to see, but you can see factories.g.cs. The G.cs is common. Sorry, I know the text is very tiny. Um, that is common nomenclature for source generated code. You can see like all of the code. I'm just going to scroll through top to bottom super fast. All of this is automatically generated. Okay, we didn't make that. Um, we do have register factories that is going to add all of these factories on. So, that's cool. All of these types though were automatically created. So, one of the things I was saying is like it would be kind of cool. Oh, we do have it. They did put a summary. I was That's what I was asking for. So, if we go to the bottom. Okay. Um, it's minor,
right? It says creates a new instance of multiconstructor factory service. But like what's neat about this is if I jump into it, we could ask Copilot because I thought it might let me type in here even though it's generated. Um there's other XML doc tags that we could do like we could have the parameters named. I don't know how it would decide what to put in there, but we could do that. We could talk about return values. Um, but the point is that if it's generating code for us, like we could have it be even more verbose because it's it's free, right? Like you're not typing this by hand. So, uh, one of the things that I'm trying to think about more in needler is like, cool, as we generate stuff more automatically, are there ways that we can enhance the developer experience? Having IntelliSense
working really nicely is is one way. um having flexibility to have a a factory interface like this. I think that's super cool. I didn't think that was going to be possible, but we get the interface and then it's backed by a real um a real factory. Super cool. Yeah, I think I think that's where we'll wrap it up. Um thanks for being here. I wanted to show you a little bit around like essentially this is what I was doing on repeat for different features in Needler. Um, if you want to check out Needler, I've kind of shared the the link in the the chat a few times now. It's just uh on my GitHub. It's just called Needler. Need dlr. It has a funny little syringe dude as the I don't know the logo I guess you'd call it. But there he is. Oh, I'm
not sharing my screen. There's needler. Um, but yeah, I use this in Brand Ghost. Um, and I have a lot of fun building it. It's been a it's been really cool using Copilot CLI to kind of take it to the next level. So, um, hope you found that helpful. I did, uh, mention that I have a couple of YouTube videos that I was putting out, one of them today. Okay, give me one moment and I'll just show you that it's there if you want to check it out. This video here, I'll put it in the chat. But um I'll pull it over here as well. That's me. That's You can't see my screen. That's my dumb face. Um but yeah, in this video I kind of walk through a lot of what you Come on. Um same idea, right? where I'm kind of showing the
changes that were made. Unfortunately, I lost all of the chat context that I wanted to show. Um, but I I walk through how I used uh Claude and Copilot to go do a bunch of this stuff. Um, and yeah, it's been it's been a lot of fun. And honestly, um, without AI to help with it, this is the kind of thing that I probably just would have, I don't know, put off for years or something or never done it because like the the value ad for me to go spend time on that versus doing something else. It's like, I don't know, man. there's probably way more important things for me to spend time on. But when I can delegate the work, uh I'm not the one typing everything. Um just a huge huge productivity boost for me to go use that. Um but yeah, uh
Copilot CLI has been pretty interesting and I'm definitely enjoying it. So, thank you for watching and yeah, check out the main dev leader channel if you are interested in like either tutorials or or walkthroughs on on how I'm using this stuff. And then my other YouTube channel I linked in the chat is code commute. And so if you have uh you know software engineering questions or career questions, just go to codecommute.com. You can write me an anonymous message. I'll make a a video. it goes on the YouTube channel and then I can try to respond to you in a way that helps you and and other people. And of course, if you just want to watch a video and you come up with a question, just leave it in the comments and uh I I read through them and I make video responses. So, thanks
for being here longer than usual stream and I will see you all next Monday, 7 p.m. Pacific, or hope to at least. So, take care and have an awesome week, folks.