Friday, June 06, 2008
While I was busy customizing Microsoft's Exception Management Application Block to classify and log all exceptions thrown in our web and Windows apps, and writing instrumentation code that published timing events via System.Diagnostics.Trace, Microsoft was busy writing ASP.NET Health Monitoring. Microsoft has more resources, so their product is a little more advanced and customizable. Here's what it provides:
- An event model: There are event classes for web request failures, for authentication failures, for errors, for SQL errors, for heartbeats, and so forth. You can subclass the WebBaseEvent in order to define your own custom events, as well.
- A provider model: Health monitoring can publish events with 4 built-in providers (email notification, SQL Server, WMI, and event log). The WMI provider is especially interesting, but you will have to write your own application to manage and report WMI events, according to Microsoft.
- A customization model: You can edit web.config in order to map events to providers and to configure providers (for example, to specify a connection string for the SQL Server provider).
Since we have already customized so much infrastructure, especially by writing a bug portal that makes use of the customized Exception Management block, we will probably not be migrating to the ASP.NET Health Monitor any time soon. However, for those of you who have been whistling in the dark with respect to the health of your web applications and services, get busy! I highly recommend Scott Allen's post as a starting place for your efforts.
Recently a friend asked me how you might create a Windows Forms application that only allows a single instance per computer. A print driver might make use of this functionality, for example, to launch a print job management dialog whenever a document prints. Never having needed this sort of functionality before, my initial answer wasn't very helpful. But being both curious and disinclined to back down from a technical challenge, I just had to figure this one out.
As I was looking for an inter-process synchronization mechanism, I came across the Semaphore and Mutex in the System.Threading namespace. A semaphore can be used to manage a pooled resource (memory buffer, thread pool, connection pool, etc.) by tracking the number of available resources. You instantiate a semaphore with an invariant maximum corresponding to the quantity of pooled resource entities (e.g., the number of database connections). Whenever a thread wants to use the resource, it calls .WaitOne() on the appropriate semaphore and blocks until the semaphore count is greater than zero. If the count is positive when the call is made, the thread will not need to block at all.
When a thread enters a semaphore, the semaphore decrements its count by one. The calling thread is responsible for calling the semaphore's .Release() method when it has completed using the resource. This allows the semaphore to increment its count--and as a result, gives another thread access to the pooled resource. You must call Release() inside of a finally block as soon as feasible in your codepath; my testing shows that the CLR will not release an unreleased semaphore when the semaphore reference goes out of scope, or even when the thread of execution terminates.
What we need, then, is a semaphore that has a maximum count of one (since we want only one instance of our application to be running) and will increment its count no matter how the thread that entered it terminates. Happily, this would be a pretty good one-sentence description of the Mutex class. The thread that calls WaitOne on a mutex ("mutual exclusion") gains ownership when it enters the mutex. It can release the mutex at any time by calling the ReleaseMutex method, but should it fail to do so (whether by logic error or run-time failure) before it terminates, the CLR will release the mutex on its behalf. As a result, the mutex should prove more reliable for our purposes.
Here is the singleton code in a nutshell:
using System;
using System.Windows.Forms;
using System.Threading;
namespace MutexTest
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// make sure no other instances of this app are running
bool mutexIsAvailable = false;
Mutex m = null;
try
{
m = new Mutex(true, "MutexTest.Singleton");
mutexIsAvailable = m.WaitOne(1, false); // wait only 1 ms
}
catch (AbandonedMutexException)
{
// don't worry about the abandonment;
// the mutex only guards app instantiation
mutexIsAvailable = true;
}
if (mutexIsAvailable)
{
try
{
Application.Run(new Form1());
}
finally
{
m.ReleaseMutex();
}
}
}
}
}
One of three things can happen when the Main() thread calls m.WaitOne(1, false):
- If the mutex is unowned (or becomes unowned within one millisecond), mutexIsAvailable is true and the thread enters/owns the mutex.
- If the mutex remains owned by another instance of the Windows Form app for the one millisecond duration, mutexIsAvailable is false.
- If the mutex is available because another instance abandoned it without releasing it, the method throws an AbandonedMutexException. In this case, the thread owns the mutex and may safely launch the application instance, so it sets mutexIsAvailable true.
If the Main thread owns the mutex, it runs the application, using a try/finally block in order to guarantee a call to ReleaseMutex. While strictly speaking it is not necessary to call ReleaseMutex (the CLR will do so on the thread's behalf when it terminates), I have written the code this way in order to maintain a best practice. In some other situation, the thread that enters the mutex might continue performing more work (or enter a suspended state) after finishing its use of the resource and might not call ReleaseMutex, so it's a good idea to write the code in this fashion.
What do you think? Is this code helpful? Do you have any suggestions for improvement? Leave a comment!
Tuesday, May 27, 2008
Our shop has been looking for a way to simplify the interaction between our domain layer and data layer. The data layer uses typed datasets for all its operations. When it retrieves data, it populates a dataset; when it stores data, it checks the DataRowState of all rows in the dataset, and calls the appropriate stored procedure to insert, update, or delete the data. The domain layer then uses dataset elements as the in-memory backing store for properties and collections. A collection typically uses a DataTable, for example, and a collection member would use a DataRow in the DataTable.
This arrangement has some advantages:
- Between requests, domain objects can cache their state in session by caching a dataset.
- DataRowState can inform the logic about which CRUD operation to perform on a DataRow. Unmodified data can also be skipped over, yielding improved efficiency.
- We have considerable freedom in designing domain classes. We can make a property read-only, for example, if it corresponds to an immutable database field, such as an identity column.
This arrangement also has a big disadvantage, however. We end up with lots of properties that look like this:
public string Phone
{
get { return dr.PHONE; }
set { dr.PHONE = value; }
}
This property's one and only use is to map a domain attribute (an entity's phone number) to a particular field in a DataRow (dr). Our domain layer has hundreds of these pass-through properties, which are a very verbose and not especially readable way of mapping between the domain and data layers. So we've been looking for a better way to handle this mapping.
Along comes the .NET Entity Framework (EF), which provides a tool that creates a domain-to-data map in XML format. Our first reaction was: this is just what the doctor ordered! And supported by Microsoft, to boot.
On closer examination, though, the EF toolset has some growing up to do before we could consider using it in our web applications. It can generate only public get/set accessors in the entity domain model (EDM) classes, for example. You cannot make a property read-only, or internal/protected/private, or virtual. You cannot map a non-generated property to a database field. And programming in a straitjacket was not what we had in mind for a new approach.
Second, EDM classes generated by EF do not have any supported way to cache their state. A Microsoftie is working on a tool ("Perseus") that can serialize the state of an entity using an EntityBag<T> instance, but it seems somewhat incomplete (and definitely not supported) at the moment. Since our web apps do cache domain entity state, adopting the EF right now would entail an important risk.
What alternatives exist? We can license DevForce EF, which is built on top of the EF and seems to offer pretty much everything that it lacks. Or we can try NHibernate, an open-source .NET port of the Hibernate tool which is quite popular in the Java development world.
Or maybe we can just wait for the EF to mature. Microsoft has big plans for the EF, and intends to make REST-oriented web services, Reporting Services, workflows, etc. EDM-aware. So an EF investment today can yield important dividends in the future.
Even though I cannot render a definitive answer, I hope that this discussion will help readers make an informed discussion about their ORM choices in the .NET world. What do you think? Leave a comment with your insights or questions!
Tuesday, May 13, 2008
You've mastered web forms and controls. You've prototyped a Silverlight 2.0 application. AJAX? You're all over it. But have you really learned how to design a good web page or web site?
Steve Krug's "Common Sense Approach to Web Usability" provides surprising and sometimes counterintuitive principles that every good website must follow. Krug preaches the importance of removing clutter in order to make the purpose and functionality of a site (or page) clear--and happily, he practices what he preaches in this remarkably lucid book. Here are some of Krug's key insights:
- Don't make users think! Your job is to make sure users do not have to puzzle over a site's purpose, or how to use it. Krug offers the search functionality at Amazon.com as a great example of this principle in action. A user does not have to decide what type of search she wants (by author, by title, by ISBN, etc.); instead, she can just enter whatever text interests her, and Amazon offers a list of matches, ranked by relevance.
- Users don't behave the way you think they do. You've been poring over your site--reading everything ten times or more--so you tend to think that users will do the same. But they don't. Instead, the users...
- "don't read pages, they scan them." (In fact you only decided to read this review after you scanned the intro and decided it would be worth your while.)
- "don't figure out how things work, they muddle through."
- Design pages for scanning. Since users are going to treat your site like a billboard going by at 70mph (rather than a textbook that they carefully work through), you should learn to design great billboards!
- Create a clear visual hierarchy. Highlight the important stuff, and indicate relationship by grouping.
- Use conventions. If your site design conforms to what users generally expect, they can more easily understand it at a glance.
- Break pages into clearly defined areas.
- Make what's clickable obvious. Use arrows or underlines to indicate that text is clickable, for example.
- Minimize noise. Prefer clarity to pizzazz.
- Give users simple\mindless choices. It's okay to make a user traverse 4 or 5 links to get to his desired destination as long as each choice along the way is clear.
- "Omit needless words." "Get rid of half the words on each page, then get rid of half of what's left" is Krug's Third Law of Usability. More words just make the site look more daunting, which can discourage the user in a hurry. Krug's Third Law has 2 corollaries:
- Happy talk must die. "We're so glad you're at our site! We think you'll like your experience here..." Oops, you just lost your user, who's too busy to keep reading.
- Instructions must die. Users almost never read them anyway (remember, they don't figure out, they muddle through). So keep instructions brief and simple.
Krug then discusses some details about 2 features every site must have: navigation and a home page. Krug recommends that the sections and subsections of a site be indicated with a clear set of links or tabs on the home page, and that the navigation remain available no matter where the user goes. (This answers the questions: what can I do on this site? and Where can I go from here?) Each page should have a visible name, and the site should a breadcrumb trail with arrows between the levels in order to allow a user to know where he's at in the site's hierarchy. (These answer the questions: where am I at now? and How do I get back to where I was before?).
Krug's discussion of the home page acknowledges that the forces conspiring against simplicity are enormous in any ambitious site, because there are so many organizational interests competing for the valuable home page real estate. Krug provides some useful tips for managing the problems, though, by suggesting how to use logos, taglines, and home page navigation.
Next Krug addresses the often religious arguments that site development teams often endure (pulldowns or menus? Flash animation or simple text?) with this simple advice: forget the arguments and start testing! Simple usability testing will reveal the key problems with a site, and often they have nothing to do with what the development team has been arguing about. Krug believes that frequent tests are more important than comprehensive (often expensive tests), and he offers advice on how to do testing on a tight budget (use 3 or 4 subjects; use an inexpensive screen recorder like Camtasia; try to get all the project stakeholders to observe). He concludes with an extremely useful script of an interaction between a test subject and a test guide.
Those who have already read the first edition will be pleased to know that Krug has included some very helpful new material in the second edition. Is your site accessible to sight-impaired users? If not, Krug offers a top 5 list of tips for making sites accessible, along with a pointer on how to use Cascading Style Sheets to make your site more accessible. Not to mention that CSS makes your site a lot easier to manage.... And what do you do when your boss (or the customer) wants you to do something that violates every known law of web usability? Just compose an email that borrows liberally from one of Krug's friendly "here's how it should be done" missives!
Krug sprinkles his book with examples of sites that work well (and a few that don't) to illustrate his ideas. He often offers a few "How does (or does not) this page implement the principles we've been discussing?" tests, with his own answers on the following pages. I found these examples to be enormously helpful. And Krug offers a wonderful set of additional resources for those who want to pursue the subject further, both within the text and in a notated bibliography at the end.
Because I am a long-time web user and web developer, I thought I understood just about everything I needed to know about usability to design a good site. Then I read this book, and learned a ton. If you work on web sites in any way (whether as designer, developer, or tester), the few hours you spend on Steve Krug's little gem will pay rich dividends.
Thursday, May 08, 2008
This post describes when you should use SQL Server encryption, which type of encryption key to use, and how to create the infrastructure for managing documents whose size exceeds the maximum encryption block size of 8000 bytes. It also summarizes network and operations steps you need to take to make sure your entire infrastructure is reasonably secure.
Tuesday, March 25, 2008
When you are coding in a hurry, it is very tempting to write business logic in the first place that comes to mind, such as a button click handler. However, for all but the simplest systems, such a practice leads very quickly to a chaotic system whose business logic is scattered like the ash from an erupting volcano. Create a great domain model, though, and you will be able to nimbly align your software with your emerging business needs.
Friday, March 07, 2008
Every time I see an example of copy-and-paste programming, I'm like a bull who just spotted a waving red flag. "Don't Repeat Yourself" (DRY) is a principle every programmer should live by, for Turing's sake! Read on for a discussion of why copy-and-paste is egregious, and how to refactor an expansive set of conditional logic branches into a concise and elegant piece of code.
Thursday, March 06, 2008
Dealing with vendor data (or your own) in the form of "codes" can pose significant challenges. You must ensure that your source code remains readable, that data are properly validated, and that data can be displayed as user-friendly descriptions. The built-in solutions (named constants and enums) help, but they have some significant shortcomings. If you derive a class of named constants from the MagicStringTranslator class, though, you can vanquish all 3 challenges in one fell swoop!
Egghead Cafe has kindly published the improved version of my article here. Enjoy!
Wednesday, February 27, 2008
As organizations pass data back and forth, they often use codes to represent the data. For example, a marital status of divorced might be represented as "D", married as "M", and so forth. You have to solve three problems when you are dealing with magic strings:
- When you write logic to handle the data, things can get chaotic on a hurry if you are not careful; the use of literal magic strings in your source code can make it incomprehensible.
- You can get into trouble by passing a string that is not in the set of valid codes as a parameter to a method that is expecting one of the codes. Since the parameter type is typically string, the compiler will not help you detect the error.
- You often have to translate codes into it description so a user of your system will know which data have been gathered.
Using named constants can help make your source code more readable, but you still have more work to do: you must write extra logic to check whether a string belongs to the set of valid codes, and to translate a code into a description that a user can understand. If you declare your named constants in a class that inherits from the MagicStringTranslator class, though, you will get the data validation and the translation for free. Check out the article I wrote for the details!
Friday, February 15, 2008
Just by calling a class' constructor, you are tying your code to some implementation details of the class. Since good software uses loose coupling, though, you should develop the habit of providing a static construction method and hiding a class constructor. There are exceptions that prove the rule, however, as noted both in this article and in the comments. Read on to learn how to develop the good habit, and when you should consider breaking it....
Wednesday, February 13, 2008
Sam Guckenheimer, the group product planner for Microsoft's Visual Studio Team System, has written an excellent book entitled "Software Engineering with Microsoft Visual Studio Team System." The first chapter compares and contrasts Agile methods with the traditional Software Development Lifecycle (SDLC, or waterfall) approach. In this little essay, I summarize Guckenheimer's findings, and sprinkle in some thoughts about how our organization might consider using Agile methods.
Tuesday, February 05, 2008
Have you ever had difficulty translating a set of requirements into a set of tests? Do you find regression testing to be a major bottleneck whenever you implement changes in your system? (Or do you have quality issues because you forgo regression testing?) Does your development team ever dump complex functionality into a "smart UI" that becomes difficult to maintain and extend? If you answered yes to any of these questions, you should check out FIT (the Framework for Integrated Testing).
Monday, January 28, 2008
Recently I discovered a tool that I had needed for a long time. Fiddler, a freeware product created and supported by Microsoftie Eric Lawson, can be used to debug HTTP traffic from any web browser (or client application). Here's how you can use it:
1. View/Analyze HTTP traffic....
2. Generate test scripts....
Saturday, December 15, 2007
I recently encountered a real head-scratcher when trying to perform a SQL query against a service performance log. If you enjoy this kind of challenge, or if you just want to learn a new SQL query strategy, read on.
Thursday, November 08, 2007
A skill that is useful during traffic stops can also help you write correct loop iterations.