1

Let's assume that I have a piece of functionality in my application which is responsible for adding a deleted marker file .deleted in a directory that is considered to be deleted.

What would be that best way to implement this? Static function or an object with a single method that conveys this functionality? Those are my 2 options (my language isn't functional):

class MarkAsDeletedDir {
  void apply(File directory) {
    directory.addChild(".deleted");
  }
}

Usage: new MarkAsDeletedDir().apply(dir)

or

class AppUtils {
  // other stuff
  // ...

  static void markAsDeletedDir(File directory) {
    directory.addChild(".deleted");
  }

}

Usage: AppUtils.markAsDeletedDir(dir)

Assume no performance overhead in creating new objects such as the former.

  • Simple rule of thumb I use: static functions should have no side effects. Creating a file is a side effect, so don't make it static. Also, consider having MarkAsDeletedDir implement an interface or inherit from abstract class so it can be mocked if necessary. – David Arno Oct 31 '17 at 12:04
  • Don't you have any "FileManager" class that handle stuff for your applications files transparently ? I would put it there. Though in my case I never delete/Rename the file, I just delete the entry in my file table. Furthermore, static methods can be an hidrance when you want to mock it for unit testing. – Walfrat Oct 31 '17 at 13:57
  • I personally do not like static methods, they don't fit into OOP, they tend to bi from big to huge, very often it's introduced as a hidden dependency, hence low cohesion. Here is an elaboration on that: medium.com/@wrong.about/… – Vadim Samokhin Oct 31 '17 at 17:52
  • FWIW, while I have created many, many util methods that were just going to perform the 1 action so I threw it into util; it turns out that I don't think any of them ever ended up remaining that way. At a minimum, there always seems to be the converse operation. e.g. 'undelete'. Most of the time adding that one piece of functionality sparks a flurry of related ideas and that utility method ends up getting pushed into a class with related operations. Save yourself some time and heartache and create a MyCurProjFileUtils class or something like that. Don't put it in AppUtils. – Dunk Oct 31 '17 at 19:11
3

The problem you're facing is not exactly what people would define as primitive obsession, but I consider it to be very close.

So, are there other file/directory-related operations in your system?

If so, you can create your own File/Directory class, wrapping the standard class and providing your own operations on top.

The point is: Instead of thinking about making a util method (static) our a util class (MarkAsDeletedDir), you can just create a method on the File itself, such as yourOwnFile.markAsDeleted().

| improve this answer | |
  • That could be a solution but the project already uses the inherent File class which is also passed into many other dependency classes and refactoring the code would take a substantial amount of effort. – Konstantine Oct 31 '17 at 12:26
  • @MichelHeinrich is right. However, considering the constraint you mention in your comment, I would say go with the latter: static util method. However, if more methods like this appear, consider refactoring to the approach suggested in this answer. – Vladimir Stokic Oct 31 '17 at 13:43
  • @VladimirStokic Not supported in every language, but extension methods kind of bridge this gap. They appear to be instance methods, but are actually static behind the scenes. Useful when you do not want to extend or modify an existing class. – Mike Oct 31 '17 at 18:03
1

Static methods with side effects are problematic, because they cannot be mocked for unit testing. So I would recommend a regular class.

| improve this answer | |
  • 1
    While I agree and know of the problem you mention, that is such a cookie cutter argument about static methods and I feel it doesn't really apply when working on big, non-scientific, impossible-to-apply-best-practices projects that I chose to bypass it for this use case – Konstantine Oct 31 '17 at 16:55
  • @Konstantine: "Best practices" is a rather nebulous term.The question is if you want to able to unit-test or not. – JacquesB Oct 31 '17 at 17:16
0

I personally don't like static methods. There are lots of reasons for that, but since you question is about a specific piece of code, I'm more inclined to the first option, but in such cases I usually use a decorator. Of course it depends on how your File interface looks like, and in case it's thin, the implementation could look like that:

interface File
{
    public function contents();
}

class Directory implements File
{
    public function contents()
    {
        return exec('ls -la');
    }
}

class DeletedDirectory implements File
{
    private $file;

    public function __construct(File $file)
    {
        $this->file = $file;
    }

    public function contents()
    {
        $this->file->addChild('.deleted');

        return $this->file->contents();
    }
}

Of course it's not an overkill or silver bullet, it's just one of the multiple ways to solve a problem. This particular solution could or could not match your exact needs, since any pattern is just a form and not an essence.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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