Want to learn about plugin architectures and how you can leverage them in your applications? Tune into this livestream where I'll show you some of the basic building blocks in C#. If you use other programming languages, you may be able to adapt some of these things to your own language and frameworks.
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
All right, let's see what we got going on here. Just waiting for the streams to pick up any day now. Cool. I think we're just waiting on Substack. I'm not going to be going to Instagram today um because it's going to be a pain in the butt because Instagram is a vertical feed and we're not doing the typical thing today. We're going to be doing a programming talk and this is going to be from a conference I just attended. So last week I was at a conference called commit your code in 20 or sorry in Dallas. It's commit your code 2025. And so I got to be a speaker there, which is pretty cool. Um, I went there before, not to the same conference, but same organizers. So, uh, Danny Thompson, he's Danny Thompson has joined the chat on these streams before, and he's been
like, "Hey, what's going on?" And I've had to be like, "Hey, I need to message you to figure out my speaking slot." So Danny Thompson runs this and uh the Dallas software um group is basically the organizers. They do meetups and stuff every two to three weeks in Dallas which is awesome. And so they ran this conference or Danny organized this conference called Commit Your Code. The second year they done it. It was a huge success. Um they had you know speaker tracks jam-packed for two days which is super cool. um you know all sorts of different topics. So like from leadership and management to like JavaScript to AI to .NET to you know cloud stuff like all sorts of things. So um I yeah I think it was a huge success and uh was you know very fortunate to to go speak there. So
I figured I'm going to redo my talk and I usually do these streams for about an hour. This talk was 25 minutes. So, um, there's hope I can hopefully go a little slower, take some more time to answer questions on this stuff. Um, and yeah, I think I'd like to do that. So, I'm going to go ahead. I'm going to share my screen, folks. This is, um, from my perspective still like an AMA stream. So, if you have questions, like jump in the chat. Um, I'm watching Substack chat. I have, um, the reream chat pulled up in front of me. Uh, what else? I think that's it. Oh, I should start by sharing the repo. So, give me one sec. Hopefully this works. Can you still see me? Hopefully. Um, so I have this repo and I'm going to put it in the chat. This
is just my my dev leader repo. So I use this on GitHub uh for you know sharing code samples and stuff that I usually have in my YouTube videos. But uh I decided when I was giving my talk in Dallas I put a QR code that linked to the repository and I said hey there is going to be a folder called CYC205 and if you want to learn about plugins I'll have a bunch of different resources and stuff. So uh link is in the chat. You can literally download the slides that I'm going to be sharing and um there's a few links and as we go through this stuff if if uh there's stuff missing and people are like hey what about whatever I can add some links in here. So um I do I I know already that there's more YouTube videos. I used
chat GPT to help get this put together but um I'll link in additional YouTube videos here. I actually did this talk before when I was in Dallas. So, you can see this link says plug-in architecture in C. Uh it's an AMA stream. This is the the stream that I gave after last time I was in Dallas. But, um yeah, there's a bunch of stuff here and that way if you're interested in building in plug-in architectures, you can at least have a starting point. And you can see after CYC 2025, I'll have a live stream and add that to this page as well. So that's that. For folks that want to see this material or um if there's more followup on on plug-in based architectures, which is the talk today, then you can check it out there. So let me pull this up. Uh I'm realizing
that I probably need to figure out something with my camera. So, will this work? Let's see. Oh, it's a it's a little nick. Can we do that? Is that going to work? I don't I can't even select that. Um, I got to block this person from chat. Bye. Um, anyway, I'll maybe I'll keep my head there for now. I might have to hide the chat as I'm going through this. I can still see the chat and if there's uh questions and stuff in the chat, I'll maybe pop it up. So, let me go ahead and do that. Also, folks on Substack, it looks like the stream is totally frozen on my side. Oh, it's not. Okay, I just refreshed it. Um, unfortunately, I can't move my little head in OBS. I don't know why. Let me see if I can give it one more shot.
Nah, I can't select it. So, I can either turn me off or I can stay on. Maybe I'll I'll stay on for now and I'll try to pay attention. But anyway, welcome to building plug-in architectures andnet. So, this is literally the set of slides that I used. Um, actually, I should make a note uh because I think this is super important. Give me one sec. Okay. So, um I met someone at commit your code and he's also another speaker. His name is Mark. And Mark watched my talk and Mark gave me some feedback after which I thought was really helpful. And I'm sharing this because this is in my opinion a really good way to give feedback that was constructive. So Mark said some really nice things about my my presentation. He talked about how uh I sounded clear and articulate when I was talking.
And then the feedback that he gave me was, "Hey, you know, more like goldplating. I'm not trying to nitpick, but he said, it would be really good if you cleaned up your slides because there's a little bit too much going on and if you are trying to get us to focus on some things as the audience, um it's hard to pay attention to where to look." And I thought that was really good feedback because he was trying to be helpful. And that was something that I thought about before I gave my talk. So you're going to notice that I have not cleaned up the slides yet. They're going to be pretty busy. And the reason for that is that I wanted to put more code into these slides. And you know, I didn't know how it was going to work. Not a lot of real
estate on slides, but I have some ideas for how to make it better for next time. So let me get my head out of the way. Boop. Okay. So, I put this QR code up. This QR code that you see here links to the repository um that I put in the chat. So, if you're can't click the link or whatever, if you scan that QR code, it will take you to GitHub. Look for the CYC 2025 folder. But in this talk, I go over who I am and what I do. If you're watching my live stream, you might already know that. talk about in my opinion what pillars of plug-in architecture are and sort of why I like to build with plug-in architectures. Let me bring my little head back here. Maybe I'll bring the big head back for now. And um I talk about
this because I like building plug-in architectures. And my goal with this talk is not to tell you that plug-in architectures are the only way to build software, but more like these are the reasons why I like to build with plugins. And that those might not be reasons that you agree with or they might not fit with what you're doing. That's totally cool. But this is why I like plug-in architecture. We'll talk about the components and structure uh sort of in general. Uh I'll talk about scanning and registration. So how do we find plugins and the the type information we want to work with? I'll talk about two different types of plugins. And I've kind like called them kernel and feature plugins, but um I don't know if there's technically like official names for these things, but this is what I refer to them as. And
then there's a a bunch of topics that are at the end. And if we have some time, I'll go through them. Otherwise, if there's questions, put them in the chat. I will answer as we go. Um if they're not related to the stream for for this stream, I'll answer them at the end, but I will come back to them. Usually, I just interrupt whatever I'm doing. Okay. So, Let's go. Let me get my head out of here again. Okay, so I'm Nick Constantino. This is me and my wife on our wedding day. I've been told it's the the happiest day of your life. And then it's I think she even told me that no day in the rest of your life is as happy as your wedding day. Um but yeah, that's us getting married a couple years ago. Uh these are my two dogs.
This is Laya. Laya has been on stream before. She bursts in the room and she snorts and farts. And this is Loki. Laya and Loki are not brother and sister or mother and son. They're actually aunt and nephew, which is kind of cool. Uh, but Laya is I think she's 10 years old right now, and Loki is a couple years younger. Uh, the running joke with my wife and I is that Loki is always three years old because for the longest time I didn't know, and I just kept telling her he's three. Um I used to work at Magnet Forensics which was a startup when I started there. We built digital forensics software and I built a lot of desktop software in C at Magnet Forensics and then I moved over to Microsoft just over five years ago. And so those are the two companies
I've worked at in my professional career after doing uh six internships in total. So I've worked for a little while but basically majorities between these two. a startup that's scaled up and big tech. So, those of you that watch my stream probably know me from YouTube and social media. So, I try to make as much free software engineering content as I possibly can. I work on something called Brand Ghost, which you hear me talk about on every stream that I do because that's what I'm building. And Brand Ghost is the thing that helps me get all of my social media content out to all of the social media platforms. And then there's the Space Needle kind of covered up by everything because I live in Seattle, but it's a small detail. Let's bring my face back. There I am. Okay. Uh we'll jump over to
the next slide. So pillars of plug-in architecture. So these are my focal points for plug-in architecture. There might be other reasons why people consider this kind of uh architectural pattern for building applications. Uh but these are the reasons that I like it. So we get modularity and isolation. And you'll see this in an upcoming picture, but the idea with this is that when we build plugins, these are generally uh self-contained. So you might have something like a, you know, a dedicated project that builds into a DLL and that is your plugin. It's, you know, a single unit of functionality that you want to work with. So modular, it's isolated from some of the other code. We get extensibility and flexibility. And between this line and the next one that says reusability, um the idea with plug-in architecture is that we can add in uh or
swap out plugins for different capabilities. So with kernel plugins, which I'll talk about in a moment, we can change implementations of things. So you can swap out your logger for something else. With a feature plugin, we can add in more features and extend the application or swap out plugins for different features. And then reusability. What I mean by this, it's similar to the previous point, but you can actually, let me talk with my hands for just a moment. I don't know if this helps. It helps me think at least. But we can take individual plugins that we put with an application and we can actually sort of repackage the same application, same core application with different plugins. And that means that you can take something and publish it one way, publish it another way, publish it a third way. and it's the same like pieces
or the same things that you've built, but by packaging it up differently and using different sets of plugins, you might be able to get um sort of like entirely different apps or for different use cases as a result of that. Um might be a little bit complicated to understand, but um if as we're going through this, the sort of applications that I want you to think of because you're probably familiar with them are like Visual Studio or VS Code. like the fact that you have Visual Studio and VS Code where there's all these extensions and stuff you can add in that's a plug-in based architecture just for what it's worth. So keep that in mind as we go through. Let me swap back here. Okay, so testability is the fourth pillar and in my opinion the reason like it's not just like oh it makes
it it like you know perfectly testable or something like that. I will talk about some tradeoffs or different considerations with testability a little bit later. But the reason I like plug-in architecture is how we end up testing things is really aligned with how I like to test things. And what I mean by that is that when we get modularity and isolation, um, you can kind of think about your plug-in as a unit. And yes, you can still write unit tests for code within your plugins, but you can also test your plug-in like in isolation and kind of think about it as a as a unit of functionality. And if you think about this and what I'm saying, if you're familiar with heavily unit tested applications that don't have functional tests or like integration tests, you'll probably be thinking, hm, doesn't that lead to some other
challenges? The answer is yes. And we'll see that in a little bit. So, next slide has a really ugly diagram. Let me get my head out of here uh so you can see the whole thing. When I made my presentation before the original one, I had more ugly pictures and I basically just tried to condense them down into one big ugly picture. I'm terrible at drawing diagrams. I'm really sorry, but this is the best I can do. So, um, when we talk about components and structure of, uh, you know, a a plug-in based architecture, the thing that I have at the top is the entry point. And I did draw it thinner on purpose. Um, it's a subtle thinness compared to the rest. But the entry point is generally in plug-in based architectures, at least the ones that I've built, very lightweight. And it's lightweight
because we're actually pushing a lot of the work to other spots. The other thing is that if you're familiar with um like traditionally for dependency injection, right, if if folks are familiar with like ASP.NET Net Core, right? You've probably seen, you know, all the examples online or in your applications. We do things like create extension methods where we say, okay, like I want to go, you know, uh, builder.addervices for some feature, right? And you have all these extension methods you build out. We're not going to be doing any of that. No, no extension methods and stuff because we're going to be dynamically looking for these things to register. And that means our entry point can really get shrunk down. We'll see some code coming up in just a moment. Um, business logic. I actually wrote here in the slides, you have a freedom for mixing
in other architectural patterns. What I mean by that is like personally I like building entire applications where almost the entire thing is a plug-in architecture. But there's no reason you have to do that. It's just a preference of mine because I like building things that way. If you, you know, want to do like, you know, clean architecture or like layered architecture, whatever you want to build that works for you, go do that. But, um, there are going to be some pieces that if you wanted to have a plug-in architecture as part of what you're building, like so you want most of your application to be one type of architecture, maybe where you need plugins, you incorporate some of these pieces. So um I am of the mindset that you know you can have applications or services whatever where you don't just have one single architecture
for the whole thing. You can mix and match but personally I just like using plug-in architectures for the whole thing. Uh if I'm working on a team and there's a different opinion about that then of course I will do like sort of what makes sense for the team. But when I'm building stuff on my own the way that I like to build things is with plugins. Next up, I have this little red box here that says SDK. Um, you can think about this as like framework or SDK. And really, this is going to be how we interface with our plugins. Um, it's not totally obvious from here, but when we see some code later, the SDK itself is actually a shared set of like interfaces or uh like data transfer objects, really simple classes. It is a shared library that your plugins can see and
your core application can see as well. Because one of the main ideas when we talk about plug-in architecture is that your business logic should not directly depend on specific plugins. And what I mean by that is like specific implementations, right? We want to think about talking to the SDK. And because we've configured the application a certain way, talking to the SDK allows us to access plugins without having to know the specific plug-in implementation. And it works the other way too. So if you want your plugins to be able to uh to either talk to other plugins or you want plugins to talk to the business logic, they don't do that directly. They talk through the SDK. So your SDK is how you allow these things to interface with each other. Okay, that's what this red box is. Next up, we have kernel and feature plugins.
So I have these four kernel plugins on the left here. Um these are not what's a good way to say this? I don't see this as like a a hard and fast rule like you must follow things this way. Um, this is a generalization of the pattern that I've seen from doing this a lot, but I refer to kernel plugins as I wrote it here like core functionality you inject into your application. And the examples I gave right below I think are some good common ones that I think of. So like logging, right? I like to use Serogg as my logger when I'm building C applications. So I could have a Sarah log plugin that is going to provide the implementation of logging to my application or I might use open telemetry right and I want that used um you know and specifically like I'm
integrating with Azure or something or I'm integrating with graphana uh or Loki right and I want to make sure that whatever I'm using for telemetry uh I'm injecting that implementation and the idea with all of these is that like if you think about in your applications you might have an eyeloger. You could argue that like your eyeloger maybe that goes in the SDK perhaps, but the idea with these kernel plugins is like these are literally core implementations that you need in your application in order for it to run. The alternative, which I'll touch on in just a second, is feature plugins that extend the application. So you can see here I say inject the implementation into your app. Right? So if we think about Sarah log as an example, we want to inject the SAL log logger into the app and we shouldn't have to
touch anything else in the app to make it work. Right? So we just configure our app to say use the SAL log plugin. Um when we look at a code example and if you're reading this you might say well why do we need a plugin for that? like why can't we just do the thing that we always do which is like builder.services.add sarilog and you absolutely can do that there is you know no reason that I'm trying to convince you otherwise but my point is that we can use a kernel plugin to dynamically do that instead of wiring it up manually. Next up is feature plugins. I kind of hinted at this, but the difference between a kernel plugin and a feature plugin is that a feature plugin does not inject a core piece of functionality like the implementation of it. It's not a logger.
It's not your off or your caching, but it's like a new feature that you want in your application or a what's a good way to say this? Like a variation of a feature, right? So, it's something that you can use to extend your application. it's not core for your application to run. Feature plugins do interact via the SDK or your framework. So I kind of touched on this already. So you could have something like an I plugin obviously come up with a better name than just I plugin but this is an interface that is provided by the plugin or you might have I sum API whatever that is that your plugins can call. So again, this would be like on your SDK and your plugins know that they can call it if they want to talk to other things. Now, at this point, you might
be saying, "This is great and all, but like what the heck is going on here? How does this all work? So, how does it come together?" And the secret ingredient with all of this is our best friend, dependency injection. Woo! Um, so at this point in the talk, I would say if you're not totally familiar with what dependency injection is, don't worry. Um, there are plenty of resources online. I have lots of, you know, videos on my main channel, Dev Leader, that talk about dependency injection. Recently, I actually did a what I consider like a pretty decent like beginner intro to dependency injection for ASP.NET Core. It doesn't get into like all the behind the scenes of what's happening, but it kind of walks you through like how to leverage it. So, if you're not familiar with dependency injection, some of these things coming up
might be a little bit murky. Like, I don't really get how it works. That's okay. This is just a reminder to you that like dependency injection in my opinion is quite important for a plug-in architecture. So, you might have some homework to go do and that's okay, right? So, you can keep following along. Just take a note that if you're like, I don't really know what dependency injection is or inversion of control or dependency containers or whatever, if if that sounds like it's crazy magic, then again, take a note. You can follow up on this stuff later. Don't worry. Dependency injection. So, um, with plug-in architectures, you can use kind of whatever is your favorite, right? So, let me get my dumb head out of here again. Um, so you can use the built-in stuff like the I service collection or you know I service
collection service provider like combo. There is a nougat package called screwdor that you can use for assembly scanning for years and years and years. I use something called autofac. like autofac has historically been one of my favorites for dependency injection, but there's plenty of other ones and there's, you know, there's way more things than I have on this list currently that I've not even touched or used ever. So there's plenty of them, but I think most commonly people use um I service collection service provider. Probably don't even touch screwdor. Um and autofac used to be quite popular, but I think that because this combination's come so far that autofax kind of uh less necessary, if you will. So something to consider, but you can use whatever you want. The idea with dependency injection how it fits into plug-in architecture is that we want to basically
do this pseudo code that I have written here. So we'll use assembly scanning and all that assembly scanning means is the following. For each DLL that we're interested in finding plugins, we want to pull out the types from that DL that we're interested in. So we're going to be using assembly scanning for that. there's some reflection involved. And then we're going to take those and we're going to wire them up to our dependency container. So that just means that we're finding the types that we're interested in. We're finding the plugins and then we're adding them to our dependency container. And that means that we can use them when we want to go resolve the plugins from our dependency container. So I have a note here from doing this talk and for right now of course that this setup for this talk is going to be
talking about doing this stuff at startup. So when your application launches, what are we doing to get plugins registered? And you can absolutely do a plug-in architecture where you know in the middle of the application's life cycle, you have a user that's like, "No, I want you to load this plugin right now." And you can go do that. You can also unload plugins while it's live. But um most of the things I build are pretty good with just doing it at startup. um a reminder like I said, hey, keep Visual Studio and Visual Studio Code in mind. What does it have you do when you install a new extension? Visual Studio is like, hey, we're going to install this when you're shutting this thing down. And that way when you go to start it back up, it's there when you're ready to go next time.
So, just keep that in mind like that this is a pattern. And that's what I'm going to be focusing on, but you can do it other ways. Okay, this next slide is going to be a little bit jarring. That's on purpose. I swear. I have to yawn really bad. You couldn't see it because I was off the camera, but I needed to get that out because I was holding it in and I kept pausing when I was talking because I'm like, "Oh, I don't have it in me." Now it's out. Okay, so this slide is terrible on purpose though, I promise. And what you're seeing on the left is literally a screenshot from one of the solutions I have. And you can't read it, but the whole point is that I wanted to show you that this is really a set of projects that I
have. And I I drew a bunch of arrows to uh to a bunch of these plugins to show like I got kernel plugins mixed in here. I have feature plugins to extend it. And this is from Brand Ghost. So, that thing that I talk to you guys about on every stream at the end when I'm like, "Hey, here's all this stuff I got." This is a a screenshot from the plug-in folder for Brand Ghost. It also has some of the test projects. So, there's a bunch of extra test projects in here, but this is real. And so, I wanted to show you this because there is a ton of plugins. There's a lot of functionality. Each one of these is like isolated on its own, which is nice because that's why I have a dedicated test project for them because I can just go test
that thing in isolation. We'll come back to test in a little bit, but the idea is that we have all of these things. If I were to personally, I can't imagine looking at the the program.cs CS file or the app startup file if I had to do this without plugins because it would be, you know, thousands of lines long registering all this stuff. Be a nightmare. But how does it work? How do we get this to come together if we have all of these plugins, right? There's I don't know how many there are. There's a bunch probably 30 plugins, maybe more. But there's a lot. So, how do we make this all work? Well, here's a bit of code that does it. Okay. And I wanted to show you this because it's not a lot of code. And this is literally the the startup for
Brand Ghost, right? It's 20 lines of code. That means when I want to go add a new feature, I've talked about this in other videos and why I like this kind of stuff, but when I want to go add a new feature, I don't go anywhere and say like, you know, register services onto my dependency container. This is just the the startup. This is just what it is. So, we have a canc Oh no, we jumped ahead. We have this cancellation token. Obviously, line four is pretty trivial. lines six through eight is just so that we have a default logger when we're configuring things. So because logging and again pros and cons to everything logging in brandost is a plugin. It's a kernel plugin but because it's a kernel plugin we don't have access to it before we've configured the plugins. So I have a
default sort of startup logger. It just logs to the console. This works well like when I'm launching things in Aspire in Azure, I can see things written out to the console. So, it's still there. Um, and it's only used at startup. Once the app's running, it's configured. It's using the logger that's configured in a plugin. So, so far we have lines four through eight, which is really just a little bit of basic configuration. Line 10 and 11, we're just making a factory for the web application. And then lines 12 through 19, I just it's written out pretty verbosely there. Um, but this is really just to create the web application, right? And I pass in the command line args on line 16. And then line 20, I'm just running it, right? So there's nothing here. Now I'm cheating a little bit. And you can see
that by the last thing I wrote on the slide. Like what is this code actually doing then? because it can't possibly just be that simple. I already talked about things like assembly scanning and registration. Like where is that happening? So that happens behind the scenes. But there's still not much code to do it and I want to show you that because this is what scanning and registration looks like at a very high level. Uh let me get rid of my head. Well, in a second I'll get rid of my head. The only code that's behind my head just says build service provider. So you're not missing much. Um, I have done other videos showing my uh, Nougat package called Needler. And again, I'm not telling you to go use it, but um, something like Needler, Screwdor does a very similar example. What you're able to
do is get a bunch of the functionality you see on screen for free, right? And so that means that the code I showed you that on the previous slide that was only 20 lines of code. It really like is that it's just that you have like use screwdor and it will go find the things for you. It's a little bit more than that. It's maybe another 10 lines of code. But the way I have it wrapped up in needler, it's all it's less than 10 lines of code. So here this is just going to be the pseudo code on the left and then uh a very sort of like naive implementation on the right. But the pseudo code for scanning and registering things is we're going to say for each assembly in our target folders that we're interested in. That could be your bin directory
where you're running from. That could be a dedicated plugins folder. Whatever you want. So for every assembly that you're interested in, we want to ask the assembly for every type that we care about. So that could be literally every type. That could be every type that meets a certain interface like say I plugin or whatever your plug-in interface is. And then given that type, we're going to do probably one of two things. And again, this is not rules. You can do whatever you want here, but I find it's generally one of two things. The first is that we're either going to invoke something on that type. And what I mean by that is we will say, hey, plugin type, whatever we're dealing with, I don't even need to instantiate you. I'm just going to call something on this type like a static method that will
go do this work for me. or maybe you do new it up like in some of my code all of my plugins that need to be instantiated the plugin itself is not allowed to take in any parameters. So dependency injection doesn't work there. So really they they could be static. It would be the same. So we invoke something on the plugin and we say hey plugin here's my dependency container that you're allowed to register stuff to. Here you go. So we call this method on a plugin and we give it our dependency container. So what we're doing is we're delegating the work of registering dependencies to the container. Okay. The other way is that we say hey um hey assembly that we're pulling types from. I'm going to take that type like I plugin and I'm going to be responsible for registering it onto the
container. So we're not delegating the work to the plugin. We're saying I found you plugin. I'm going to register you. If we look at the code that's on the right, if I walk through it, you know, line by line, we're not looking through a directory. We're just kind of looking at a single DL, but you can imagine this goes through a folder, whatever you want. And then we're saying for each of the um the types that are in the assembly, we're checking and it says impl for implementation. We're checking if it's not a class or it is abstract just continue because we need it to be a a type like a concrete type and then we're asking in this case this is saying give me all of the interfaces on this type and as long as it's not generic we're going to register it onto
the the service collection. So you can do this there's so many different ways you can do this. This isn't you know the way to do it. This is a way you can do it. And the whole point is that I'm just trying to show you that you can filter them and then you can pick how you're registering. So this example of code that's on the screen is actually the second way. It's this way. Register the type on your DI container. Right? So we were saying, hey, I have this type. I'm going to register it. The other way you could do it is you would say like imppl um and this is a type. You have to do a little bit more but um you could basically use reflection to invoke a static method on this type and you would give it your service collection. Like
I said multiple ways to do this but this is the the highlevel flow of how this works. And then at the end you build your services right. So servicesbuild service provider that's the part that's behind my head. Okay, hopefully that's making sense so far. I don't see any questions in the chat which must mean all of you understand it perfectly. If not, just ask in the chat because I'll stop what I'm saying. Um, okay, kernel plugins. I touched briefly on kernel plugins before. One of the ways that I like to think about this for examples is like what if I want to swap an implementation to X later on. So I said I like using Sarah log, right? Uh but if I wanted to swap Sarah log out for a different logger, say like for log fornet or I don't even know what loggers there
are now. There's there's lots of different loggers. Um, if I didn't want to use Serogg though, instead of me changing all of the spots in my code, I could just configure the application to use a different plugin instead of the Serogg one. And that different plugin would be responsible for registering its implementation of a logger. Again, I have it literally on here. Let me highlight. Sorry. Normally, we would use extension methods like services.add logging. So again, I'm not telling you that kernel plugins versus just calling what I have highlighted here as an extension method. I'm not saying that a kernel plugin is better. It's just a different way to do it. I like using plugins and that way I don't write extension methods like this and that works for me. So I listed out some examples. Again, this is similar to what was on one
of the earlier slides, but you usually uh have your implementations meet some common interface that you're just going to use everywhere like an eyeloger. That's just, you know, built in from Microsoft. We have the eyeloger interface. Uh hybrid cache. I think the hybrid cache one is not an interface though, but oh, I can't edit because it's protected. Um, you might have like an I telemetry interface. But the point is that these could be SDK things, but you're probably going to have an I logger absolutely everywhere in your application. You could make an argument that you want to have a dedicated logger for your plugins and pass that in. Like there's so many different ways you can do this, but kernel plugins provide the implementation. If we look at some of the code that's below, you can see that it's taking a shortcut. It's not scanning
all assemblies, but it's just saying go load the Sarah log plugin. You probably wouldn't write code exactly like this. You'd look in some folder for plugins, and then we would say for all of the kernel plugins, I want you to go load that uh that plugin, get the types from it, and then we're going to look if the type that we're examining is an I kernel plugin. That's what is assignable from T means. So if the type we're looking at is uh can be assigned to I kernel plugin which means it is of that type and it's a class and it's not abstract then we're going to so you can see here this one actually uses reflection to create an instance. I can't highlight it because it's a picture, but it will basically the part that's um to the left of this dotregister. Everything here
uses reflection to create an instance of the plugin. It casts it so that we can refer to it as a kernel plugin. This one calls register and gives it the service collection. So, if I jump back a slide, it's the opposite way that this one works because we're saying, "Hey, plugin, I'm delegating this work for you to go register whatever you need to to the service collection." Another important note here, because I don't talk about it much in these these slides, is that we're essentially saying, "Hey, kernel plugin, I trust you to go do whatever you want with this service collection. I trust you to go do it. So go do it. And if we look at the implementation of this Sarah log plugin, it has a register method. And this is going to hook up several things to the service collection, right? You can
see add singleton. It's going to add Sarah log. Add singleton. It's going to add a logger factory. Add singleton. And it's going to add in a generic logger that is the Sarah log logger. Okay. So we delegated that responsibility to the kernel plugin to go do this work. Right? A quick note is like this last line that says uh add singleton of type I logger and then type logger. This is the kind of thing that if we go back to this slide, we're not going to know how to do that generically. That was actually the responsibility specifically of that logging plugin. We're saying, "Hey, look, when we're going to register this logging stuff, we want to make sure and this logger knows how, sorry, this plugin knows how to go register this generic logger. Okay, so again, this just shows you that you can delegate
the registration to the plugin itself. Not a rule, but generally that's how I think about some kernel plugins. feature plugin. This is going to work sort of the exact opposite way. Some common pieces, but we're going to be instead we're doing the registration, not delegating the registration to the plug-in. So, I wrote feature plugin. It provides an I plugin interface. Okay. So, uh again naming you don't have to call it I plugin anything. It's whatever you want to call your interface or your plugin. So again, this is enabling new functionality in the app. We're extending the application with functionality. Um, and I also just when I gave this presentation, and it's a good opportunity for to remind folks like I um I don't see this as a rule. I don't see this as like you must do it this way. I don't like having hard
and fast rules um in software development because I don't think it makes sense. I think there's always exceptions to everything and I would much rather like people kind of think about the trade-offs and make their own decisions. Uh otherwise I just feel like I'm misleading people. Give me one second. I'm just checking. Did my LinkedIn Oh, it did go. Okay. I thought that my LinkedIn live wasn't going. Okay. So what we have in this example is we have a plugin at the top and this is a really boring example. A lot of these were made by chat GBT. Thank you so much chat GBT for helping me out. Um so we have a plugin that is a feature. I feature and um maybe a question a little quiz for you to think about is you see I feature defined right here but where should I
feature really be defined if you think back to the structure and component slide where would we define I feature you'll have the answer soon but think through this as I'm talking um so we have the hello feature that implements an I feature this code and This top box is essentially like a hello plugin, right? It says hello from a feature plugin. That's what happens when we call the run method on this plugin. But if we go look at the assembly scanning and registration, looks pretty similar, right? We're focusing again on a single DL. Usually you would do this over a group of DLS. We say give me all the types. We're checking only for I feature types. So that's where we see this is assignable from code. Again, we're checking if it's a class and not abstract. The part that is different is that right
here, instead of saying let's go make a new instance of this plugin and invoke the register method or whatever you want to call it, we are adding this feature or this plugin onto our service collection. In this case, by default, it's going as a singleton, but you could figure out the lifetime scope that you need to use for your plugins. Maybe you want it scoped or transient. Um, a lot of the stuff I build ends up being a singleton lifetime. So, that's why it looks this way in the example. But again, big difference is that in this one, we are doing the registration on behalf of the plugin and the kernel plugins, it worked the other way. Okay. Um, spoiler alert, no. Um, okay. I didn't mean to go to the next slide. This this code at the very bottom just shows that we can
ask our service provider, give me all of the features. Give me all of them. Right? We can say, this is why I was saying if you're not familiar with dependency injection, what we're able to do with dependency injection is we can ask the provider that has all of our services, give me all of the features. And then in this case, we're iterating over them and just calling run on every single plugin that we have. Okay, SDK considerations. This is a super busy slide, so I apologize. Pretty gross. Um, I said this a little bit earlier, but I want you to think of the SDK as the interface between your core application and the plugins, your plugins and your app's features. So, you know what your plugins can call or even potentially between plugins and other plugins. These things are supposed to be as much as
possible. You can break the rules as much as you want, but they're supposed to be as isolated and independent as as they can be. And part of that means that they should not I'm not saying never, but they should not depend on the implementation of other plugins. Okay. So, plugin A and plugin B and plugin C can all exist. I got to get rid of my head after when I talk about this code. Um, plugin A, B, and C can all coexist, but plugin A shouldn't directly depend on plug-in B's implementation. It doesn't it doesn't really make sense in a plug-in architecture, but if plug-in B was offering some functionality, we would want to maybe perhaps expose that through the SDK. And that way we can get rid of plugin B and put a different plugin in and we don't have to worry about these
things stomping on each other. Um I kind of said that here core app shouldn't know about specific plugins but it does see the SDK interface. And this is basically something I already said communicate the other way. Uh, now that I'm uh reading the code, there's almost nothing except a semicolon and uh curly braces. Sorry, um parenthesis behind my head. Let me just get rid of it. Anyway, this is broken out into three different spots. The top part is the SDK. So, the answer to the question that I asked you from this slide is this interface I feature, you would define this in the SDK. If I jump ahead again, right, this time it's I greeting being defined in the SDK, but from the previous example, I feature would also live here in the SDK. This is the common code that gets used between the plug-in
and the core application. And because it's common code, you want to keep it very thin, just ideally focusing on interfaces and maybe some of the like data transfer objects or simple classes that are allowed to be shared. If we look at the plug-in code and again consider all of these, there's three major groups. Consider that these are in different projects. So this plugin, this code, you can see it's using the SDK. It's using the SDK, but it defines in this case chat GPT wanted to use pirate examples. I have no idea why, but it decided to go with pirates. But we have this implementation of a plug-in or in this case the pirate greeting is the implementation we have. You can see that implements greeting. We call you know this greet implementation will print out or I guess it returns aoy whoever the name is,
right? And this is the the interface that we have up here in the SDK. When we think about the part down below, I trimmed out the code that does the registration. But you can see that like if we wanted to go have our core application use the plugins. The core application doesn't know the specific implementation. It doesn't know anything about a pirate greeting. Has no idea. But it does know because you can see here where my cursor is. It says using SDK. The core application knows that it can use the SDK and as a result the core application can look for services that implement I greeting coming from the SDK and then we can call greet. So overall this is uh trying to illustrate that your SDK is shared code between the plug-in and the core application. So one more thing to think about before
I move from this slide is um oh sorry I just reading on LinkedIn if you want this code um I might have to check the repo after this code is not there. There's better examples um in the repo. So, I'm not sure when you joined the stream. Give me one sec. I'm just gonna paste it again. This is the I just put it in the chat again. Doesn't go to LinkedIn, does it? Damn. One sec. That's annoying. I'm going to join my own stream on LinkedIn and I'm going to add a comment. So, the link that I just put Oh, failed to post comment. LinkedIn, could you stop sucking? Okay, one sec. The best way to get the code, uh, not from the slides unfortunately, but I have a repository. It's just called Dev Leader on GitHub. And you'll see I have a bunch of
other code examples, right? like all of these folders that you see on the left like here's one plug-in loading right so I would go check this out personally but um this repository specifically this folder that I'm looking at right now is related to this presentation and I have lots of other code and videos that you can check out for uh like more specific examples but I hope that helps sorry the chat just isn't working for me to send you stuff um when it comes do SDKs. I just want you to think about like how much responsibility you are giving or how much you trust um how much you trust the plugin. If you're wondering what that means because you're like, "Well, shouldn't I trust plugins?" Sure, if they're your plugins. Um, to say it another way, uh, think about, because I said at the beginning
of the stream, think about Visual Studio and Visual Studio Code, right? If Visual Studio or Visual Studio Code allowed plugins to touch anything they wanted, right? They had full access to everything, they really have to think about what that means. Are there, you know, parts of Visual Studio that they don't want to expose to plugins? Because if that's the case, then they need to restrict that in the SDK so plugins can't see too much, right? If you're letting users define plugins, like third parties defining plugins, then you might want to be a lot more restrictive in what you're letting them do. If you own all of the plugins and there's no third party, it's just, you know, you or just your team that's building these plugins out, um, maybe you do give them a lot more trust. Maybe you still want to restrict things because
you don't want to give people too many options and then they uh, you know, they can do too many things and kind of uh, the phrase like shoot themselves in the foot so to speak because they can do too much, they can get themselves into a bad situation. Maybe you really want to narrow it down, but you need to think about that with your SDK. Okay, the last big topic is going to be testing. And I tried to hint at this earlier, but plugins and testing. Plugins don't mean that you automatically, you know, have the best testing in the world or the best experience. But in my opinion, I like plug-in architectures for testing because you get modularity and isolation. So to be more specific, when we go add a new plugin, so let's say a feature plugin, that plugin is supposed to be isolated.
You shouldn't be touching any other code in your application except maybe, you know, um, at some point at the at the build to be able to include the plug-in, right? It needs to be part of the application, but you don't need to go touch other code. And so almost by definition, you should have a lot more isolation from other parts of the code and those tests should pass, right? the likelihood of you breaking things by adding isolated code should be very low. Right? Kernel plugins are actually almost the opposite. And I tried to give a funny example when I was doing my uh presentation in person if I talk with my hands here. The example I gave was like okay I've been talking about serog as your logger. You can use a kernel plugin for that. But a good example of how you can really
screw things up with a kernel plugin is let's say I said I don't want to use Sarah log anymore. We're going to use Nyx logger, right? I have my own fancy logger package that we're going to use, but my code sucks. And when you call logger.log information or log debug, it just throws an exception. Poof. Just throws an exception. That's all it does. And so I was saying that plugin should be isolated and feature plugins are, but yes, a kernel plugins isolated, but because you're providing an implementation that's used across the entire application, in this example, Nyx logger would probably break everything because anything that calls logger.log information or log debug is now going to throw an exception. that probably breaks a ton of code. So, the difference that I want to call out when it comes to testing these things is that a new
feature plugin is probably quite safe by definition and a uh kernel plugin probably carries a lot more risk because the impact will be spread across the entire application or any plugins that will use kernel functionality. Okay, so that's something to think about. The next points that I have here um tie back to something I said earlier in the talk and I said things become so modular that your code base starts to look like units, right? Every feature is its own isolated unit. It's modular. So for folks that are familiar with, you know, uh the testing pyramid and stuff like that, there's memes and stuff about this too. If you have like uh a heavily unit tested application and there's no other types of tests, the idea is that all of these things work perfectly in isolation and as soon as you start sticking them together,
they fall apart because they don't have test coverage that shows that they work together. So, a similar thing can happen with plugins where if you're not careful, you end up testing all of your plugins and they work perfectly in isolation and then you go to drop these plugins, you know, to go run them together and there is something about how the actual um interfacing works at runtime that doesn't work. Okay, so this is important because there's a in my opinion like an entirely different set of tests that you want to think about. And the two that I wrote down here, if I go back to my slides are that you probably want to think about configuration tests. Oh, I didn't write them on this slide. Um, oh, I talk about on the next one though. Configuration tests or architectural tests. So here's an example. This
is ArchUtn net which is a Nougat package. Um there's other you know net creators like Milan uh Javanovic talks about this a lot and um this is just you know a really simple example of this stuff being pulled together. But in this case we can use architecture tests to prove what our solution looks like. we can prove that the way we have tests set up sorry the way we have plugins set up can be validated in tests. So this is contrived these rules may not make sense but this is just uh an example. Okay so this one says plugins depend only on the SDK or system. Now system you might change to be other dependencies but what this test would be checking is do your plugins only have the SDK as a dependency and any other you know assemblies that you're allowing them to have.
That means that if a plugin depended on another plugin this test would fail. If a plugin somehow depended on the core application this test would fail. So you can enforce these plug-in rules that you want to have. Uh maybe not all of them adhere to the rules like maybe in this case you only want all plugins to um depend on SDK or like the system namespace but maybe you have a couple of plugins that you know they're the exception they could add in a couple of nougat packages. You could add like an allow list for this test, right? So there's a lot you can do with this kind of thing. And this one says uh host or like the core application does not reference plugins. I said this earlier, right? Like you ideally don't want your core application to know about specific plugins. So if
someone was like, hm, I can see this plug-in project right here and I just need to access, you know, something very simple from this plugin in the core application. they could accidentally add that as a dependency, write some code, maybe it doesn't get caught in review. But the point is that like that breaks probably and like in my perspective, one of the the nice isolation rules that we have when it comes to building plugins and then there's just, you know, another example down here for uh SDK uh checks that you might want to do. But this is up to you, right? The point is that you can use architectural tests to prove how these things are structured. Okay, this is a whole bunch of stuff. And I put this together originally. Whoops, there's my head again. I put this together originally because my talk that
I did in Dallas is 25 minutes. There's a whole bunch of other stuff to talk about, but there's not time. And even now, this stream has just hit the time. So, um, I'm leaving you with this slide. If you're interested about this kind of stuff, I have a bunch of YouTube videos on it on my main channel, which is Dev Leader. And if you want to see more, like I actually don't think I have a a video. It's a good reminder. I don't have a video on architecture testing with plugins or configuration testing with plugins. So, perhaps I could do that. But if there's more videos you want to see related to plug-in architecture, just message me. You can comment on this video if you're watching it on YouTube, especially if it's the recorded one. Shoot me a message on any platform, LinkedIn, Twitter, Instagram,
whatever you want. Send me a message, comment on some other YouTube video and say, "I want to see a plug-in video on whatever." Um, these are a bunch of different topics that are interesting and unique challenges or things to consider with plug-in architecture. Uh, to briefly wrap up, um, I mentioned Needler. I've made YouTube videos on Needler. Needler is how I get my um, my plugins wired up and my dependency injection wired up with just a couple of lines of code. Needler is very opinionated. It registers things the way that I like to do it. But again, you might hate it. That's totally cool if you want to check out what the code looks like because you're like, the concept is cool, but you know, the way the default way that I do things, you're like, I hate this. I register everything as singletons, right?
Singleton uh as the class and as its implemented interfaces. I do this for basically everything. If you're like, that sucks. I hate it, but I like the idea. You can literally define your own registration pattern that uses the default. So maybe Needler still is for you, but Needler is what I use to simplify my plug-in registration immensely. This is just a slide that said, you know, um if you got questions, just ask me, make a video on it. And the end, right? So let me get rid of my head on here. There's a QR code. Um that QR code takes you to all of my links. It's it's my link tree. So, if you want to see my YouTube channels, if you want to see like LinkedIn, Tik Tok, Instagram, Twitter, you name it. Um, that's what this uh QR code is. And so, of
course, to sign off, I have courses and stuff on Dome Train. So, if you are interested in the way that I teach, you like the the topics I go through, uh you can check out my courses on dome train. But, of course, I always try to make as much free content as possible. So, my goal is not just to, you know, try and steal your money. My goal is to help you. So, if you um, you know, if you enjoy the content and courses aren't for you, then, you know, thank you so much for being here and supporting me that way. But the goal is just to help. If courses are a good alignment for you, then there's courses, right? So, let me bring my head back. There I am. And, you know, just to show you, right? Courses. This is courses on dome train.
So, um, getting started with C and the deep dive for C, they're available. And if you're like, hey, I don't like C, despite watching a whole plug-in architecture video on C. Um, I have other courses with Ryan Murphy for career management, getting promoted, behavioral interviews, and soft skills. So, happy to try and help you out in some capacity there. Um, plug-in architecture on dome train. I can ask Nick Chapsis. I am about after this stream I am literally sending over my um curriculum for the next course that I'm going to do. It's not plug-in architecture though, but I can ask. I think um I think I talked to Nick Chapsis before about plug-in architecture as a course and he wasn't opposed to it, but I don't think I think it was one of the lowest requested course topics at that time. So, um I don't
know where you can go on dome train to make requests, but I mean this genuinely like I am happy to make a course on it, but if uh if you'd like a course on dome train, I would uh reach out to Nick Chapsis and make the request, I can of course do that, but he's he's the brains behind the operation, right? If uh if he sees that people are requesting things or interested, then then he will be driving um driving a lot of that. So I would be happy to do one on plug-in architecture but um I think based on what data we had before there wasn't a lot of interest. So, um, still a possibility, but I will I'll let Nick Chapsis know. And if you are interested, please reach out to him, tweet at him, message him on LinkedIn, whatever you want. Get
it in front of him because, uh, the more that he sees, the the more uh, sort of reason he has to believe that people have interest in it. Um, folks, I'm just going to do a quick run through of the other stuff that I have to offer. So, I'm just going to put the dome train courses if you're interested in the chat. Um, usually if you're Thank you for hanging out on this live stream. Usually what I do is I go to my newsletter article. I put out every week. I didn't this past week because I was at a conference, but every Saturday I publish a newsletter article. You do not have to subscribe. It's just at weekly.devleer.ca. You can read it just like a blog post. But um for example, if I click this one, this is the topic that we end up focusing
on for the live stream. So if you're curious and you want to join the live stream, uh I'm not going to do one next Monday. My sister's visiting and she hasn't been to Seattle before. So um the week after, sorry folks, but if you're interested in what this looks like on these live streams, the topic comes from the newsletter article. And the newsletter article is based on my videos on code commute. So whatever the most popular topic is from the week on code commute, that's what I will be doing the newsletter article on. So for example, this week is still fresh. But if we scroll down and we look at this one, right, this one had 15x. It got a lot of views and I think it's because the title was a little bit like clickbait. These junior developers suck, right? junior develop de developers
obviously don't suck but this is based on some Reddit content and so that's again right that's what the newsletter article became and then we talked about it on the live stream so code commute is where I do my vlog if you have questions that you want answered in software engineering you can go to any code commute video you can write a comment and ask your question or you can go to codecommute.com and you can submit your question anonymously so there's this check box you can press, you can write whatever you want. One of the videos I'll be putting up this week, someone wrote a huge message, lots of details, super helpful, and I try to answer your questions in a vlog. Um, because you're all here, the live stream is on the Dev Leader podcast channel. So, I interview other software engineers and put up
those podcasts. And then, like I said, the live streams also here as well. I have Dev Leader. So if you want more plug-in videos, you want to see content like that, that's going to be on this channel, which is just devleader on YouTube, and put that right in here for you. But yeah, these are all C or programming tutorials. Um, my most popular videos are basically just really basic C concepts. And what else? Dev Leader Path to Tech is my I got four YouTube channels. Yeah, there's too much. channel. This is the fourth YouTube channel and this is where I do ré reviews. So, if you have a resume that you would like to be reviewed, you can submit it by checking out one of the videos for instructions and then I will redact your information and give you what I hope is helpful feedback
on your resume. And I think that's mostly it, but I have to shout out Brand Ghost. So, Brand Ghost is um what I was showing you in those plug-in slides. Brandos is the platform that I build to be able to publish to all of these social media platforms. And if you're wondering what that has to do with plugins at all, consider this for a moment because it's a good example. If I want to post content to a social media platform, how many social media platforms are there? A lot. Each one of these platforms is a plug-in inside of Brand Ghost. So that way I can write how to post a social media one way and then each plugin has the specific implementation for how to go post that content to that platform. Okay. So there is a ton of plug-in usage in Brand Ghost. But
if you're interested in posting to social media, uh it is literally free to crossost and schedule the I met a bunch of people at this conference, not even creators. They were just aspiring junior developers and they said, "Hey, we're really motivated to start learning in public. We're going to try out Brand Ghost. It's free. Plus, if it doesn't work or it's got something that or it doesn't have something that you want to see, then just message me. I'll figure out how to add it. I want to make sure that I can support people that are trying to create content um because that's what I do and I want to help other people do it as well. If you have a small business and you need help with social media marketing, Brand Ghost can be a huge help for you. If you're curious about how to
make that happen, again, just shoot me a message. I'm happy to try and help. But folks, that's it for the stream. Thank you so much for being here. I appreciate it. I won't see you next week because my sister's visiting, but the week after that, I hope to see you. And if you want more content kind of like this in the meantime, head over to Code Commute and you can check out the vlogs because it's just me rambling in the car, which is almost like what this was. So, thanks again. See you next time.