2

Is it an acceptable practice to initialize physical/external resources from a constructor when the resource is needed for the object to do it's work?

For instance, let's say I wanted to create an object that proxies a durable message queue and that the message queue is a physical database table.

Would that make sense to create an idempotent constructor which physically create the table if it doesn't exist yet?

E.g.

IMessageQueue queue = new SQLTableMessageQueue('table_name', dataSource);

Perhaps a static factory method would be more appropriate? In that case, the table creation would occur in the factory method and the constructor would be free of such behavior.

IMessageQueue queue = SQLTableMessageQueue.create('table_name', dataSource);

I'm not too sure what would be an appropriate approach? Another idea I had was to use the Repository Pattern.

plalx
  • 379
  • 1
  • 9
  • 1
    While this is somewhat language-agnostic, certain languages have more tolerances for this than others and/or have different ways of approaching this problem (although many of the same problems exist across languages). What language are you using? – J Trana Jan 21 '15 at 01:57
  • @JTrana Well, I'll have to implement this in ColdFusion, a dynamic language where there's no real static members or static classes, but let's just say it's Java. – plalx Jan 21 '15 at 04:54
  • `Constructors must usually be side-effect free` - Impossible, unless you're constructing an empty object. Where did you hear that? – Robert Harvey Jan 21 '15 at 06:41
  • @RobertHarvey I removed that as it was confusing since I chose the wrong words. I meant that for instance, if your class was a `Timer` you wouldn't start it right away when the constructor is called, but even that point is not very important for the question. – plalx Jan 21 '15 at 13:49
  • 1
    @RobertHarvey I think he means they mustn't have *externally observable* side effects, which I agree with. Obviously constructors have internal side effects when they initialize instance fields, but you can't observe them unless you do something remarkably stupid like passing a reference to `this` to another thread before the constructor has finished. – Doval Jan 21 '15 at 14:06

2 Answers2

3

Usually constructors are not used to initialize external resources, there are few reasons,

  1. Testability - It would be very hard to create unit tests
  2. To be in compliance with SRP

You could always pass the message queue to the constructor where you use it.

class QueueProcessor
{
    private IMessageQueue _queue;

    public QueueProcessor(IMessageQueue queue)
    {
        _queue = queue;
    }
}

Yes, you can use a factory to create the queue

class QueueFactory
{
    public IMessageQueue CreateMessageQueue
    {
        return new SQLTableMessageQueue('table_name', dataSource);   
    }
}

With this approach you can easily mock the message queue for testing, and also it does comply with the SRP compared to constructing the queue within the constructor.

Low Flying Pelican
  • 1,602
  • 9
  • 13
  • Well, I do not see how your exemple is different than mine? The creation of the database table still would have to occur in the `SQLTableMessageQueue` constructor. Also, abstracting away the concrete queue class behind a factory isin't as simple as this. Different queue types might require different arguments to be constructed. – plalx Jan 21 '15 at 04:50
  • Difference is in my example, I pass the interface IMessageQueue to the constructor, where you can pass any implementation including a mock object for testing. About the factory, it's the same thing nothing different in my case, if you want to add parameters you can pass it into the factory method. – Low Flying Pelican Jan 21 '15 at 04:55
  • I see that, but that's out of the question's scope and is irrelevant to my question. I haven't even mentionned anything about processing the queue and about the factory, if the goal is to abstract away the concrete class being used, you must make sure that the factory's interface doesn't leak specific concrete class's implementation details. Otherwise, client code will still have to be modified if the concrete class changes within the factory. – plalx Jan 21 '15 at 04:57
  • It's in scope of the question, question is, is it a good idea to initialize external resources. And if you summarize the answer, it says : "No it's not a good idea, you should construct it outside and pass into the constructor." – Low Flying Pelican Jan 21 '15 at 05:08
  • I'm sorry, but you are still misunderstanding the question. My point is, where the SQL table creation code shall go in the stated example. Is it fine to have that resource created when invoking the `SQLTableMessageQueue` constructor or not? If not, what would be more appropriate? – plalx Jan 21 '15 at 13:52
  • Sorry.. from what I read from the question, that's what I understood. When you do invoke the constructor of the SQLTableMessageQueue it's preferable to have database table created, as if there is a failure at that point there is a potential that your application might end up corrupting data, so in such cases sooner you fail the better. So you should create such tables when application starts. – Low Flying Pelican Jan 21 '15 at 14:02
0

Google's C++ Style Guide asks you to refrain from doing work in constructors. Their arguments may or may not be applicable to your language. Testing on the Toilet's six-year-old advice #3 on how to write testable code by not doing work in the constructor still holds though.

If you search for it online you'll find tons, /*Programmers*/ is one place to start.