There’s a lot that goes into file deletion. You can pass many files/folders to delete, follow symlinks if desired, and there’s logic to try to recover from failed deletes with nuances depending on the system platform. The operation seems trivial because the API is simple and hides most of the complexity from the client code / build script.
Behind the scenes, both the
Delete task and the
project.delete() method delegate much of their work to the same classes, such as the
Deleter that does the traversal and deletion. One just provides an API appropriate for a task while the other provides immediate action, more suited for a task action.
Good object oriented design such as single responsibility still applies here. The one job of your tasks / actions should be to convert what makes sense in their context to what is understood by a collaborator that can actually do the work. You may have multiple clients to your code that does the heavy lifting, but this shouldn’t be a bad thing.
When a task executes, it executes one or more actions. The
Delete task has an
Action that takes the task configuration and does the actual execution with it. The
project.delete() method gives you a public API to access the same behavior (just without abusing the
Task implementation details).
There shouldn’t really be duplicated code. Multiple clients with different context calling the same API each have a valid use case that should justify their existence.
You should be able to follow these same principles if you’re implementing custom functionality from scratch.