S07E14 - Metaprogramming Made Accessible: Gael Fraiteur Explores the World of Metalama
Sponsors
Support for this episode of The Modern .NET Show comes from the following sponsors. Please take a moment to learn more about their products and services:
- RJJ Software’s Software Development Services, whether your company is looking to elevate its UK operations or reshape its US strategy, we can provide tailored solutions that exceed expectations.
Please also see the full sponsor message(s) in the episode transcription for more details of their products and services, and offers exclusive to listeners of The Modern .NET Show.
Thank you to the sponsors for supporting the show.
Embedded Player

The Modern .NET Show
S07E14 - Metaprogramming Made Accessible: Gael Fraiteur Explores the World of Metalama
Supporting The Show
If this episode was interesting or useful to you, please consider supporting the show with one of the above options.
Episode Summary
In this episode, Gael Fraiteur shares his journey in software development and the evolution of his work in metaprogramming, with a focus on his latest product, Metalama. Fraiteur reflects on his early start in programming at the age of 11, his transition to .NET in 2002, and the founding of PostSharp, one of the first open-source projects in .NET, which he initiated in 2004. He elaborates on his recent efforts to modernize PostSharp for current technology stacks and introduce Metalama, a tool designed for metaprogramming utilizing Roslyn and the latest .NET features. The conversation emphasizes the growing need for metaprogramming to automate tedious and repetitive tasks associated with coding.
Fraiteur frames metaprogramming as the “programming of programming,” explaining that it can significantly streamline the software development process by automating code generation and verification tasks. He clarifies that metaprogramming includes various forms of code generation, and although templates are one aspect of it, there are other methodologies such as LINQ-like queries aimed at code verification. By contrasting earlier versions of PostSharp with Metalama, he points out the new capabilities that come with integrating Roslyn and modern C# templates, allowing a clearer separation between aspect code and business logic—something that enhances code maintainability.
A significant portion of the discussion revolves around aspect-oriented programming (AOP) concepts and implementation within Metalama. Fraiteur provides examples of how to apply aspects, such as logging, to multiple methods without repeating boilerplate code, thus reducing code bloat and preventing common errors associated with copy-pasting. He explains, notably, how using attributes can simplify the application of aspects, along with a programmatic entry point known as “fabric” for targeting multiple methods within a namespace. Metalama allows for non-invasive modifications of code at compile-time rather than runtime, enabling developers to apply aspects broadly without the limitations of middleware approaches used in other frameworks.
Moving deeper into technical specifics, Fraiteur describes the operation of Metalama at both design and build times, detailing how the tool integrates with Roslyn’s compilation pipeline, which allows it to generate and manipulate C# code instead of directly transforming IL or MSIL. He emphasizes the importance of the debugging experience with Metalama, where developers can view both generated and original source code, making it easier to troubleshoot and understand how aspects are applied during runtime. This clarity extends into testing, as he assures that traditional unit and integration tests remain unaffected by the use of Metalama’s metaprogramming, maintaining standard practices for ensuring software quality.
Fraiteur discusses the broader implications of adopting Metalama for development teams, advocating for a focus on reducing complexity in software architecture. By using metaprogramming to automate repetitive tasks and enforce architectural rules, teams can mitigate ballooning code bases and prevent architectural erosion. He suggests starting with small, less critical projects to experiment with aspects and gradually shifting development mindsets around code efficiency and quality. This approach not only enhances the productivity of developers but also provides a safeguard against potential pitfalls of expansive metaprogramming practices.
Episode Transcription
And I think this is really the key factor in software development. I think it’s really to keep complexity low, because in most projects, unless you are writing an operating system, a framework or rocket navigation you are not coding against hardware; like the hardware is not your bottleneck. You are coding against human brains, cognitive abilities of your team; like how many smart people your company is able to put on your team, this is your limiting factor so we need to keep complexity low and I think it’s really the most important benefit.
Welcome friends to The Modern .NET Show; the premier .NET podcast, focusing entirely on the knowledge, tools, and frameworks that all .NET developers should have in their toolbox. We are the go-to podcast for .NET developers worldwide, and I am your host: Jamie “GaProgMan” Taylor. And I no longer have a throat infection.
In this episode, Gael Fraiteur joined us to talk about Metaprogramming with Metalama. Gael is the original author of the wildly successful PostSharp and has been working with the aspect-oriented programming pattern for over 20 years. In this conversation we talk about how metaprogramming (regardless of whether you use Metalama to achieve that or not) can save on both the complexity and the number lines of code in your projects.
Well, there are studies that try to correlate the cost of software projects to the number of lines of code. And the conclusion is: it is more or less a linear dependency. A bit super linear. That means that if you have 15% fewer lines of code, you are going to get 15% lower development cost. So that’s the easiest part.
Anyway, without further ado, let’s sit back, open up a terminal, type in dotnet new podcast
and we’ll dive into the core of Modern .NET.
Jamie : [0:00] So, Gael, welcome to the show. It’s been a wonderful couple of days getting this all sorted and put together, and I have absolutely no idea about what we’re going to talk about today. I know the topics, but I don’t know the background information.
Jamie : [0:15] But I guess before we get into any of that, I wonder, could you give the listeners a bit of an introduction, maybe an elevator pitch about yourself? Like maybe, if you want to share, how you got into software development or maybe like the things that you like to do, the kind of work that you like to do, that kind of thing.
Gael : [0:34] Sure. My name is Gael Fraiteur. I started programming when I was 11. That was in ‘89. That’s a long time ago. And I’ve been programming in .NET since version 1.0. That was in 2002 and I never really stopped. So I grew up in Belgium, I graduated in Belgium and then I immediately moved to Czech Republic and i’m still living in Czech Republic. And in 2004 I started one of the first open source projects in in dotnet called PostSharp which became quite popular.
Gael : [1:21] And recently, in the last five years, I’ve been working on a kind of remake of PostSharp based on the modern .NET stack and not on the .NET stack of 2004-05. So based on Roslyn, .NET Core, .NET 5, 6, and now 9. And this is called Metalama. Today we are going to talk about metaprogramming in general and more specifically about Metalama our brand new product based on Roslyn .net 9 for metaprogramming.
Jamie : [1:55] So here’s the thing right: I know nothing about metaprogramming. My feeling is it might be related to templating. So I know that like in C/C++ and rust and things like that I can get the compiler to do some of the coding for me. But I don’t know whether that’s what we’re talking about. Is that what we’re talking about?
Gael : [2:16] That’s one aspect of metaprogramming indeed. Metaprogramming is the programming of programming. That’s what it means. So the starting point is to realize that when you create software, there is a lot of repetitive tasks that you need to do. And, two categories of these tasks. One is writing code, and the second is verifying that the code complies with some verifications and some rules. So we can use metaprogramming to automate these two categories of tasks. Templates are useful for code generation. And then, of course, for code verification, we have another technology, which of course is not based on templates, but is based on LINQ-like queries.
Gael : [3:07] So metaprogramming is not necessarily templates. And PostSharp was also a metaprogramming tool and also did code generation, but it was not based on Roslyn. It was based on MSIL transformations. PostSharp was not template-based. It actually, when you wrote an aspect, So an aspect is some code that is injected inside some target code. So say for instance, the typical example is logging. If it’s boring, it’s still the hello world example. So adding logging to every single method is very repetitive. So you create an aspect which is basically conceptually a template. And you apply this to all these methods. But the magic is that the code is not modified inside your editor. So the source code is not modified. It’s done on the fly when you compile, which means that your source code remains small. So we are not talking about your usual code generation.
Gael : [4:15] This code is generated during transformation, So you have a clear separation between your, what we call the aspect code, it can be logging, and the business code. So now we always talk about logging because it happens to be the Hello World example. And many people believe that, well, this is called aspect-oriented programming or used to be called like that. It’s no longer true. But it’s actually useful for a lot of different patterns, like transaction handling, exception handling, very useful to inject calls to Polly, for instance. You know, you can use Polly for exception handling. It would be stupid to create your own exception handling library.
Gael : [5:01] But you still have to write some plumbing code. And this is where you can use Metalama or other metaprogramming tools. Recently I’ve created an aspect to implement the builder pattern. Notify property change, it’s another example. Like every time you have some kind of code repetition you can use metaprogramming to formalize the repetition, it’s like when you have a recipe and, and you create a program that will code for you, except that it will be applied at the build time when you compile. So this is for the for the templating part.
Gael : [5:44] Yes, I said PostSharp did not use templating because actually Metalama is the only tool in .NET that is based on Roslyn and so it actually works as template expansion. The other tools like PostSharp before would only generate the glue code, calling your aspect from the target code. So there was some kind of performance over it from this approach. But now with Metalama, we developed a C# to C# template engine, template language, sub-language of C#. And this is quite powerful. Quite powerful.
Jamie
:
[6:27] So just so that I’m on the sort of the same page and listeners are as well: one of the ways that i’ve understood that I can implement aspect-oriented programming is when i’ve had like an attribute above a class or a method. Like you said, maybe logging right. So I can have like an attribute—so that’s the, if you’re not sure of the syntax let’s say you’ve got a method called Foo
, uh the line above that method you’ll put a couple of square brackets and maybe the name of an attribute or a method to call. And what will happen is there’s some magic that happens that wires everything up and calls that method. So you might know this from, if you’re in say, ASP .NET Core land, and you add the AllowAnonymous
attribute to a controller action that allows an anonymous, i.e. non-logged in user to access that route. That’s my understanding of that. I mean, am I a million miles away? Am I kind of in the right ballpark?
Gael : [7:23] A couple of meters away.
Gael : [7:25] It’s true that the most common way to apply an aspect to a method is to use a custom attribute. If we are using logging as an example, you would definitely not use custom attributes to do logging because most of the times you will want to do logging on the whole namespace. So we have a different concept that we call a fabric and this is a compile time entry point to your project, too. So you get the code model of the project at compile time and you do a code query and it really looks like LINQ. So you do, you select all public types in this namespace, all public methods there, and then you do add the logging aspect. So there are two ways to add an aspect. One is to hand pick the target using a custom attribute and you would use that for instance, for caching. The second one is to use what we call fabric, so these programmatic compile time APIs. Now there is a third one where you can say that the aspect is inheritable, which means that typically for notify property changed, if your base class must implement this interface, then you also need to override the property setters of all derived classes.
Gael : [8:47] Now you mentioned action filters in ASP .NET. This can be compared to what we are doing, except that the technology of implementation is completely different.
Gael : [9:05] These action filters, they work on the principle of middleware. That means that you have your implementation, which may be your controller, and then you have the caller. In this case, it is a network client. And between the caller and the implementation, you put some middleware. And one of these middleware that you can add can do something. It could do custom logging. It could check for authorization.
Gael : [9:34] Now, ASP .NET is not the only infrastructure that would accept middleware. You have other cases. And one is dependency injection. So you create your service collection. And into this collection, you would put implementations of the service. And you would inject into this collection classes. But the consumer would consume an interface. So you have libraries in .NET, and now I couldn’t fetch the name, but I can put that in the notes. But you have libraries that allow you to create dynamically a proxy class. This proxy class would sit between the client and the implementation. So these are all the AOP [aspect-oriented programming] implementations, say, based on middleware, like there is another one for WCF because it was the same concept.
Gael : [10:35] Now, Metalama works completely differently because we modify the code, not the source code, but we modify the code during compilation.
Gael : [10:45] So that means that you do not need a middleware infrastructure. You can add an aspect to a static method that you would otherwise not be able to intercept. And that’s the big difference. You are not limited to intercepting interface calls and adding behaviors to either interfaces or virtual method calls. You can do anything. You can add fields. You can intercept static methods. You can add operators. You can do anything that you could do in source code, except that you can program this. So that’s what we are offering with Metalama.
Jamie
:
[11:26] The example that I’m coming at this conversation with is: like, if I have some super repetitive code that needs to be called, use logging as an example. That is a great example. I can’t think of many other examples, but like some code that needs to be called whenever any method is called, right? So rather than adding a call to that, so like in your Foo
method from earlier, you’ve got a public void Foo
that takes in some arguments. Rather than jumping in and at the very first line of every single method be, “call this other thing and do this other thing. And then come back and then carry on. " You were saying that you can add that everywhere in the build steps, like you were saying, right? So I don’t have to actually write it into every instance of that method throughout my code base. But I can do some, we’ll get onto it later, but I can do some kind of magic in perhaps my program.cs that says, “hey, Metalama, wherever you see me calling anything, do this thing. " Or, “whenever you see me calling a thing of this type, do this thing. " And then that will sort of wire everything up in the generated, like you were saying, in the generated IL code, right? So it’s using Roslyn to do all of that stuff for me, taking away all of that repetitive, almost toil of wiring everything up. Is that correct?
Gael : [12:47] Yes, it’s almost correct. There is just one correction I should do, is that currently with Metalama, we will not modify the calling code, but we would modify the called code at the implementation site. Right. So we are not really doing interceptions. We are adding the feature not to the caller, but to the called feature. This is in the current version of Metalama. We are not able to add logic to the call instruction. We do that in Roslyn. actually the way that the magic works, there are two scenarios. One is design time and one is build time. And this is quite different because at the design time, we don’t control the compiler. The compiler is shipped with Visual Studio or Rider, so we cannot change it.
Gael : [13:46] At design time, we are integrating with standard Roslyn APIs, which are source generators that you may have heard of, analyzers, suppressors, code refactoring providers, because we also allow you or we allow the users to create their own code refactorings. So we integrate with these official integration points. But there is one missing extensibility API, which is the ability to replace code with another. So, you know, with Roslyn, you can have source generators, which can generate new files. You cannot modify an existing file. So what we did is that we forked Roslyn into what we call Metalama compiler, which is fork of Roslyn that just adds one extensibility point. And it is the ability to replace a syntax tree by another syntax tree. So this is an open source fork of Roslyn that everybody can use to do their own transformation.
Gael : [14:48] So this is Metalama compiler and on top of that we have Metalama framework which integrates with this Metalama compiler and replaces one syntax tree with another. We do that before the real compilation step in Roslyn. So Roslyn has many steps. It runs analyzers, it runs source generators and so on. And then finally we call generate binaries. And so what we are doing is to add a step before calling emit binaries that’s how it works inside at build time.
Jamie : [15:23] Right okay. Because that was going to be my next question of like, “how does it all work?” Because I think it’s Scott Hanselman who says the good way to get really good at C# and to understand what’s happening is to understand the next level down right to at least have a knowledge of, “my C# is converted to IL; which then is converted to bytecode at runtime. " So knowing that you’re at that stage, that the majority of the Roslyn work is happening at the emit binaries and generate IL stage, it’s really quite impressive to me. Because like you said, right? You’re not touching the source code itself. The C# code is not changing, but the code that is generated from that C# code is what’s changing, right?
Gael : [16:08] Yes. Well, actually, the implementation of Roslyn is like a pipeline with many steps, and we are quite soon in these steps. So the fork that we did is actually very shallow. There are very few changes because we are just adding one extensibility point, but we don’t go very deep inside the implementation of the compiler, which is why it is quite simple to maintain. Because people are quite often afraid of, “why you are forking Roslyn? Isn’t it dangerous to me?” It was a lot of effort to do it in the beginning. It was a couple of months of effort. But now we can do an update of Roslyn in half a day, maybe. Sometimes it is two days.
Gael : [16:54] So half a day when it is, for instance, from RC1 to RC2 is just a couple of hours. That is very simple. so if Microsoft didn’t offer this extension point it’s not because they are not able because it’s very simple. But it’s because they don’t want to open this Pandora box that actually we are opening. And I think you should pay attention because it’s very tempting, when you have a toy like this that you are able to change anything with anything, it’s very tempting to play with that and say, “well I’m going to use it to replace this by this and do something crazy.” But then there is a challenge: that is the developers on your team that may be not you, or it may be you five years later, you will not understand the code.
Gael : [17:40] So this is quite a serious problem. And so I understand why Microsoft did not open that. So we had to open the door to implement our feature. But the way that we implement our feature is a kind of a responsible way. We don’t allow you to do crazy things with the code. You can wrap a method. You can turn the field into a property. But our approach is safe: that you cannot really turn your code into something that is completely something different and that is no longer understandable. So that’s a big difference because you can have this low-level metaprogramming where you are coding directly with syntax trees and syntax nodes. So you can do everything. But what you really want to offer is a high-level metaprogramming that is safe, that you can use in business projects, not only in research projects or like academic research, but for business projects.
Gael : [18:40] For instance, it’s quite important to think about the case. What if you have two aspects on the same method? What if you have logging and caching? The framework ensures that there is no problem.
Jamie : [18:55] So related to that, one of my things initially was like, if we’re changing the IL that goes out, and I admit you know we we’ve just said you’re not doing it at such a high detailed level. And I do have a question about um how you keep your version of Roslyn in step with the official version of Roslyn we’ll come back to that in a moment .
Jamie : [19:16] But like if the IL is different then, I mean obviously we’ve got reproducible builds because I can just hit build again and it will get the same build, but like from my perspective: there’s a point where maybe I’ve got a junior on the team who’s like, “wait. There’s some magic happening and like the binary is different right it operates in a slightly different way.” So I guess there’s an education boundary there for folks.
Jamie : [19:38] But I guess the burning question that I have is, “how does this affect like testability?” right . Because if my code is changing at the output step then my assumptions of how methods work and stuff, maybe I’m doing an integration test maybe doing a unit test. Do I need to think about those kinds of things in a slightly different way? Do I need to approach testing in a different way? Auto testing I mean xunit , nunit, mstest, whatever. Do I need to rethink how I do that if i’m using some Metalama and metaprogramming magic? Do I need to… do I need to do that?
Gael : [20:11] No. Testing really doesn’t change. But before I go into details of testing I would like to to answer maybe your next question would be about debugging . Because based on the debugging experience, you will understand better how it works.
Gael : [20:26] So, you mentioned that Metalama creates a different IL. To be correct. Metalama creates a different C# input to the Roslyn compiler. And this is totally different because we are able to write this C# input to disk. So that means that if you choose, you can debug the generated code from C#. We are going to write to disk the C# that we are generating. You can put a breakpoint and you can debug your code. You can compare. We have a feature where you can compare the source code with the generated code side by side.
Gael : [21:06] So regarding testing, while there is no difference to testing, it remains the same. You need to make a difference between testing your aspect and testing your business code.
Gael : [21:22] Typically, when you test your aspect, we have a testing framework and you would apply your aspect to different kinds of methods with different signatures. Maybe that your aspect works both on static and non-static methods. You want to make sure. So you create a test for both these cases. Step one, you test your aspect. Then you want to test your business code. And probably you don’t want your aspect to be active at that time. So the way that you do that is that you use dependency injection just as with handwritten code, that your aspect will pull a dependency from the service, for instance, the logging service, and the logging service would not be inserted in your testing context, for instance. You have to code your aspect, logging, caching, whatever, in such a way that it will work without the dependency if you want to allow for this situation. And of course, there are some aspects where you always want the aspect to be active, like notify property change. There is not a case where you would not like it to be active.
Gael : [22:38] So testing is not affected. I’ve been working on metaprogramming since 2004, and when I designed PostSharp, it was just the beginning of unit testing and dependency injection was not yet so popular. So at this moment, when I designed PostSharp, I didn’t design it immediately for testing and for dependency injection, but Metalama was designed immediately for testing and dependency injection. So this is completely covered. Did I answer your question?
Jamie : [23:12] Yeah, yeah, yeah. I’m just thinking that if somebody’s hearing my misunderstanding of Metalama, what it’s doing, and they’re saying, “hey, if things are changing, how am I going to test it?” But that makes total sense.
Jamie : [23:24] You said earlier on you’ve taken your own open source version of Roslyn, which, for folks, if you’ve managed to get this far in the episode, just in case you don’t know: Roslyn is the C# compiler. I realize that we’re throwing words around, and I’m worried that someone’s listening in and doesn’t know what that means.
Jamie : [23:42] You’re taking your own version of the Roslyn C# compiler because there are some things that, like you said earlier, there’s a Pandora’s box that you could open up, that Microsoft could open up. It can lead to all sorts of pain and issues. Does that mean that every time there’s a new version of .NET, every time there’s a new version of C#, which thankfully they’ve fallen into step, that you then have to go away and figure out, “right, what are the new changes I have to bring into our Roslyn compiler? " Or does that not change very often? How does that work from yourselves not going mad with, “wow, there’s a million changes and we have to keep them all sort of in line with our version”?
Gael : [24:21] As I mentioned, it’s just practically a couple of days per year of work because we are not doing changes very deeply in the compiler. There is this pipeline. Roslyn receives what is called a compilation, which we developers, non-Roslyn developers, we call that a project, a set of files. So it receives a set of files. And what we do is that we have a hook. We replace this set of files by another set of files, but we don’t need to go to the implementation of every kind of syntax or keyword. No, not at all. We have a couple of points when there are significant differences. The rest was pretty straightforward.
Gael : [25:03] Now, if you want to go into details, there was one feature that was more difficult to implement and we had to go deeper. And it is that even if we provide the compiler with a different set of files, we still want the PDB file to be emitted against the source code. Because you still want to debug your source code by default. Sometimes you want to debug the generated code, and this is easy because then it is the normal Roslyn algorithm. But most of the time, you will want to debug the source code.
Gael : [25:40] So we had some work t o make sure that when Roslyn emits the PDB, we use the file location, so the line and columns from the source and not from the generated. So this was more work. But now when we have a normal version of Roslyn, it’s really between two hours and two days, four times per year. So we are very confident with that. And also our branch is open source. So if you want, you can clone the GitHub repo and you [can] compare our branch with Microsoft branch and you will see it’s actually completely manageable. Also pay attention to comments every time that we have a difference.
Gael : [26:31] So for us, it’s no longer a problem. It was a challenge in the beginning. Before we did, when we did the prototype, it was a question like, “how hard is it going to be and will it be maintainable?” But yes it’s maintainable there is no problem with that.
Sponsor Message
The following is a paid advertisement.
Welcome back, .NET enthusiasts! Today's special episode of The Modern .NET Show is brought to you with the help of Jamie Taylor - a renowned expert in software development and artificial intelligence. You may recognize his name from your favourite episodes, but did you know that he plays an even bigger role at RJJ Software?
As our lead consultant, Jamie has guided numerous businesses to unlock their digital potential with bespoke solutions tailored to their unique needs. From crafting cutting-edge software to integrating advanced AI technologies, he's been pivotal in transforming challenges into opportunities.
If your company is seeking a partner who can provide expert guidance and deliver exceptional results, look no further than RJJ Software. With Jamie at the helm of our consultancy team, we guarantee that we won't just meet expectations—we will exceed them. Dive into the digital future with us today.
The audio for this advertisement was created with AI
Jamie : [26:46] I hadn’t even thought about the PDB generation until you explicitly brought it up then. I know that we said earlier on that the debugging experience is still the same debugging experience and that you can switch to debugging the metaprogramming code. It’s something that didn’t even register with me that, “wait, hang on. If you’re generating different IL and different binaries, you’re going to need to somehow generate the PDBs.” So I appreciate that you brought that up even though I hadn’t thought to ask that. That’s a really really good point. And again for folks who are maybe not sure what that is those are the files—Gael did a really good job of alluding to it—it allows the debugger to map the code that is running against individual lines and columns and things in your C# source code; so that’s how you get the rich debugging, the Visual Studio, and Rider, and Visual Studio Code with the C# Dev Kit what they give you is access to that stuff.
Jamie : [27:44] Okay. So like i’m a .NET developer, i’m hearing all of this that we’re talking about here and i’m like, “Right okay. The project manager has decided that we’re going to do loads of metaprogramming , and bring in Metalama and things like that.” What kind of project examples can you give to the listeners that give a good example of why you might bring in meta programming? I know we talked about logging, and we talked about that repetitive stuff, but like what kind of benefits do I get as a developer for adopting Meta Lama techniques and using meta programming like, and how does that change my development process?
Gael : [28:20] The most obvious answer is that you are going to have less code, so fewer lines of code. With PostSharp, we measured using telemetry that typically a customer would say 15% of lines of code. So 15% of code would be generated by PostSharp. I expect that with Metalama, it can be higher because it is more able than PostSharp. There are more patterns that you can automate with Metalama.
Gael : [28:55] So what does it mean? Well, there are studies that try to correlate the cost of software projects to the number of lines of code. And the conclusion is: it is more or less a linear dependency. A bit super linear. That means that if you have 15% fewer lines of code, you are going to get 15% lower development cost. So that’s the easiest part. Because it can be quantified. Now, there are all the dimensions that cannot be quantified so easily. So it’s not only writing the code, but maintaining the code. So first you have defects.
Gael : [29:43] So think about like any feature that you are going to… Any repetitive feature is a feature that you are likely to implement with copy-paste. So you have all these copy-paste errors and bugs. There was some research done back in the days when this technology was called aspect-oriented programming and was a subject of academic research. And there was a conclusion that these kind of cross-cutting features, those that are implemented by copy-paste, well, they are more subject to bugs than the other ones. So that’s another dimension.
Gael : [30:21] There is a dimension of complexity also, is that your code becomes more readable. There are a lot of things that a new developer on the team doesn’t need to understand on the first weeks or months. Sometimes it’s only after a few months on the project that they come to the senior developer and ask, “hey, by the way, how does it work? Why does this notify property change work, because I didn’t do anything for this to work. " So this is really good feedback because it means that during all these months, the developer didn’t need to care about that. So complexity goes down, number of bugs goes down.
Gael : [31:10] Another benefit of that is that when you change your mind about the pattern, well, you don’t need to change the thousands of locations where you have implemented the pattern. Suppose that first you decided to cache one way, using memory cache, say, and then you want to change the caching pattern to something different and even add, say, locking. Well, if your pattern is implemented at one place, it’s much easier to change it at this place. That can be an important benefit that you can change the pattern at one place.
Gael : [31:53] So overall, when you use these techniques, and here I’m just talking about code generation, there are more for code verification. Well, you are going to have lower development costs, lower maintenance costs, and a longer useful lifetime of your app. That means that instead of having to rewrite it completely every, say 10 years, it may last a couple of years more, which may talk to the CFO that you have a longer amortization of your software assets.
Gael : [32:27] Now, if you look at the other pillar of metaprogramming that we didn’t really talk about in detail, which is code verification. So here, the situation is a bit different. Typically in a project, when you start, you would have a phase where you create the architecture. When you have a waterfall project, it is upfront, you create UML diagrams, then you write the architecture. Then at some point in the project the architecture crystallizes that it becomes clear that during the next three years the 200 developers on the team are going to follow these patterns. So we will have naming conventions how things are named, we will have conventions about which design patterns we are going to use which components will be allowed to call other components, so all kinds of conventions And typically, an architecture team would create documents with diagrams and text, and this would be the architecture. Quite important in large teams.
Gael : [33:32] And it’s important for the team to follow the architecture because the key metric in software, to me, is not lines of code and it’s not so measurable. It is complexity. And complexity is composed of two things. It’s the number of rules and the number of exceptions that you have. So when you have a large project, you should have an architecture that is well defined, but has as few rules as possible, but also as few exceptions as possible. So typically, to make sure there are no exceptions and that all developers follow the rules, you have code reviews. And we check that naming conventions are followed and that this component doesn’t talk to this one and so on. But because code reviews are human processes, they can be slow, it can be hours or days later. So they can be defects. And we call this kind of defects architecture erosion. It means that your code base is farther and farther from the original design, the original architecture.
Gael : [34:43] If we want to keep code quality high, what we do is to use what we call in Roslyn analyzers. That means real-time verification of your code against all kinds of rules. But the analyzers that you can just download from different vendors or just come with the .NET SDK, t hey don’t allow you to express your architecture. You will have code style analyzers, you will have pitfall analyzers, security analyzers, and they are very useful, but you are not able to say, “hey, these factory methods should never call this namespace because we want things to be done different. "
Gael : [35:32] So using metaprogramming, you can create your own verifiers, analyzers, And here, the benefit is that you keep complexity low. That means that the code base fits more in your brain, that you need to understand fewer rules, fewer exceptions. And I think this is really the key factor in software development. I think it’s really to keep complexity low, because in most projects, unless you are writing an operating system, a framework or rocket navigation you are not coding against hardware; like the hardware is not your bottleneck. You are coding against human brains, cognitive abilities of your team; like how many smart people your company is able to put on your team, this is your limiting factor so we need to keep complexity low and I think it’s really the most important benefit.
A Request To You All
If you're enjoying this show, would you mind sharing it with a colleague? Check your podcatcher for a link to show notes, which has an embedded player within it and a transcription and all that stuff, and share that link with them. I'd really appreciate it if you could indeed share the show.
But if you'd like other ways to support it, you could:
- Leave a rating or review on your podcatcher of choice
- Head over to dotnetcore.show/review for ways to do that
- Consider buying the show a coffee
- The BuyMeACoffee link is available on each episode's show notes page
- This is a one-off financial support option
-
Become a patron
- This is a monthly subscription-based financial support option
- And a link to that is included on each episode's show notes page as well
I would love it if you would share the show with a friend or colleague or leave a rating or review. The other options are completely up to you, and are not required at all to continue enjoying the show.
Anyway, let's get back to it.
Jamie : [36:34] So I really appreciate that you are thinking about the developers and the cognitive load that the developers have to be under in order to work on a system. As someone who does a lot of starting on new or projects that are new to me and then getting up to speed and then becoming as productive as I can as quickly as I can, knowing that I can put some of the design for the system or some of the rules or whatever to one side and not have to worry about it, because perhaps the compiler is going to yell at me as soon as I start stepping out of that boundary , because, you know, you’ve got your custom version of Roslyn and maybe the team has set up these verifications and stuff. That really helps me to actually focus on the task at hand instead of the ceremony around it, y ou know. “Have I injected this thing or am I newing it up? " That’s a very, very simple example. It’s not the best example ever, but hopefully you get the point, right?
Jamie : [37:34] Having to not worry about how I’m doing these things and accidentally stepping out of line and doing it wrong and just being able to just do it. That’s a huge thing. And especially with, like I said, cognitive load, the amount that we have to hold in our brains about the business logic and about how the app is architected. And perhaps you’re using a number of services—whether they’re microservices or monolithic— you have a number of services you’ve got to remember to call and how to call them maybe you’re sitting there going, “i’m writing all of this code. Wait there’s a library to do that.” If I can take as much of that cognitive load away from someone and just let them write the code that needs to be written that then makes their job so much easier. So I am fully on board with anything that makes it easier for people to get started.
Gael : [38:22] Yeah. It’s it’s a responsibility to be a, to be an architect, to be a coding architect or a senior developer. I think our role is to be a performance multiplier for the rest of the team. Typically, we see that customers of PostSharp and Metalama, they often have about 10% of the team actually write the aspects and then the rest of the team will just use them. And that’s important because when you embrace metaprogramming, you don’t need to train your whole team. And that could be counterproductive, actually. You want the architecture role, whether it’s a role or a team or a hat, it doesn’t really matter. But this role should define how everybody should write the code and then create the infrastructure and select the tools, select the processes, select the patterns so that the whole team can be productive. And I think this is the role of senior developer. It may be the role of the team leader too.
Gael : [39:26] It is not just about metaprogramming. It’s really, “how do I create a work environment, including all the tools, the practices, the processes I will put in place that my team is going to be to be productive now? “nd 10 years from now, we are still going to be able to to maintain this software and we are still going to be productive.” That’s very important.
Gael : [39:51] And when you talk about metaprogramming, you should pay very attention that if you open that Pandora box of being able to do anything with anything and to do any random change, you can make things much worse. If you use Metacompiler to do your own custom changes, it can be much worse than doing that another way. That’s why we build these tools that actually gets you the level of abstraction that you need to be productive and does not encourage you to hack. We are not in the hacking industry. That’s that’s not what we want to do. Sometimes we need to hack to allow other people or users to be more productive, but we don’t want our users to hack. This is not why we develop these tools.
Jamie : [40:41] That was going to be something that I was going to ask about with how folks can really kind of change their mindset and their benefits and challenges of doing metaprogramming specifically with Metalama and in. NET. Are there any misconceptions that you hear a lot with regards to metaprogramming? Whether it’s Metalama specific or not right. Just like metaprogramming as a subject; are there any big misconceptions that you hear all the time?
Jamie : [41:09] So as a podcaster I hear, “oh well. It’s super easy. You know, you just hit record and away you go.” And folks can hear how much i’m stammering and falling over my words. I know we talked a lot about how, “we’re not in the hacking business,” and how we’re talking about how to make it easier and safer to make changes. And how to make it easier for folks to get up to speed. I get the feeling one of the common things you’ll be told along the same lines as testing right, “it slows me down. It makes my work take twice as long. It’s more confusing.” Is that something that comes up a lot?
Gael : [41:40] Like, aspects done badly are worse than having no aspects. There is a big responsibility on the shoulders of the aspect author. That’s also why we build aspects. So we have a library of ready-made open source Aspects that you can use. And you need to be careful when you build aspects because you can make the life of your team worse if you don’t pay attention.
Gael : [42:05] So yeah, a misconception would be that it is necessarily more complex because no, you can make it in a way that it is way easier. You know, PostSharp our previous generation of product is used in a line of computed tomography scanners. I will not name the vendor, but we are talking about a three-digit number of developers working for 10, 20 years. And they saved tens of millions of dollars if you count the number of lines of code. So, of course, if you get into these kinds of projects, you need to pay attention. It’s not like you are coding just for yourself. You have responsibilities.
Gael : [42:52] So that’s one misconception. that is going to make things more confusing. Another misconception comes from aspect-oriented programming that I believe got bad reputation, probably for good reasons. So aspect-oriented programming was designed in the early 2000s at the Xerox PARC Laboratory, very famous to have invented the mouse, for instance. But it was an academic research group. And they had a terribly theoretical formalization of these concepts. And they came with barbaric language like point cuts and joint points. But we need to remember that this was 20 years ago. And an AOP of 20 years ago was very different. Actually, AOP was designed at the time that in Java, there was no custom attribute. So they had to come with a way to add aspects. So I think that one of these misconceptions is that it is academically complex, because I think it is not deserved and now in the modern implementations, I think it integrates very simply with the language. So that’s the second one.
Gael : [44:13] We talked about debugging. Many believe that debugging must be much more complex, but actually no, because you can choose if you want to debug the source code or the generated code. We talked about the misconception that it’s terribly difficult to maintain the Roslyn fork. No, it’s just a couple of days per year to maintain this fork.
Jamie : [44:37] So let’s say someone’s listening in to this and they’re like, “I want to do some metaprogramming stuff on one of my projects, because perhaps I’ve got something that is happening all over my code base and I want to simplify some stuff. “What’s the best process for them to sort of go from, “I have no meta programming,” to “I’m now using Metalama and I’ve maybe taken a small piece of my app and simplified it by having it generate, maybe that one percent of code that makes it easier to understand”?
Jamie : [45:10] There is obviously a step required to go from no aspect-oriented programming, meta programming, Metalama to some.
Gael : [45:18] Yep.
Jamie : [45:19] So is it just a case of: take a step back, have a look at the design of the application and think about how aspect-oriented programming, how metaprogramming, how Metalama can help? Or are there, sort of, rules of thumb that you can apply that will help to identify areas that you can simplify to make it easier? I’ve said simplify twice there. Sorry.
Gael : [45:41] It’s maybe better to get started with a project that is not under stress, you know, where you are far from your release date, so you can take a bit of freedom. You can start with the free edition of Metalama that allows for up to three aspects per project. So you can start playing. You can go to our documentation website, you would find a lot of examples, a few videos. You can go to Metalama Marketplace, where we have a repository of ready-made aspects. All of them are open source, so you can check if something can be applied to your project.
Gael : [46:21] I guess in the first phase, you would do something that you find immediately useful. And then progressively, you will change your state of mind. And you will change the way that you will think about making software, about writing software. And then this is when it becomes interesting. Because first, during the first year, maybe, it will be kind of shy. You will just test the waters. And then you will understand, “oh, I can do this pattern and this pattern. "
Gael : [46:52] The last misconception is that once you start using Metalama is for life, you can never remove it like any other library. And that was a problem with PostSharp, because with PostSharp, we generated IL code, and we couldn’t give you the IL code and say, “well, you know, maintain your IL code.” And actually, a lot of potential customers would not go to PostSharp because there would be no good way out. So we took that into account when designing Metalama, and since anyway we are generating C# code, we have a feature where we tell the compiler, “before you compile, you write the code back to the source code, " and then actually what you get is a commit where you have all the code generated from Metalama. You have that in your commit and you can check for yourself and like accept or not every change, and go back to a life without Metalama. So that’s an important feature that we built because we understand that some projects want a way out if you have a different opinions about the technology or if there is a failure from our parts. There is no vendor lock-in. We try our best not to put you in a situation where you would be locked with Metalama.
Jamie : [48:12] I appreciate that because like you said, with PostSharp, because it’s generating the IL, not generating extra C# code that’s passed through Roslyn, that was super non-trivial to do. So I like this idea of being able to try it out, being able to see if it fits with your workflow, with your team, with your design, and then not having to go, “whoops. Now we’re kind of, in inverted commas ‘stuck’ with it,” right. We don’t want to be in that position.
Jamie : [48:38] It feels like there’s almost no downside. That’s the feeling I’m getting right. There’s a way to try it out and we can export the code if you need to. It feels like it makes sense to give it a try and see see how that works for everyone right. Where’s the best place for folks to go to learn a little bit more about Metalama and metaprogramming, and because I guess they’re going to have to have a little bit of background of aspect-oriented programming to start with? Or is that something that you cover in your documentation for Metalama?
Gael : [49:10] Yes, you should have a good practice with C#, one of two years, because it’s not the first problem you are going to solve. Code repetition is something that you get in larger projects. But actually, I’m just saying that my 16-year-old son tried Metalama in a project. So really, there is no requirement of any prior experience.
Gael : [49:38] So you go to our website, Metalama, or just Google Metalama—with one L, because with two Ls, it started to be the large language models, unfortunately, they took us the name. We were first. And then you have some tutorial videos that I recorded a year and a half ago, commented examples.
Gael : [50:06] So you have a series about logging for instance, like the first example is very simple it’s like five lines of code and then you have progressively adding features, going exploring a rabbit hole of logging and then we explore many rabbit holes like builder pattern. In the documentation, you have a complete documentation. And we have, as I mentioned, the Metalama marketplace where you will find ready-made aspects that you can just use. It’s very good to understand the concepts of metaprogramming. But once you will do your first simple aspects, sometimes you will be happy that we spend the time to do the real production aspects because it can become tricky to do something that really works with all code.
Jamie : [51:01] So what I’ll do is I’ll get some links from you for documentation and like the the videos you were talking about things like that so that folks can try it out. There’s going to be a link in the show notes to find out more about Metalama anyway . Are you someone who’s approachable, can you can folks get in touch with you? Like not everybody is but like maybe X or LinkedIn or something like that. Is there a place where folks can reach out and say, “hey Gael. I’ve got this question, can you answer that?” Or is there like a forum or like a Slack group or something that folks can join, if they have questions?
Gael : [51:32] Well the best way for for technical questions is to reach out on our Slack workspace that you will find [on] our website, and you get an invite to the Slack workspace. You can find me on on LinkedIn. We are not very active on Twitter, so Slack and LinkedIn would be the two channels. We are on github we manage all bugs on github. Metalma is completely source available, you can look at every single commit. And don’t forget, there is a free edition with three free aspects per project. So you can really get started free of charge with full support from the development team on Slack.
Jamie : [52:11] Amazing. Thank you very much, Gael, for having this conversation with me. I feel like I’ve learned a whole bunch more. I already knew a number of things about aspect-oriented programming, and this has really sort of glued a couple of those things together and brought me back with way more information than when I started. So I really appreciate you being on the show. Thank you ever so much.
Gael : [52:32] Thank you for having me, Jamie.
Wrapping Up
Thank you for listening to this episode of The Modern .NET Show with me, Jamie Taylor. I’d like to thank this episode’s guest for graciously sharing their time, expertise, and knowledge.
Be sure to check out the show notes for a bunch of links to some of the stuff that we covered, and full transcription of the interview. The show notes, as always, can be found at the podcast's website, and there will be a link directly to them in your podcatcher.
And don’t forget to spread the word, leave a rating or review on your podcatcher of choice—head over to dotnetcore.show/review for ways to do that—reach out via our contact page, or join our discord server at dotnetcore.show/discord—all of which are linked in the show notes.
But above all, I hope you have a fantastic rest of your day, and I hope that I’ll see you again, next time for more .NET goodness.
I will see you again real soon. See you later folks.
Useful Links
- Gael on LinkedIn
- PostSharp on LinkedIn
- Metalama
- Metalama Documentation
- Metalama Marketplace
- Metalam on GitHub
- Supporting the show:
- Getting in touch:
- Music created by Mono Memory Music, licensed to RJJ Software for use in The Modern .NET Show