The document provides insight into:
- why repetitive code is a major source of pain
- what technologies for pattern automation exist today
- why you should consider a pattern-aware compiler extension
- what investment gains you should expect
The white paper was written for CTOs, software architects and senior developers in software-driven organizations—specifically in financial, insurance, healthcare, energy and IT industries that typically write a lot of repetitive code.
Additionally, we hosted a webinar that covers the white paper topics. Watch the recording and learn about the consequences of boilerplate code and how to eradicate it with pattern-aware programming. You can also download the slides.
- The Problem: Repeating (Boilerplate) Code (1:14)
- The Solution: Inadequate Technologies (4:23)
- Four Reasons for Pattern-Aware Compilers (10:18)
- Ten Features to Look For (13:39)
- Return on Investment (44:42)
Hello everybody. My name is Gael Fraiteur. I'm the founder and CEO of PostSharp Technologies. Today I will deliver this webinar about our new white paper, Ten Reasons Why You Must Consider Pattern Aware Programming. Before I dive into the slides, let me just set a few rules. This webinar will last 40 minutes, and after the 40 minutes there will be a Q&A session that can last whatever time you want. Please write the questions not to the chat window actually, but to the question window in GoToMeeting, and after the slides I will go through that and answer to everything.
There are three rounds of this webinar. This one is the second one, and tomorrow we are going to take the best recording, make it available and send you an email.
The Problem: Repeating (Boilerplate) Code
We can start. The problem that we are trying to solve here is the problem of repeating code. What we are calling boilerplate code among developers. Basically, developers are not different than other professions in this specific thing that we think at a high level of abstraction using patterns. Other professions do the same, so if you ask an architect to design an industrial building, he would not design everything on windows separately of course. You design a pattern of a window and say, "Here, I need 200 of these patterns." That's just how the human brain works, and that's fine. Developers do the same. We are using design patterns when we think about software. The problem is that when we go to implementations, the languages that we need to use don't have the concept of pattern. Therefore, we need to translate the pattern into C# and we are executing the repetition ourselves and our code contains a lot of repetition. This is what we call boilerplate code.
Typically, we would find boilerplate code in features like INotifyPropertyChanged, undo/redo, code contracts, logging, transaction handling, threading, security caching, and so on. All these kind of features translating to patterns of code that actually translating to boilerplate code. The problems of boilerplate code is that well first you need to write it. It takes a lot of time, it takes a lot of effort. It actually produces bugs, defects. It actually prevents you to write good software as good as you could, and the code is more necessary than it should. That means that one of the biggest problem of complex code is that it is difficult to modify after the first release. In a typical enterprise software that has a lifetime of many years actually the version 1.0 is maybe only just 20% of the overall cost. Maintainability of source code is very important.
Another angle to the same problem is to look at it from the point of view of new team members. How hard it is to look at the code and understand it. The simpler your code, then the best maintenance. Boilerplate code costs the industry a lot of effort, a lot of frustration. The big question that the whole industry is trying to address here, is how can we produce high quality software with less development effort, but without having to replay the compiler, the language, the platform and so on? We are not looking for one more new language that will magically solve all problems, because we've been in the situation many times in the last decade.
What’s the solution? First, lets see a few technologies that are not adequate for this specific problem. One thing that comes in mind quite soon is dependency injection. Actually if you realize that a few patterns like exception handling can be implemented quite easily with interceptors. It comes quite natural to use a dependency injection. With dependency injection you can inject behaviors at the boundaries between components. That means between a service, and a consumer of that service.
The problem is that, if you like to inject not only dependencies, but also behaviors, you will actually split your application into smaller, smaller, and smaller components up to a degree that no longer makes any sense. It will affect your architecture and always for actually bad reasons, because with dependency injection and just interceptors, you can only support quite basic patterns, not the more complex ones. Dependency injection is a great tool, but it is not a great tool for automation of design patterns.
Another category of tools are code generators or refactoring tools, and here I want to be very clear that this is not what we are looking for. We are not looking for a category of tools that generate code based on some pattern definitions because source code, even if it has been generated, it is still source code. That means it needs to be maintained. We don't just need a tool that will generate things that we need maintained. We actually need the source code to be as clean as possible.
These two technologies are not adequate for pattern automation, but there are other technologies that you already know, and that are adequate, and they cannot be ignored. Metaprogramming, for instance, comes quickly as an example of something we could use to implement pattern-aware programming. With metaprogramming you actually get access to the program at a very low level of abstraction. If you do metaprogramming with Roslyn, you will get the abstract syntax tree, and at the other end of the pipeline, if you do metaprogramming with Cecil, for instance, you will get the IL code. The problem with these two extremes is that the level of abstraction of any of these forms of code is too loud. You are going to actually write almost a compiler, or write at a very low level, and you don't actually need it. Most of patterns don't need to know the difference between try finally and using for instance. Metaprogramming is a good tool, but in itself this is not the solution. We want to raise the level of abstraction, we don't want to lower it.
Aspect-oriented programming. This is a step in the good direction. This approach to programming is already 20-25 years old so there is nothing new, and those of you've been knowing PostSharp for a long time know that we actually started as an Aspect Oriented Framework. Actually, I personally have been involved in Aspect Oriented programming for 10 years, and so at some point of thinking and talking about AOP, I started to realize that the way that we are talking about AOP is not the right way. The way that AOP is communicated is with cross-cutting concerns and so on, and then I realized, "Well this point of view is way to talk about AOP is actually even too low level. AOP is a technology, but what is it good for?" Then I realized, after being in this business for seven years, I realized, "Well this is excellent to implement design patterns."
If we take design patterns seriously, design pattern automation become the goal, because why we are doing that? We are doing all this technology, metaprogramming, aspect-oriented programming. We are doing that to automate the implementation or the validation of design patterns. Then when we have this objective, then it becomes quite clear that we need other technologies and things like static program analysis, or even dynamic program analysis. They can all converge in order to automate the implementation of design patterns, or threading patterns.
Pattern aware compilers are not something that comes out of the blue, a completely new thing. It is the convergence of many technologies into what I believe would be a new generation of smarter compilers that allow us developers to work at a higher level of abstraction.
Basically, we don't want to design a fully new language. This is useless. We can do that in C# and VB, in Java, we just want to extend the language with this notion of pattern, which actually is implemented partially through aspect oriented programming.
4 Reasons for Pattern-Aware Compilers
What are the main reasons to consider a pattern-aware compiler? First, the boilerplate code. You would no longer need to write and maintain this boilerplate code so you can deliver faster. Basically, what we are doing here, we are realizing that companies are paying software engineers quite a lot of money, and a part of their work is just repetitive and boring. So the employer has to pay a lot of money, and the engineer has to do boring work. There is something that is not really good there. Now, in enterprise setting there is a big part of your job that is not fun at all.
The idea is that machines are much better than us in doing repetitive work. They are faster, and they are more reliable, and they never get bored, so that's what we are doing here. We are outsourcing the repetitive work from highly qualified people to machines. A second reason to consider pattern aware compilers is that we will be able to build more reliable software. First, because there will be fewer lines of code and since every line of code is a potential hide for a defect, fewer lines of code means fewer defects, but also, if you look at the difference between a prototype and the production ready application, you would see that most of the difference is in features like logging, exception handling, caching, security and so on, and so these are features that actually typically generate a lot of boilerplate code.
Now, if we have the right tool, it becomes much easier to implement this feature. I keep hearing everywhere now that you need to log everything. Quite frankly, how do you log everything if you have to do it manually. You need the tool to do that. With a pattern aware compiler you get the tool and reliability comes much cheaper.
The third reason is that with a pattern aware compiler, your code is cleaner and shorter, so it is easier to understand it means that you can focus on business logic. It means that the code is more maintainable, and this is actually very important to have maintainable code. Also, from a point of view of team dynamics, or division of labor. Because the business code is better separated from the patterns and multi-threading and so on, it's actually simpler for a developer to modify business logic. That's very important. It means that you can have a multithreaded experts in your team, or caching experts, but the rest of the team doesn't need this level of understanding. That's very important.
These were the top four reasons to look at pattern aware programming.
10 Features to Look For
Lets now look at the top 10 features to look for and because I'm talking from PostSharp here, I will show you for a few of these points how this is implemented with PostSharp. Lets start with that. The first point to look for are ready-made pattern implementations. The idea is that I believe, I hope in the future, you will be able to purchase pattern implementations on the marketplace, just like you can buy a Graph or DataGrid. I think there is no reason in the future that you couldn't buy INotifyPropertyChanged implementation, and maybe you could have even several vendors proposing that. Currently, we are the only one proposing this as a commercial product.
This makes developments much faster because you can actually get started very quickly. I will switch to my development machine and see how development looks like when you have a set of ready made pattern implementation that you can use it. I have this very simple form. I'm doing a few changes, and you see this field here, this text field is a composite text field, and it doesn't get updated. It should actually show my name and the town should be here. It doesn't get updated, this is because I didn't implement NotifyPropertyChanged. If I look at my source code, you see I have a property here. I have a composite property, so this will not be very complex to implement manually. Here that would be okay. For the customer view model, it's a bit more difficult because I also have a composite property that depends on the property, of a property, of a property, all these properties are mutable, so this may be a bit bothering.
With PostSharp you would put your caret here and then you get the light bulb and you say, "I want to implement, NotifyPropertyChange" here. The first time that you go through this process, PostSharp installs itself into the project because it is delivered as a NuGet package, but the second time you will see I need to do the same on the view model, second time is faster because it's already implemented. We are telling the compiler what we want, not how to do that. We want INotifyPropertyChanged and now the compiler is doing the job. It looked at the code, look at dependencies and you see that all this things works, even dependencies of properties, of properties, and properties. All these things work properly.
What the compiler did here is to actually look for dependencies between different properties. It knows that a change in customer possibly affects property full name and now PostSharp knows that this property depends on customer. Customer.first name. Customer.last name and so on, and so on. The compiler gets an understanding because we did static analysis on the code. We understood it and we implemented the pattern based on aspect-orietned programming, but also based on static analysis. You see how converging technologies can actually create something very useful, very powerful.
This was a very simple example. I would like to implement something that used to be so complex that nobody did it. I'm talking here of undo/redo. There is a Memento pattern from the Gang of Four book. It's not the one we selected, because actually we can do better. There is a better pattern if you have a better compiler concept. The concept is here Recordable. We are making the object recordable, and not only the object ... Should not have closed this assistant actually. Not only the object, but also the whole model should be made recordable. Okay, here is it. Here it's a bit more complex, because I don't know if I don't tell the compiler I don't know if the collection of addresses is a child or is a reference. You see how we are taking concept from UML here. If it is a child, I need to track changes in the collection of addresses. If it is a reference I don't need to track changes in the collection itself, but if I need to track changes in the collection, I need to choose a collection that actually is able to track these changes. Okay, I need to change it here also.
It‘s quite interesting to see how we go from design patterns that are designed fine on paper, on a white board, to actually something that now is inside the language. I just made my model recordable, and now I'm going to add the undo/redo control. Okay, going back to my window and I don't need this. I need to define the namespace for undo/redo, and just add the controls. The real value of the undo/redo pattern is not really in the control itself, but we provide them so its easy to get started. Lets just redo the same changes. Okay, you can see I can do undo, undo, undo, redo, redo, redo, and that just works and my source code is still source code. I can go here to the tool table. I see that the compiler extension added Aggregateable, Recordability, INotifyPropertyChanged, but it is still my source code. It has still business meaning. I can still go to my manager, or customer and they could understand approximately what the code is doing because it's not polluted. That‘s what we can expect from pattern aware programming, and we can get that feeling of productivity to get started.
Another area where we have ready made patterns is multi-threading and I think its extremely, extremely important. C# and VB are multi-threaded languages. Well the language itself is not aware of threading at all almost, so it's very easy to create multi-threaded applications, especially with async await now. Its very easy to create bugs because the language is not thread safe. There is almost no feature in the language to make it thread safe.
What happens is that there are data races. When you have different cores or threads executing code on the same data, at the same time you get corrected data structure. Minutes, or hours later, some other code path can evaluate the data structure, but it discovers that invariance are broken basically, or have been broken by the data race, and you have an exception that is random first. That is absolutely unrelated to root cause. They are thousands of bugs this way. This kind of data races and it's very, very hard to diagnose especially because they are random, they happen only in production. They may have a probability one on the million, one on the thousand. Something like this. Randomness is the problem.
To address data races, developers typically use logs, or they would implement message queues, events and so on. The problem is that this is too complex for the human brain. It doesn't matter how smart you are. If you have more than a few logs in your applications, it just becomes too much. It becomes to easy to forget to take a log, or it becomes to easy to just get completely messed with that. The problem is not the machine here. The problem is that the human brain is too limited to handle this level of detail. We can blame the human brain and say that everybody should be smarter, and go to training, and so on, or we can blame the programming languages. We can say, "Well, let's try to make them simpler. More adapted to the real cognitive abilities of people."
That's what we are doing here, and there are ways to do that. We didn't invent anything, like the Immutable pattern is well known, Freezable, Synchronized pattern where you take a log at every method. The Actor pattern, Thread Affine. These are well defined patterns, but there is no support in the compiler unless you move to a compiler that specifically supports Immutable, like F# for instance. What we are proposing here is let‘s stop building new languages on the top of threading patterns and threading models. That's not the right thing to do. Let's extend the language in a plugable way with different threading models that you can choose from. There is not a single threading model that is good universally.
Once you choose a threading model for a specific class the compiler would emulate code that validates that the code is valid against the model, and the validation would occur both at build time and at run time. We have both static analysis and dynamic analysis of your code to make sure that your assumptions are verified, are correct. This is an example here from our own source code from the Visual Studio tooling. The text marker layer is responsible for underlining the code that is the target of an aspect. Our assumption when writing this code is that this class is always going to be invoked from the UI thread. How do we know that? We just believe it. We hope. Hope is not a good engineering principle. What we did here is that we added a threading model Thread Affine and the compiler extension will now enhance the class and add code that will throw an exception at run time if this assumption is not true. If I believe it will be called from a UI thread, but instead it is called from a background thread because I have an event handler coming from the background thread.
I'm going to have an exception. It's going to be deterministic and I'm not going to have a data race. This is very important to have deterministic failure. The big benefit that we get from threading models, not so much saving source code, but is making failures deterministic, fail fast and fail deterministically even in a single threaded test coverage. This is very important.
Okay, I've been talking about design patterns, ready made patterns, sorry, and threading patterns, a sub category of these patterns. Now I want to talk a bit more about custom patterns because there will always be patterns that are specific to your project or to your company, and you still want to automate that. For this you will need a framework. There are many frameworks available, and here is what you can look for.
Most of these frameworks, they support interception of methods, and this is okay for some patterns like transaction boundaries or some kind of basic logging and so on. This is fine, but look for the availability of more complex transformations in case you need to implement a more complex pattern. Can you intercept events, or throwing events? Can you introduce new methods interfaces and so on? Can you combine these things together? What happens if you have several aspects on the same declaration? How complex is it to use this API? Look at these kind of features. I would like to illustrate the process of translating a pattern into implementation artifacts as can be executed by the compiler. For this example, I will take the Weak Event pattern. You can use your favorite search engine and type Weak Event pattern. You will get to an article on MSDN describing the pattern.
What the pattern is solving here is this problem that normally with a default implementation of an event in C#, the event source holds a strong reference to the delegate. The delegate holds a strong reference to the event client, and therefore, you have a memory leak because you have unexpected or unpredicted strong reference from the even source to the even client. This is probably difficult to understand and to diagnose especially for new developers on the team. Very common source of memory leaks in .NET. What's the solution? According to the article, the source should store only a weak reference, but the client should store a strong reference to the delegate, because if nobody stores any strong reference, the delegate is going to be collected immediately, and the handler is never going to be invoked after the first garbage collection.
Now let's translate this pattern into aspects. First, we have an aspect weak event that we apply on a standard C# or VB event, and the role of this aspect is to make the event store a weak reference instead of the strong one. But that's not all, because we still need to implement the other requirement that the client should store a strong reference. Inside the pattern, I'm defining an interface IWeakEventClient that actually has two methods, addreference and remove reference, or subscribe, unsubscribe, so this semantics. The only implementation is to store a strong reference.
I can implement these two requirements. Implement automatically the interface should the weak even client interface, and implement the weak event using custom attributes. The custom attribute is how the developer says what he wants and it actually is implemented as an aspect. Two artifacts, two aspects, and the third artifact is a validation. Whatever code that registers a handler to my event should be in hands by weak even client.
Let me for now dive into the two aspects. I will not dive too deeply because that would take a lot of time, but I will show you ... it's not this one. This is PostSharp samples. You can download the samples on samples.postsharp.net. You will see this sample code is there. You can download this from GitHub to have the freshest version.
This is the weak event attribute. It is an event interception aspect. We are intercepting the action of adding a handler to the event instead of adding the strong handler, we are actually adding a weak reference. We are registering the even handler through this interface, through the WeakEventClient interface. On the remove handler we are doing the opposite thing, and on evoke handler we are actually de-referencing the weak reference calling on the target.
This is an implementation of one aspect, and this aspect is a part of the implementation of the pattern. Now, on the client side, we introduce the interface a IWeakEventClient and event into the target class and this is simply the implementation of the interface. It's very easily we have a thread safe implementation. Now that we have the code, we can use the code. I can mark one event as a weak event, and then the client of this event is weak event guide.
Okay, that was to illustrate how we go from a design view of the pattern, to an implementation using aspects. A bit later, I will show how we can implement the validation.
Let me move forward. How do you add patterns to code? One way is to add the custom attributes. I've shown it already now. Sometimes it's cumbersome to add the attributes one by one. For instance when you want to log everything, so it's good to have multicast attributes to actually add things to a lot of ... to all public methods for instance of an end space.
Another way to add aspects is to use inheritance. For instance, if I add NotifyPropertyChanged on my model base class, it will automatically be implemented to all classes derived from this. That's a useful feature. Other frameworks propose configuration through XML, even some frameworks to JSON so the idea is that there is a non-source code file to do that.
PostSharp proposes to programmatically add aspect at build time. That means basically that you have code that executes inside the compiler that actually provides the aspects according to whatever analysis you may do with system reflection, for instance. You could look at all classes that have a data contract attribute and add some aspect based on that. Some frameworks allow to add aspects and behavior at run time which can be sometimes useful, but this is not a compiler technology. This is available in frameworks that are based on dependency injection, which is cool for some categories of behaviors, but I would not consider that as being a pattern enabling technology.
Another thing to look at is: is the framework compatible with your existing code base. There are two angles for that. First, does it just work with my technology stack? And the second angle is to look well what kind of changes do I need to my code? Some framework, if it is based on dependency injection you will need to do a lot of changes, but the answer otherwise is not black and white. For instance, in PostSharp, if you want to use threading aspects or undo/redo, you will need to annotate your code with chart and reference, which is invasive, but for some other kind of aspects like logging or transaction handling, there is no assumption at all. Depending on the patterns that you want to implement, the neutrality can be total or it can be partial. Pay attention to this angle.
Okay, here is quite an interesting point of view on software development. From our experience delivering PostSharp for 10 years now, we know that typically in the medium teams, eight-ten people, 10% of this team would actually design the patterns, do the white boarding and the architecture and so on. Then members of this team would implement the patterns with aspects. This team can be called system developers, architects, senior developers, name that doesn't really matter here. What matters is that this team creates the framework based on which the rest of the team will build the real business logic. Now there is a big responsibility on the shoulders of this architecture team.
Suppose that the team creates a caching aspect. Delivers it to the team and the HR division just hired 15 people from university, and every single day they come to the team leader and say, "Hey, my caching aspect doesn't work." Then you debug, you debug, and you realize, "You guys are caching an enumerator, this cannot possibly work." Or, "You are caching the stream. We don't support that." If they come every single day with this question, put the blame on yourself as the designer. You are the one who actually designed the aspect incorrectly, because if you designed it properly, they would not come to you. That means that you have the responsibility as senior member to make your junior staff productive. I think that's quite an important angle of senior software development as a social activity, and not as alone warrior activity.
Here we are definitely not in the perspective of ninja coders and so on, but as collaborative multirole development. How do you do that? Well just as you have preconditions that you check the value of your input parameters is as expected, you would actually build, or implement build time validation to check that your aspect is used as expected. You can apply this principle to aspects, but you can apply the same principle to patterns that you recognize as being patterns, but you cannot automatically implement them using aspects because there is too much code to be written manually.
For this, for instance, if you decide that all business roles should be in a public class named something business rule and should have a public nested class called factory with a public constructor with a method explorer custom attribute and so on, and you have half a page of documentation to tell people how they should implement the 200 business rules in your app. You can deliver the half page of documentation, or you can also implement validation at build time to make sure that this is being validated automatically.
I'm going back to my demo here, back to the program. Suppose that five developers in my team went to my desk today wondering why there are memory leaks and so on. I could implement a validation, and I will do it here, so that when I add an event handler, but my class is not a weak event client, I get an error. I got the error here and it was actually pretty easy to implement this validation. Easy when you know how to do that, or if you look at a sample. Basically I'm enumerating all weak event attributes in my assembly now here and what I'm doing here. I'm looking for all methods that are calling the other of the event. Then I'm getting the method body of this method to be compiled as an expression tree. Then I create a visitor. Inside the visitor I'm going to visit specifically method calls. Specifically calls to the event other, and then I'm just looking at how this other is represented in MSIL. This part is a bit more complex. This is actually a new object. This is a constructor call and then I have a method pointer which is an MSIL concept here.
Then I'm just asserting that the type I'm passing implements the interface or has the aspect. If it does not, I'm writing an error on the client type with my error code message and so on. I can implement validation for even relatively complex things. Doing that, I am helping the whole team to be productive. They don't need to search and to debug manually, or to go to my desk, which means that they previously lost three hours because they are afraid of going to my desk, and so on, and so on.
Let me rush to the end because now I've gone through the main points. Visual Studio integration. That's also quite important. Not to be rushed actually. Developers will ask questions with coding. It's very important for developers to understand what a piece of code is doing. It's less important to understand how it is doing it, but what the piece of code is doing is important. It's not obvious if you don't see inside the code that there is some behavior. The way that we solve the problem in PostSharp is that we have Visual Studio tooling here, and for instance, if I go to the address model, I don't see that there is NotifyPropertyChanged here, but if I put my mouse pointer on the setter I can see, "Oh yes. This is being enhanced by PostSharp and specifically NotifyPropertyChanged is doing two things here to enque changes and to flash notifications. You can actually know that something is being done. This is important. You don't need to understand how this is done. This is a concern of the aspect developer.
A second point is which aspects are present in the solution, and this will be here in the Aspect Explorer. Another thing is how to debug with or without the aspect. Okay, run time performance. Build time technology is always going to be faster at a run time than a run time technology. Look at that and commercial support make the difference between master thesis work, and a real supported product. There are a few open source products that are really supported, and you will see immediately that they have been there on the market for several years, but pay attention to this project that has received effort just during six months, then don't get maintained.
Typically, people would be afraid of not understanding the code, but this is really a problem of tooling. A Visual Studio integration in this case, not of the technology itself. Debugging is also a concern, but it's affected in major products. There is a problem of compilation time. It will also be slower to have a smarter competitor than dumm compilers. You will always have slower builds. Another question is what is better: to wait a few more seconds for the build or to have 20% more of engineering time. Because this is actually what you actually get.
Return on Investment
Typically, when a user uses the product significantly, not just for one method, but significantly, so the top quartile actually saves 20% in average. If you count on the US market $100,000 per developer and per year, which is not even an overestimate on this market, when you will see that it can mean up to $20,000 of savings per developer and per year, so there is quite a big potential. If you take more source code point of view, on the US market, probably also on Western European market, every single line of code costs your company $14.00. Think about that. Of course, also boilerplate code.
Picture this. Picture it that your team is using a pattern aware compiler so that there is no more boring and repetitive coding. No more hours trying to understand the business logic sunk in an ocean of boilerplate code and highly technical stuff. If you are using thread safety aspects, you have no more random errors or much fewer of them. If you are using architecture review properly, your code reviews can be much smoother. You would be much less disturbed. Basically, what we are achieving there is to cut development and maintenance costs of the whole development process and go to market faster. With that, we are doing through pattern aware compiling a few more steps into this direction of the holy grail of software development, to produce high quality, easy to maintain software that has fewer bugs with less development effort, and I would add even with less development skills because looking at the job market for developers is pretty hard to hire skilled developers, and it‘s a pity to have them writing boilerplate code. Life is good for developers, for architects, for managers.
This webinar was brought to you by PostSharp. The number one pattern aware compiler extension to C# and VB with more than 10 years of presence on the market. Trusted by 10% of Fortune 500 companies. Mostly, companies that have boring code bases and large teams, and need to really optimize that: financial, insurance, health care, technology companies with a lot of repetition I would say.
For more information you can download the source code. You can download the product. You can download the white paper. You can read customer testimonials, case studies, and you can ask questions now in the question board, or you can write to email@example.com if you have questions that come to you later today.
About the speaker, Gael Fraiteur
Gael started programming as a kid and never stopped - building and selling his first commercial software at age 12. He is the Founder and CEO at PostSharp Technologies, a widely recognized expert in aspect-oriented programming and pattern-aware programming, and speaks at developer events in Europe and the United States.