> On Apr 28, 2016, at 8:13 AM, Phillip Lord <[email protected]> wrote:
> 
> Marshall Pierce <[email protected]> writes:
> 
>> The job of slf4j-api is just to be the developer-side interface to logging. 
>> It
>> purposely delegates the decision of what to do with those logs to the end
>> user. I think it is a mistake to include policy mechanisms like these into 
>> the
>> API.
>> 
>> If you’re writing a library, don’t include a binding. If you’re writing a
>> tool, select a binding.
> 
> I do not understand this distinction. I have some software which can provides
> an interactive shell that I can use directly (i.e. a tool) or which can
> be used as a dependency by downstream applications (i.e. a library).
> Conclusion I should select a binding, and not include one.

Ah, well, it is a bit subtle, but it is there. Maybe it will be easier to draw 
parallels from a different language. Suppose you are writing yourself a figlet 
clone (phiglet, perhaps?) in C with the goal of being embeddable into other 
programs.

As a polite C library author, you allow your users to specify their own 
malloc() implementation: some people will want jemalloc, others will want their 
own custom arena allocator, etc. 

However, you also want to provide a /usr/bin/phiglet executable in addition to 
/usr/lib/libphiglet.so so that people can use your new, fancy, ascii-art-text 
capabilities. Let’s brush aside for the moment that executables and shared 
objects have different file formats (a distinction that doesn’t exist for the 
JVM). In the phiglet executable, you need to make decisions about allocators 
and such things. In libphiglet.so, you need to *not* make those decisions. If 
you wanted both to exist in the same file, you would need to do some runtime 
histrionics to do the right thing (setting the malloc impl, or not) depending 
on how it was invoked.

You have some requirements:
- Provide a library for use in other projects
- Provide a command-line (or whatever) tool that is usable stand-alone

Is it also a requirement that these both be resident in literally the same 
artifact? If so, you have a problem (and a very unusual requirement). If you 
provide more detail on how you expect your software to be consumed as a library 
and as a tool, perhaps we can find a solution that doesn’t involve classpath 
wizardry at runtime.

>> It is an error to not include a binding, and that’s why it prints to
>> stderr. If you’re writing a tool and you want silence, use nop. If
>> you’re not writing a tool, it’s not your decision.
> 
> I am writing both.

Yes, but it’s probably not the case that they must live in the same artifact. 

>> Regarding slf4j-silent / slf4j-strict: This is just another “policy via
>> classpath” mechanism. If you want to control the output of calls made via
>> slf4j-api, we already have a mechanism for this. What happens when both are 
>> on
>> the classpath? As a new user to SLF4J, would you really enjoy learning how to
>> use dependency excludes as a debugging tool during your “why won’t my logging
>> show up” journey rather than having a clear error message that informs you
>> that you’re doing it wrong, and pointing you towards the URL with more info?
> 
> Indeed. But, as a non-user of SLF4J would you really enjoy learning
> about how to turn off an error message for a library that you are not
> using, but which any of your transitive dependencies has chosen to use?

You ARE using it, because your transitive dependencies use it. If you choose to 
approach transitive dependencies as “less real” than your explicitly specified 
dependencies, you are going to have a sad time.

> In fact, given the approach above, all you would need is to change your
> advice: use slf4j-api when developing, but deploy your artifacts with
> slf4j-silent. The hello world default case would behave as now. In
> practice, I think, most library developers will need to use a different
> dev dependency environment anyway (with logging on) and during
> deployment (with logging off).

No, now all your users would need to exclude the slf4j-silent dependency or 
risk confusing silence when logging isn’t working. That is a very bad outcome.

In library development, running the library consists of running tests (where 
logging can be easily configured by adding a test-only dependency) or running 
other standalone programs that use the library (where, again, configuring 
logging is trivial and completely separate from the library). In what sense are 
you “running a library during development” that is not one of those cases?

>> This complicates logging, and the debugging thereof, without a clear gain.
> 
> The clear gain is that the SLF4J is not going to printing error messages
> to people who have not deliberately chosen to use it. I can understand,
> of course, why it might prefer the needs of its users over those who are
> not. But, it doesn't take too much googling to find quite a few people
> asking "where is this error message coming from, and what is SLF4J”.

You HAVE deliberately chosen to use it by using software that uses it.

>> The fundamental issue is that you’re trying to use the same artifact as both 
>> a
>> library and an end-user tool (which I’ll define as “a thing with a main 
>> method
>> or equivalent”). This is an antipattern because there are conflicting goals
>> for libraries and tools, as you’ve correctly identified. 
> 
> I'm writing in Clojure -- so all things have a main method. Also true of
> scala, groovy, javascript and, indeed, Java from 1.9 onwards with
> jshell. So, not an antipattern at all, just business as usual.
> 
> The JVM is a big ecosystem; bigger than Java.

Yes it is, but we disagree about its antipattern-ness: libraries and standalone 
tools have different responsibilities. Just because it’s possible doesn’t mean 
it’s a good idea. (It’s quite possible to do in Java, FWIW: just shove some 
main methods in various classes in your library. I’ve seen it more often than I 
would wish.) If you want to have both types of usage coexist in the exact same 
artifact, be prepared for sadness and complexity.

>> If your users will consume your code in two different ways, then it is
>> sensible to have two different artifacts.
> 
> 
> Well, by this argument, SLF4J is being consumed in two different ways.
> In which case, it should have two different artifacts. This seems, to
> me, a more sensible approach than suggesting that all downstream
> dependencies of SLF4J should have a "thing-with-slf4j-api" and
> "thing-with-slf4j-nop" artifacts.

I’m not sure what you mean here. There already ARE two parts to slf4j: the api 
and the set of different bindings.

_______________________________________________
slf4j-user mailing list
[email protected]
http://mailman.qos.ch/mailman/listinfo/slf4j-user

Reply via email to