1

In one of my projects, I have this following use case -

I have a variable, that I need to pass around in many methods. Business logic and object creation in those methods are dependent on that variable. It can be the case I have object creation inside a constructor of another class. For those, I am also propagating this variable so that nested object creation can use it.

This way method contract is very clear. Anyone can look at the method and readily know that is the information that this method is working with. But this leads to a messy propagation of the variable in many places across the codebase. Depending on the variation of the use case, sometimes it has to be stored as a field in many classes.

Another alternative is to use ThreadLocal. Where this variable state can be kept. It's clean and easier to implement. The application processing unit is single-threaded, so thread safety is not an issue.

But the problem is, it affects the clarity of the methods that will be using it.

What is the recommended approach in this kind of scenario?

5
  • When you use ThreadLocal with a private static variable, each thread gets its own copy of that variable that works independently from the other threads. Is this what you want? If you don't need this behavior, you might simply prefer an ordinary static variable. Jan 9, 2020 at 3:55
  • 3
    Note that there will be many, many people that will tell you that using a static variable in this way is a bad idea, but if you want simplicity, this is one way to accomplish it, if you're careful. For what it's worth, it's probably better to just pass around the state that you want to share using ordinary class methods. Jan 9, 2020 at 3:56
  • @RobertHarvey, yes the state is per request thread, not common to every thread.
    – shakhawat
    Jan 9, 2020 at 4:31
  • 1
    The ThreadLocal variable you're talking about is really a global variable. If the application is single-threaded, then there's not even a reason to put it in a ThreadLocal, you could just make it a static variable. But: Global variables are bad. They cause hard to understand spaghetti code and make your code hard to test. Why does this variable need to be passed everywhere? The fact that you need this is a hint that you should rethink the design.
    – Jesper
    Jan 9, 2020 at 14:44
  • 1
    @Jesper Thanks for your input. I corrected the point that Application is Single Threaded. The application is not single-threaded, the processing unit is. So I can't use static. The reason for passing it around is I need it to create certain type of objects. So basically whenever I have to create those objects I need to pass it.
    – shakhawat
    Jan 10, 2020 at 2:51

1 Answer 1

1

I would recommend against thread local storage. That bypasses the normal rules around object lifetime (how long it exists) and scope (where it can be seen). It will potentially lead to very hard to debug situations, for example when your code runs into an exception and there is stale data in the thread context. Also, I am not certain there is a promise for your call to be on the same thread for it's lifetime. I think the promise is that there is no concurrency, but you may be switched threads. I might be wrong. Just something to consider, that would also be tricky to debug.

Personally I prefer to pay the price and have all inputs declared on the method signature(s). This is in the spirit of honest methods (a concept borrowed from functional languages)

Have you reviewed the code for opportunities to remove the dependency from some classes entirely? It's a warning sign that so many classes would have to have knowledge of that one thing. Often, the dependency can be removed altogether by changing the responsibility of the classes. Sometimes, the code paths needing the one thing can be refactored out of the classes.

public class DoTheThing
{
    DoTheThing(ILogger logger)
    {
        logger.LogTrace("Constructor called");
    }
}
public class DoTheOtherThing
{
    DoTheOtherThing(Action<string> OnMessage)
    {
        OnMessage("Constructor called");
    }
}

Action is a C# way of expressing a function pointer (not a Java guy :) ). So what happened here in DoTheOtherThing is we removed the knowledge of ILogger from the class. It's now the responsibility of the caller to provide a function to express what needs to be done to log a message.

A dependency injection framework may have a facility to create instances on a defined scope. In the context of a web application, this can be the call context. I found that a good way to concentrate touching said call context in a single location.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.