1

I have made an application that deals with collections of images. Currently it has a REST api to add/remove images, create/clear/delete collections and a worker that can automatically fetch images from sources.

I want to make a CLI application to execute some tasks. An example of a task would be to clear a collection, delete a collection etc but also to create/clear the database and also run the worker.

Since the REST api and the CLI have some common functionality, I am thinking to abstract the functionality in tasks (eg AddImageTask, ClearCollectionTask). The worker will also have a task, FetchImagesTask.

Now, the issue is logging. For debug stuff, I think it's ok to implement inside the task. But for some long running tasks like the worker task, I want some in between logging (search for images -> 'Found N images', download image -> 'downloading n/N images', etc). I don't find that appropriate to be used by the REST api.

The worker task would probably not be executed by the REST api but some other long running tasks maybe would.

My solution to this is to have the REST api call the tasks directly and the CLI to wrap the tasks using commands.

So, for a simple command like CreateCollectionCommand:

public void execute() {
    new CreateCollectionTask(...).execute();
    log("Created collection");
}

and for long running tasks like FetchImagesTask:

public void execute() {
    var task = new FetchImagesTask(...);
    task.onSearchResults(results -> print(...));
    task.onDownloadImage((index, total) -> print(...));
    task.execute();
    log("Added N new images to collection");
}

My questions are:

  1. Is the command pattern appropriate for logging stuff? I read somewhere that it shouldn't change the state of the UI.
  2. Some commands will require a database connection, where would be the correct place for the connection code? Inside the execute method? In some other init method? Or maybe as a constructor dependency? The last options seems the most complicated to me but also the most clean.
  3. Could I just scrape all this and have the REST api and the CLI both just execute the tasks? Are some logging statements in the REST api a big deal?

I should say that I am aiming for as clean design as I can, as this probably will be a very big project and will take a long time. I don't want to have to refactor it much later but I am open to suggestions since this my first time making something this big and I intend to learn from it.

1

I am not sure I understood all the details of what you are trying to accomplish, but it seems dependency injection is pretty much the solution you are looking for:

  • you sometimes need logging, sometimes not: so inject an abstract "logger" here (maybe a callback function, maybe an object), and let the tasks or commands call this logger wherever it could be useful. When you don't need any logging, inject a logger with empty implementations. If you need logging to the console or to a file, inject a logger which does exactly this. For example, in your REST context, an empty logger or file logger could be injected, in your CLI context, a command line logger could be injected, whatever serves you best.

  • same for the database connection: if your REST api requires a DB connection, and your CLI a different one, inject a database context (through some abstract interface) from outside. For making a decision about where the connection should be initialized, one has to know your system better than me, but the tasks are most probably the wrong place for this. This can also be used for unit testing purposes, by providing a "mock" db context.

| improve this answer | |
  • I was thinking of a more general callback instead of a logger, because maybe later I could wrap the tasks in some kind of desktop gui instead of cli and the values would be needed to update some sort of progress bar. As for the database, I just think the command as something that gets mapped to a command line input and isn't the connecting to database a part of the command? In my cli, I have an option - database <config>, which gets converted to a configuration POJO and passed as dependency to the command. The connection can fail, so I view it as part of the commands responsibility to handle – alexk745 Sep 26 '19 at 8:14
  • "I was thinking of a more general callback instead of a logger" - fine, then go ahead, design an even more general interface. My suggestion about the principle to solve your issues by using dependency injection stays the same.... – Doc Brown Sep 26 '19 at 8:23
  • ... and to your comment about the DB connection: just make sure you have an "inner" function which can get the DB context from outside and holds the business logic, and which can be reused in your REST as well as your CLI context, and one or more "outer" parts which create the DB connection whereever it makes most sense. Then reuse the "inner" function from both sides. What you call a "task" or "command" is up to you, that is not the important part of my recommendation. – Doc Brown Sep 26 '19 at 8:28
  • I think I understand, thank you very much! – alexk745 Sep 26 '19 at 8:31

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.