Design your classes for their consumer

I’m going to describe a methodology that will help you save time by writing better classes, and will help simplify your life by allowing you to solve problems with a top-down approach.

Developers such as myself often have a tendency to just focus on the class we’re currently working on. Of course I believe this is a good thing, because we all know the importance of focus. However, you should never forget the reason you’re actually writing that class. It is because other code will be consuming it.

Consumer-Approach

There have been far too many instances where I would figure out which pieces I needed to build, and then build each one, from the bottom up. The problem is that I would write the class in the most short-sighted and easiest way possible, which is usually not the best way to use it.

Now, when there is a question of what a class interface should look like, I ask myself what it should look like to make the life of the consumer as easy as possible.

Sometimes we can even take code usability to an extreme. For example, Fluent interfaces, which allow you to chain together multiple calls. In many instances, this makes the code much easier to call, potentially at the expense of making the called code more complicated.

I’ve come up with a simple example to help illustrate. Suppose I need to process a list of x,y coordinates. Here are a couple of potential signatures:

ProcessData(double[] xData, double[] yData); ProcessData(PointF[] points); ProcessData(IDictionary<double, double> points);

For now, just ignore the performance implications (they’re going to be linear in this case, or close to it anyway). To choose the correct signature, we need to know who the caller is.

Of course there is a good chance that we’ll have a slight intentional leaky abstraction. In the previous example, we may have been able to use the IEnumerable generic to be more flexible. That’s a topic for another day.

Thankfully, this problem is minimized, although not always eliminated when you follow the single responsibility principle. The better you can follow that principle, the simpler each piece will be. That tends to minimize the potential for the consumer to need the interface to look different than it would naturally be.

Another way to look at your classes from the consumers point of view is to practice test-driven development. In fact, I see this as one of the strongest arguments for test driven design. For each layer in your code, you’re creating code by consuming it before writing it. Every layer acts as an API to the layer above it.

In conclusion, I’m simply recommending that you don’t lose sight of why you’re writing that piece of code. You’re not just writing code for the sake of writing code, you’re writing it to be used!

ASP.NET Changing Session ID’s for each request

I ran into an issue where ASP.NET was changing the Session.SessionId for every request from the same user. A quick Google search revealed 2.3 million pages. I’ll summarize one of the main reasons this can happen, and discuss 2 ways to fix it.

Hand-Counting

I’ve been working on a search function for a website I’m working on. We’re taking the Lean software approach and implementing an extremely basic search for now. We’re going to track the searches that users are making, and will have the data we’ll need to make a better search in the next version.

In order to know if users are making multiple searches, we’re storing the ASP.NET session ID with the search record in the database. Much to my dismay, every search request resulted in a different value in Session.SessionId.

The problem lies in the fact that ASP.NET is trying to be extremely efficient storing sessions for users. If ASP.NET doesn’t have a reason to remember who you are, it won’t. If you think about it, that can save a tremendous amount of work by avoiding session management.

If you want to tell ASP.NET that you want it to track user sessions, you can do one of 2 things:

Store something in the session. If you store something in the users session, ASP.NET will be forced to associate that data with your current visit. Example code:
Session["foo"] = "bar";

Simply by handling the Session_Start event in your Global.asax. The presence of this method will tell ASP.NET to track sessions, even if there is no data in the session.
public void Session_Start(object sender, EventArgs e)
{
}

How to get the best customer service for free

Today’s tip is a hack for getting awesome tech support from a company for a product that you may or may not have purchased. It may not be polite, but it may be a method of last resort.

Helpful-Crowd

We all knows what happens if you buy a product and then call for support. If you’re lucky, you get put on hold. If you’re unlucky, you’ve called outside of their business hours of 1am to 3am. When you do talk to someone, you’re treated like an idiot (in their defense, it’s a learned behavior).

If you want great service, call their sales department. Tell them you’re evaluating their product, but ran into an issue. You’ll be talking to someone that actually wants your business. They’re typically very helpful, and remind us of the benefit of good customer service.

Just today a coworker sent me a link (unrelated site) that had a link to a page called "Pre-Sales Questions". They’re openly distinguishing between potential customers, and paying customers. The problem is that they make the pre-sales question form easy to use, but the paying customer form is not. Customer service is in a bad state.

My official recommendation is to to fully try out their product during a trial, so that when do you do talk to their sales team, they can at least earn a sale from it. Like I said, this is a method of last resort.

Programming for someone with blinders

One of your goals as a developer should be to make your code as readable as possible, both for yourself, and for the other developers you work with.

Horse with Blinders

One great way to determine if your code is well written, is to ask yourself if the code you’re writing is readable by itself. Another developer should be able to jump into a module, and have a fairly easy time seeing what’s going on. They shouldn’t have to sift through thousands of lines of interweaved code to figure out what’s going on.

Of course, what I’m talking about is simply a test for the single responsibility principle. If you’ve written a huge "do it all" class with thousands of lines of code, you’re ensuring that you’re the only one that will be able to maintain it. That that type of code usually suffers from high coupling to the other modules in the program.

I used to organize code into classes based on the type of functionality being provided. I used them more as containers for related functionality. At the time, I didn’t see a reason to split it apart. I was very wrong.

In a recent article by Jimmy Bogard, he walks through creating classes with a separation of concerns. In the conclusion is my favorite part:

Now we have many more classes (4 vs. 1) and interfaces (3 vs. 0).  For those who don’t like more classes, GET OVER IT.

That is an excellent point. Why should you be afraid of creating more classes and interfaces? It’s really not more code to write, in fact, it’s often less. Refactoring tools remove many of the obstacles of maintaining the interface, class, and method structure

When someone looks at your code and you have 4 classes instead of 1, and those classes are very specific and short enough to process by our tiny brains, it will be much easier to maintain and modify (or even better, extend).

Locking sessions for multi-threaded access

I recently ran into a situation where I needed to upload some small files from a Flex client application to an ASP.NET web server. I decided to store the uploaded files in the users session while they were in the checkout process. Once the user confirms their order, the images are read from the session and stored to the database.

Here is the original code from the page that accepts each uploaded file, and adds it to a Dictionary in the collection:

if (Session[SESSION_ORDER_FILES] == null)
{
        //Our dictionary hasn’t been created, so we do it now
        files = new Dictionary<string, byte[]>();
        Session[SESSION_ORDER_FILES] = files;
}
else
{
        //The dictionary has already been created, just load it
        files = (Dictionary<string , byte[]>) Session[SESSION_ORDER_FILES];
}

//If we have the "_clearPrevious" flag, that means all
//of the files should be removed from this users session
if (_clearPrevious)
        files.Clear();

//If the file name is the same, replace it
if (files.ContainsKey(_fileName))
        files.Remove(_fileName);

files.Add(_fileName, bytes);

The problem is that we ended up with missing images. The client was sending them, but when the user confirmed their order they were missing images in the session. Since ASP.NET will process page requests in multiple threads, the session can be accessed in multiple threads!

Now, we need to find a way to lock them. I questioned whether ASP.NET would give me the same session object each time, or a new instance representing the same session. I whipped up this code in a test page. It saves the previous session reference to the session. I know it’s a little strange, but since no serialization happens with the session, it gave me a good way to know if the previous session object and the current session object were the same instance.

const string SESS_SESS = "test";
var currSessionObj = Session[SESS_SESS];

if(currSessionObj == null)
        //First page load
        Session[SESS_SESS] = Session;
else
        lblText.Text = (Session[SESS_SESS] == Session).ToString();

The result of this page was false. That means you most certainly do get a new session instance each time. Keep in mind that I’m not saying it’s a different session, the object you’re accessing the session with simply changes.

What does this mean?

This means that you have to be careful when there is a chance that you’re working with session objects in multiple pages, or in a page that could be accessed multiple times simultaneously. Thankfully, there are only a few real-world scenarios where this would be a large concern.

As with any other kind of multi-threaded code, be careful if you’re checking the session, and then performing an action based on the result. In that case, you’ll need to lock a global object that is available to all threads that could access that code. Here is an example:

lock(Global.SessionLock)
{
        if(Session["foo"] == null)
                Session["foo"] = new Bar();
}

In your Global class, you’ll need this field:

static object SessionLock = new object();


You are viewing a mobilized version of this site...
View original page here

Mobilized by Mowser Mowser