3

I've recently disputed with my colleague about the following situation:

I've developed a framework that processes the resources (in java, although its not really important). It goes (simplified, pseudo-code) like this:

class Algorithm {
    Processor processor = ...;
    execute() {
        forEach(Resource r : readResourceNamesFromFileSystem()) {
           DomainObject do = convertResourceToDomainObject(r);
           processor.process(do);
        }       
    } 

}

interface Processor {
     process(DomainObject do);
}

Class Algorithm is an entry point to my framework. Resource is a representation of some content in the filesystem (it has methods for reading the data from file and the file name, which is important)

Class DomainObject (declaration is omitted) is a java representation of the content of the file depicted by Resource. DomainObject only has data and doesn't have a filename inside.

Class Processor represents the business logic layer, the DomainObject can be processed, stored in Database and so forth.

The content data is supplied by others, we just know that these files contain the data that can be converted into DomainObject(s) which is a real object we work with in the framework. We store one DomainObject in one file.

Now we argue about the file name. Colleague of mine wants the file name to be propagated into the Processor and potentially to all the layers because its easy to print the logging message/throw an exception that contains a file name if something goes wrong during the processing, or maybe to write the message like "domain object stored in file (here__comes__filename) has been processed successfully".

I see the point of my colleague (convenience) but I'm sure it breaks the design and encapsulation because the processor module shouldn't really be aware of the "origin" of the DomainObject (today we store them in files one DomainObject per file, tomorrow we'll maybe use something else, something that doesn't necessarily has a filename).

I claim that we better catch the exception in the Algorithm.execute method and rethrow the exception with a filename/ log the filename. The log file will be less readable but the encapsulation won't be broken.

In my understanding its a design vs clearness. Could you please share your opinion, who is right, who is wrong? Should I sacrifice the design for the clearness of logs?

BTW I've promised my colleague to ask this question so we'll read the possible answers together :)

Thanks a lot in advance and have a nice day

1
  • 1
    One option would be to add a source property to DomainObject and set it to the filename when loading from a file. This provides the info your colleague wants without breaking encapsulation or leaking the abstraction too much. Commented Jul 9, 2014 at 15:15

2 Answers 2

6

Catch the exception at the level where you do have the file name, incorporate the file name into the error message, and rethrow.

This is a classic example of why exceptions are designed the way they are; they propagate up the call stack to the next available catch clause, where new information can be added to them where it is available. This avoids the need to pollute your classes by propagating logging information throughout your class hierarchy.

Java will even maintain the original stack trace.

The whole point of having things like stream objects is to abstract away details like file names. A stream doesn't care where the data it is streaming comes from, and some data sources don't even have file names associated with them.

8
  • Thanks a lot for an answer. 10 points from me for sure :-) I totally agree with you, but please note,its not only about exceptions, but also logging messages from within the processor. Commented Jul 7, 2014 at 20:34
  • You can still do that as well, right? Commented Jul 7, 2014 at 20:36
  • If there is no exception, than there is no way to know inside the processor class what's the file name is without passing it into context. I think that's the main reason for debate - whether we should pollute the code (design) or keep it clean and live with a situation when the log message doesn't contain the file name Commented Jul 8, 2014 at 4:28
  • You can always throw your own exception, y'know. Commented Jul 8, 2014 at 4:51
  • If we really have an excpetion then I totally agree with you. Yes, of course I can, but I'm talking about the situation when there is no exception. Instead we have a lot of resources to process so throwing exception and interrupting the flow is kind of "expensive" and I think its wrong. Commented Jul 8, 2014 at 4:58
3

If you're using a logging framework like Log4j, you can use a nested diagnostic context (NDC) to store the file name at the point it is available, then retrieve from the NDC at the time you log the messages.

Logj4 NDC

This can be even more useful because you can actually write a log4j appender that handles log messages specially based on the NDC content.

The specific case I used this was an embedded Jetty web server. Parts of the incoming URI identified the customer e.g.

http://domain/app/<customer-name>/otherstuff...

The Jetty request dispatcher extracted the value of "customer-name" from the URI and stored it in the Log4j NDC.

It was almost trivial to write a log4j appender that, when the NDC contained a customer name value, appended the message to a .log file.

That way we had a single coherent log file that contained all the diagnostic information in sequence, plus we had logs of activity relevant (and private) to each customer.

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.