Posts tagged with 'c'
My new employer is Heuristic Solutions, and I am starting as the Software Solutions Lead today.
(I blurred the phone numbers and email address to avoid spam, but if you want to know what they are, just contact me).
Heuristic Solutions made me an offer that was just too good to turn down. We are a very small consulting firm, but also a product company. Heuristic Solutions is the company behind Learning Builder, a leading online credentialing management platform. However, I won't be on the product team. Instead, I'm coming on to help grow the consulting practice. In my view, a consultant company that also builds and sells a product (or a product company that also has a consulting practice, depending on how you look at it) is in a very strong position. I won't go into it too much, but imagine the talent that you can develop and attract when you can offer experience in a variety of technologies and industries, and then apply that experienced talent to your own product. And, more practically, think about the diversification of revenue sources.
Anyway, the opportunity to lead the consulting practice for a company positioned like Heuristic is positioned is just something that I couldn't say no to. I'll still be working remotely (though probably travelling a bit more than I was with Zimbra). Just like when I started with Telligent, I'm a little scared! I have some pretty ambitious goals for myself and for Heuristic, and I've left one of the best jobs of my career to take on a whole bunch of new responsibilities and risks.
However, it's a challenge that I think I'm ready for. I'll be a coworker with the inimitable Seth Petry-Johnson (though he's on the product side), and after extensive talks with founder Christopher Butcher, I'm very happy about the Heuristic philosophy and the direction that he wants to take Heuristic.
(I'm even fond of the company name: Heuristic Solutions. In software, there is no silver bullet that solves everything; there is a instead a series of heuristics that usually represent the optimal course of action. These heuristics almost never become "laws", and always remain open to augmentation.)
Over three years ago in August 2010, my life changed drastically. I was working as a consultant for a consultant company that I like (and still like), with team members that I like (and still like), but for a project and client that I haaaaaaaated. I was miserable, and even my wife could tell. Though some good things eventually came out of my experience on that project, I couldn't wait to move on to a new client.
However, that time never came. Jim Holmes tweeted that his employer (at the time) was hiring a developer for a remote work position. I had some reservations at the time about working from home, but I figured...why not? I'll try something that really scares me. After a rigorous interview process with Jayme Davis, Josh Ledgard, and many others (Did I mention Rob Howard, founding member of Microsoft's original ASP.NET team?), they let me become part of the Telligent Analytics product development team.
Yes, Telligent. TELLIGENT. Not Telerik. Telerik is a different software company that makes very different products. Jim Holmes worked for Telligent then, but he works for Telerik now (belay that, he just left Telerik and is moving on to something else). Yes, I realize that makes it more confusing.
The twin frontiers of working from home and working on a product team were very challenging. Keeping up with a team of really sharp developers like Scott Watermasysk, Kevin Cunningham, Jose Lema, and others was difficult, but rewarding. I learned a lot, and I helped to ship some products. I got to work with Jim Holmes(!), and a great QA team including Miles Dunn. I annoyed Michael Monteleone, Wyatt Preul, and Ben Tiedt on a regular basis. I could list a dozen more awesome employees of Telligent (past and present) that I got to work with.
I also had a major life event while working from home: two broken shoulders caused by a major seizure. Telligent was incredibly accomodating, and if I weren't already working from home, my life could have been affected a whole lot worse.
Telligent eventually merged with (purchased) Zimbra from VMWare, and took their name.
This opened up a whole lot of amazing possibilities with email, database technologies, integration, and analytics. I got the opportunity to present a session at The Big Social, which is the annual Telligent/Zimbra conference. I helped to ship a major new release of the Analytics product--version 4.0, which was rebuilt entirely to take advantage of the Zimbra Community platform.
I got to work on a code base where I had plenty of input on design decisions, and I got to work with support helping customers on a regular basis.
I could absolutely see myself retiring as a Zimbra employee. Everyone I've worked with at Zimbra has been sharp, kind, professional, and if you are reading this blog post now wondering if you should apply to work there: yes, you should.
However, another opportunity presented itself that I just couldn't say no to. More on that next.
No Weekly Concerns this week, but don't worry: it'll be back next friday.
In the last post, I laid out the bare essentials of an error handling aspect for my service layer.
Before I proceed further with the aspect, let's examine the layer right above the service layer: the UI layer. I'm using ASP.NET MVC.
With ASP.NET MVC, there is a concept of ModelState, which holds information about validations performed during model binding, and is also used by the controller to convey error information to the view (through the Html.ValidationSummary helper, for instance). I'm already using ModelState to convey simple validation errors; I'd like to use it to convey any errors that the service layer might encounter. There are many ways to approach this; I've chosen the "callback" approach--passing a lambda to the service layer in order to communicate error information from the service layer up to the UI layer. Here's the basics:
Dependency injection gives me an object that implements the ITerritoryService interface, but I have to take one more step and pass that service the lambda x => ModelState.AddModelError("", x) in the controller instructor. This is because ModelState doesn't actually get instantiated until the controller does (so I can't pass it to the service object any sooner).
Now, when there's an exception in Territory service, I can simply use this "callback" to add an error to the ModelState. (Side note: a benefit to this approach is that it does not couple TerritoryService to my UI: if I wanted to use this service with another UI--say, WebAPI or WebForms--then I would simply have to pass in a different lambda).
Let's get the aspect to use that callback.
By using args.Instance, we can get a reference to the object in which the method resides. If that object can be cast to ITerritoryService, then we can simply call AddModelError. This works great: now anytime there's an exception in TerritoryService, it will be added as an error to ModelState and displayed to the user.
But clearly there are still issues here:
- This only works for ITerritoryService--what about the other services?
- Swallowing exceptions: we should at least be logging the exception, not just ignoring it.
- If the method has a return type, then it's returning null. If it's meant to return a reference type, that's probably fine, but what if it's returning a value type?
- What if it's returning a collection, and the UI assumes that it will get an empty collection instead of a null reference?
- Do we really want to show the exception message to the user?
Next time, we'll start addressing the first issue, and figure out a way to make this aspect more generic.
I've written a lot of AOP demos, given a lot of presentations on it (AOP For You and Me and The Class That Knew Too Much), and I even wrote a book about AOP in .NET. These aspects are all great places to start, but I thought I would take it a little deeper in a blog post series, detailing a real aspect I'm using in a real project, how I built it, and the reasoning behind the decisions I make. Because this is a much more practical example, this aspect is not generally applicable. You can't just drop it in to your project without tailoring it a bit. (If you are interested in those types of aspects, PostSharp has custom design patterns, ready for you to use today).
I'm only going to show you the basics of the aspect right now, and I'll build it up and add to it as this blog post series goes along. Note that this is an active project, and therefore it's still a work in progress. Part of the reason I'm doing this series is to help me get some real feedback!
My goal with this aspect is add error handling to my service layer. This service layer sits between my UI layer (an ASP.NET MVC application) and my data layer (which uses Dapper on a SQL Server database). When this aspect is done, it should:
- Catch exceptions
- Log (most) exceptions
- Ensure that a useful/helpful/friendly error message is given to the UI, instead of bubbling up the exception
- Make sure the service method returns something useful, if it's meant to return something
As an aspect, then, I can apply this to every public service method so that I don't have to worry about writing it over and over, and I don't have to worry about forgetting to add it to new service methods.
Let's start easy with a basic shell of an aspect:
I'm using MethodInterceptionAspect. I guess I could use OnMethodBoundaryAspect instead (or even OnExceptionAspect), since most of the code I'm going to write is going to end up being in that "catch" block. But let's just stick with this for now, and consider changing later (because of how PostSharp's API is structured, I know that this won't be very difficult).
Notice that there are two attributes on this aspect.
- [Serializable] - this is required by PostSharp, since PostSharp instantiates and serializes aspects at compile time.
- [MulticastAttributeUsage] - this is me telling PostSharp that I want to be able to multicast this aspect to public methods (see Aspects.cs below)
As it stands right now, this is not a good aspect, since it will just be swallowing all the exceptions. But it's as good as place to start as any, especially if you aren't familiar with AOP/PostSharp.
I'll also create another file in my project called Aspects.cs, which will contain assemly attributes so that I can apply this aspect to every method in the namespace where I put all my services.
I put an AspectPriority of "10" on it because I actually have another aspect in my project that I use to manage SQL transactions that has a priority of "20". I want the exception handling aspect to be the highest priority (lowest number).
Make sure you understand what's going on here before continuing. If not, you may want to review those presentations I linked to, check out the PostSharp documentation, or maybe check out my PostSharp Live webinar series.
Welcome to another "Weekly Concerns". This is a post-a-week series of interesting links, relevant to programming and programmers. You can check out previous Weekly Concerns posts in the archive.
- Part 2 of using PostSharp to implement Undo/Redo. You will not believe how easy it is.
- There's also a Part 3 of using PostSharp to implement Undo/Redo.
- And guess what, there's a Part 4 of using PostSharp to implement Undo/Redo.
- I submitted something from "Look Around You" to the Moviecode tumblr, and it's in BASIC.
- I've heard from multiple sources now that SVG icons are becoming a trend. Check out geomicons.
- In my web development class at Capital University, a guest lecturer (Jon Plante) asked the students to go through an exercise of trying to name the website after taking away all the text and graphics. Dedesign the Web is just like that.
If you have an interesting link that you'd like to see in Weekly Concerns, leave a comment or contact me.