Posts tagged with 'c'
JavaScript is an object-oriented programming language. (This may be an overly simplistic statement). As an object oriented programming language, it's subject to some of the same pitfalls that other object-oriented languages have, in terms of boilerplate, cross-cutting concerns, etc. With that in mind, AOP is a tool that can be used to address these issues in the JavaScript portion of your application.
For instance, the Prototype JS framework has a wrap function that you can use to implement "the essence of AOP".
Here's a self-contained Hello World example:
A trivial example, but notice that JavaScript's dynamic/functional paradigm gives you the ability to "wrap" a function instead of actually "weaving" in a cross-cutting concern. In this example, prototype's capitalize function is being replaced, which is very similar to an interception aspect, and the underlying capitalize method is being called within that interceptor/wrapper.
One of the problems with object-oriented programming that AOP aims to solve is excessive boilerplate. And there's no more stark example of excessive boilerplate than the use of INotifyPropertyChanged.
NotifyPropertyWeaver is a tool that adds an MSBuild task to your project. It will find all your implementations of INotifyPropertyChanged and rewrite the properties to do all the notification code for you. So you don't have to worry about mistyping that property name string, and you don't have to worry about refactoring when you rename or remove properties.
In this code example below, the first file is a typical implementation of INotifyPropertyChanged, done entirely by hand. Notice all the noise and duplication: explicit backing properties, multiple calls to NotifyPropertyChanged to account for the derived property, the use of a string that exactly matches the property names. And this is a class with only three properties. Imagine if you had a whole bunch more properties, and imagine the maintenance problem to add/remove/change one of the derived properties!
The second file is an example of how you would do the exact same thing using NotifyPropertyWeaver. You don't have to write the NotifyPropertyChanged method, or call it in the setters, or write backing properties. This class is so much easier to read and maintain. The third file is actually a look at the class after it's been compiled, run through NotifyPropertyWeaver, and then disassembled with Telerik's JustDecompile. Look familiar? It's almost exactly the same as the hand-coded implementation.
And finally, the fourth file is the change that will be made to your project file when you add NotifyPropertyWeaver with NuGet. It calls a task that uses Mono.Cecil to rewrite the code for you. You don't need to reference the build task DLL in your project.
NotifyPropertyWeaver is a tool that does a single task, but this approach (an MSBuild post-compiler task) can be used to implement other AOP features. Fody is a tool by the creator of NotifyPropertyWeaver to do just that.
One of my favorite acronyms is "RTRJ" for "Right Tool for the Right Job". At worst, it's something of a cliche, and sometimes even an excuse or blanket answer. But I think it's an important thing to keep in mind whenever you are thinking about architecture of an application. If there was a perfect framework or tool for every job, then architecture would be easy because then every developer would always be on the same page.
I came across this article on CodeProject about making architectural decisions and choosing technologies for a .NET project. While you may not agree with every choice made for that project just from reading, I think it's interesting and important to note why each decision was made. For instance, the author was looking at IoC/AOP tools for the project, and considered many popular tools like Spring.NET, LinFu, and PostSharp. Ultimately, the author determined that Spring.NET was the best choice because of its documentation, integration with NHibernate, and the fact that it also comes with dependency injection capabilities. The author also notes the downsides and risks to using Spring.NET.
I think "Right Tool for the Right Job" consists of two main concepts: understanding the job and choosing the right tools. Everyone can probably rattle off their favorite tools, but are all of those tools correct for this project?
- Is the rest of the team more familiar with and comfortable with a different tool?
- Will this project be cheaper or faster to finish with a certain tool?
- What about support: is an older tool with a bigger support community better than a newer tool that doesn't have a big following yet?
- Are the benefits of new tool going to outweigh the uphill challenge of learning curves and convincing others to adopt it?
- Biases: even if you don't admit you have them, you have them. Figure out a good way to make your analysis objective: have others on the team do the spike and get their opinions. Try to play devil's advocate. Find someone to ask you the hard questions and find the answers.
- Is tool X being used just because it's always been used before? There's probably a good reason for that, but don't be afraid to challenge assumptions and the status quo, even if it does end up being quo.
Above all, don't forget: shipping is a feature. You could spend eternity trying to figure out just the perfect combination of tools and architecture, but ultimately the best way to get feedback is to get building! If you find yourself putting a square peg in a round hole during your first sprint (I'm assuming you are using some sort of agile methodology), say so at your retrospective and switch to something else while you still can.
Someone asked in a comment on my post about OnActionExecuting if one could get access to the model in these filters in order to record some audit data. I think this is probably a good use-case for using PostSharp or Castle DynamicProxy to write an audit aspect and apply it on your service classes or repositories.
But suppose you wanted to record certain fields and other audit information about information being modified in your controller. I wasn't sure if this was going to work, so I coded something up in 30 minutes, and much to my surprise it worked pretty good.
It's too long to embed here, but here's the Gist link to an Audit ActionFilter proof of concept. To use this attribute, simply decorate the actions you want to audit like: [Audit(typeof(SomeEntity), "EntityPropertyName1", "EntityPropertyName2"]. The filter will first check to make sure the incoming entity results in a valid ModelState. If it's not, then no reason to record an audit record because you aren't persisting changes yet (maybe the user missed a required field).
If it is valid, then it will interrogate the parameters and arguments to see if it can find one of type SomeEntity. If it does, it will then interrogate the properties of that entity to get all the values of the properties that are named EntityPropertyName1, EntityPropertyName2, etc. It will then record all this information, along with other audit information like action name, controller name, the current user, timestamp. All this "interrogation" is being done via reflection.
In my example, it just writes it to TempData so that it can be displayed back out. In a real example, it would write it to whatever data store you are using for your audit records (a database, for instance).
Problems with this method of auditing:
- Reflection - it's slow and brittle. This version is very simple and it's still quite messy. A real production version could be downright unwieldy
- Line 61 of CustomerController.cs - I'm making the assumption that a ToString on each entity's property is meaningful. That may not always be the case, which could lead to even more complexity.
- If you spell one of the field names wrong, you could have problems. Refactoring/renaming of your entity properties could break this quite easily.
That being said, if you have a very large system and audit requirements like this, then this messy approach could be better than the even messier alternative of boilerplate audit code in every controller action. I still think using PostSharp or DynamicProxy on the entity repository/service layer would be a cleaner approach.
I contacted Nestor with my proof-of-concept, and he had some comments about possible further refinements:
- Store the name of the class and properties to be audited in a class/model of its own, so an administrator could decide which properties to audit via some administration tool.
- Store the property/value pairs audited in a XML format in the model, facilitating the search of some values (what were the activities of a given user, who or when a given class was deleted o modified, etc.) using the abilities of SQL Server in making indexes over XML columns.
It's been a pretty light week as far as interesting new links popping up. But here are three interesting items to check out. Have a good weekend!
- The English in this white paper is a little rough, but I think they are using AspectJ to help find race conditions in multi-threaded programming. [PDF]
- This is an older post, but still relevant: Myths and realities about AOP
- Another AOP tool for .NET, called SNAP (Simple .Net Aspect-oriented Programming), and here's the Github repo for SNAP - it looks to be a tool that sits on top of Castle DynamicProxy and integrates with your favorite IoC container.
- A white paper from Germany on analyzing models to identify cross-cutting concerns, to best apply AOP when designing an application [PDF]