Posts tagged with 'CI'
Since I'm a professional blogger now, I decided that I need to use a tool with a bit more functionality than a standard TinyMCE or CKEditor box.
I decided that Markdown was the way to go, so I installed MarkdownPad 2 (choco install markdownpad2). This worked fine for a bit, but there are a couple of issues:
- In order to embed images and preview them, I had to actually put them on a public dropbox folder and use the public dropbox URLs
- Embedding code is just a copy and paste. I can't reference another file and import the code. This means I have to manually update my md file whenever I tweak code samples.
- I had to install Awesomium in order to use MarkdownPad 2's preview feature (why?!)
THERE ARE PROBABLY SOLUTIONS to these gripes.
But what I've found is that I like the AsciiDoc format as much as Markdown, and I like AsciiDocFX way better than MarkdownPad 2.
Embed images
In markdown, what I did was put images into a public dropbox folder, and link to the public URLs. This felt darn hacky, but I couldn't figure out how to get it to point to local files (at least not in MarkdownPad 2).
With Asciidoc, I simply specify a local folder with a metadata tag: :imagesdir: images - and that tells AsciidocFX to look for images in that subfolder.
To include an image then, I just use image::filename.png[alt text goes here]. And that does it.
Import code from source files
This is a great feature that I wish I had when I was writing my book. To include a source code file right in your document, just use include::path/to/sourcecode.cs.
That will include the entire file in your document. If you just want part of a file, you can add a comment with "tags" in it. In C#, for example:
// tag::Example1[] public void MyCode() { } // end::Example1[]
And then, back in AsciiDoc, use include::path/to/sourcecode.cs[tags=Example1]. Now only the code that sits between those comments will appear in the document.
This is such a great feature, because I'm always tweaking code up until the last minute before I publish. Now I don't have to worry about the blog post getting out of sync with the actual code!
Awesomium
Not needed for AsciiDocFX. So, even if you decide to stay with Markdown, AsciiDocFX still seems like the superior tool to me.
Conclusion
I'm sure there is much more to learn about AsciiDocFX and Markdown, but I'm pretty convinced at this point. I'm going to start using AsciiDocFX for blogging (and, heaven forbid, if I write another book).
One of my core motivations for using AOP is that it can bring the single responsibility principle to places that would otherwise be difficult or impossible without AOP.
To review, here's the single responsibility principle in a nutshell:
A class should have one, and only one, reason to change.
Why is this a good principle? I think that the ObjectMentor white paper on SRP [PDF] sums it up very nicely, but basically if you have multiple concerns in a single class, those concerns become tangled together. This isn't a huge problem until you need to make a change (which never happens in software, right?). If I want to change responsibility A, I now have to involve the code for responsibilities A and B (and C and D, etc). All these responsibilities are coupled. If I make a change, I could break the class in multiple ways, affecting every one of the coupled concerns (unless I have a good suite of unit tests, which is unlikely if I have a very coupled set of concerns).
To avoid coupling, a good rule of thumb that I use is to describe what a class does in one sentence. If I have to use the word "and", then it's probably doing too much, and should be split into 2 or more classes.
Examples:
- PersonRepository: this class persists person objects to a database. Check! There's no "and", so this class is only doing one thing.
- BillPayService: this class submits transactions to the payment processor and stores payment history in an audit database. Bzzt! It's doing two things. Maybe I should consider a PaymentProcessorService and a PaymentHistoryRepository refactor.
- AccountController: this class routes the user to the appropriate account views (and logs any invalid request errors). I'll stop belaboring the point and leave this an an exercise to the reader.
I've been trying on and off to figure out Mono.Cecil, and so far it's not very encouraging. It's a bit above my pay grade, it seems.
But all is not lost: I came across a tool while browsing NuGet called FireWeaver. It sits on top of Mono.Cecil, which means it does its work after compilation. It provides you with a way to replace a class with an entire other class. So it's not exactly intercepting or proxying classes, the way other AOP frameworks do: it flat out replaces it and is "essentially duct typing(sic) the entire object definition". I don't know if that's supposed to be "duct taping" or "duck typing", but I rather like the term "duct typing".
Here's a quick example of how it works, taken from the FireWeaver CodePlex site. First, I added FireWeaver with NuGet. Then I created a console app like this:
Compile and run as normal and here's the output:
Next, run the FireWeaver.Bootstrapper.exe tool against your assembly/assemblies. In my case, my Replace class is in the same assembly as the class it's replacing, so my arguments are identical, but you could certainly specify another assembly as the second argument:
And here's the output of the console app after I ran FireWeaver.
And here's what the assemblies look like (decompiled) before and after FireWeaver. Warning, your head may explode:
I'm just as confused about Cecil looking at these JustDecompile screenshots as I was before. But I assure you, it does work.
There's definitely some potential here, since this is a pretty easy tool to use, and integrating FireWeaver into your build script(s) shouldn't be too difficult if you don't want to hit the command line after every build. And it almost looks like pure duck typing brought to C#.
But this could also lead to some really wild code if you aren't careful with it. "Dogs and cats living together, mass hysteria" code.
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.
Recently I was made aware of another AOP tool for .NET that uses a post-compile step to do the weaving (similar to PostSharp). SheepAspect appears to use the Mono.Cecil library, which is a powerful utility to work with CIL assemblies. I mentioned SheepAspect in an earlier post, and I thought it deserved a closer look.
SheepAspect is available via NuGet, so it's an easy install. Here's a 'Hello, World' aspect in a console app that I threw together:
It's a somewhat unfamiliar approach to me, being used to PostSharp.
- To define an aspect, create a class and put the [Aspect] attribute on it. So far so good.
- You don't use attributes to apply the aspect to your code. Notice that MyClass and DoStuff are not decorated with any attributes.
- Instead, you define a pointcut by creating an empty "marker" method (MyPointcut in the above example), and placing a selector attribute on that. The one I'm using is SelectMethods, but there are others available.
- The string in that SelectMethods attribute is called SheepAop Query Language (SAQL).
- The advice goes into the InterceptMethod method, which returns an object and gets an MethodJointPoint (yes MethodJointPoint, not MethodJoinPoint, that's not a typo). MethodJointPoint is very similar to DynamicProxy's IIntercept or PostSharp's MethodInterceptionArgs, in that it gives you a context to work with.
- I put an "Around" attribute on this method to specify that I want this advice to surround the pointcut, and I specified the pointcut with the string.
Compile and run, and here's the output:
After using SheepAspect in this admittedly trivial way, I do think it has some potential, but it also feels like a project that's in its very early stages and is a little rough around the edges still.
- SAQL is a very interesting way to select pointcuts, and based on the SAQL documentation that I've read, it can be very powerful. This is a double-edged sword though: this query language is specific to SheepAspect, so you'll have to spend some time learning it to get the most use out of it.
- SAQL queries are just strings, so refactoring/renaming could be problematic. Perhaps if you are coming from an AspectJ environment, this would not be as difficult, since that's what SheepAspect seems to modeled on. A Linq provider would be tremendous, but that might be very ambitious, if not impossible.
- The fact that SheepAspects are only connected to your regular code by SAQL is also an interesting approach: your pre-compile source code goes completely untouched, which is nice and clean, but it could also be hard to keep track of what aspects are being applied where.
- Finally, while there is some good documentation, it looks like some of it has yet to be written, which indicates to me that it's still very much a work in progress.
I can't say I'd recommend using SheepAspect over more mature and supported tools like PostSharp or Castle DynamicProxy, but it might be worth a look for specialized usage in low risk situations. In the future, who knows; it could develop into a very popular tool.