I thought about this a little more in the context of avoiding Logger becoming a kitchen sink.
This is today already a mini-leak in toward kitchen sink-ness due to the (good IMO) addition of the printf APIs. The way I see it, if I am a 'classic' programmer, I will not use the fluent API, and vice-versa, if I am a fluent programmer, I'll use the fluent API and not the standard API. So why should both crowd the same interface. In fact why should all THREE (fluent, standard, and printf) be in the same interface. I like the LogManager.get<Style>Logger approach proposed earlier. If I am a fluent programmer, then I call getFluentLogger() and I get a clean fluent API sans extra stuff. If I am a classic programmer, then I call getLogger() and I get a clean standard API sans extra fluent stuff. Whether or not we want a getPrintfLogger() I know not yet, but I think it worth mentioning. Logger can even implement toFluentLogger(), toLogger() and toPrintfLogger(). Having separate interfaces lets you have your fluent API without crowding the standard API. Thoughts, Gary On Mon, Jul 29, 2013 at 7:57 PM, Remko Popma <[email protected]> wrote: > It is unfortunate that you've already put a lot of work into this. > For me, I am firmly in the "don't do this" camp. (Sorry Nick) > > I think a fluent interface would add unnecessary complexity that does not > add any value. > We currently have a single method call that does a bunch of work. > IMO, splitting up that work to make it "look fluent" is not what fluent is > about. Fluent is more than just a coding style, it should simplify and > remove clutter. > > The canonical example uses fluent correctly, *to reduce complexity*: > {code} > > private void makeNormal(Customer customer) { > Order o1 = new Order(); > customer.addOrder(o1); > OrderLine line1 = new OrderLine(6, Product.find("TAL")); > o1.addLine(line1); > OrderLine line2 = new OrderLine(5, Product.find("HPK")); > o1.addLine(line2); > OrderLine line3 = new OrderLine(3, Product.find("LGV")); > o1.addLine(line3); > line2.setSkippable(true); > o1.setRush(true); > } > > {code} > > After: > {code} > > private void makeFluent(Customer customer) { > customer.newOrder() > .with(6, "TAL") > .with(5, "HPK").skippable() > .with(3, "LGV") > .priorityRush(); > > } > {code} > > > In the above example a fluent interface adds value because it allows many > objects to cooperate and it removes clutter. > But I would argue that we don't have any clutter that needs removing. > > Remko > > ------------------------------ > *From:* Nick Williams <[email protected]> > > *To:* Log4J Developers List <[email protected]> > *Sent:* Tuesday, July 30, 2013 8:08 AM > > *Subject:* Re: LOG4J2-242 (Fluent Logging) > > Well that's unfortunate. I just finished it. :-( Haven't committed it > yet... > > I'm not sure what the advantage is to delaying it to 2.1. Is it just to > study it further? I understand "do it" and "don't do it," but I don't > understand "do it later." > > I've heard a few "I don't like it fluent" and "I didn't understand how > it's better" assertions, and I think that's missing the point. I don't have > a particular fondness for fluent APIs, but some people use a different > programming style and prefer them. Just because person A doesn't like or > understand how fluent is better, doesn't mean that person B doesn't like or > understand how fluent is better. Person B might like fluent so much they > write their own logging API wrapper around ours. Person B might not be able > to wrap their head around non-fluent APIs for one reason or another. > > Is there a major difference between these two lines of code? > > logger.error("This is a message with {} arguments {}.", arg1, arg2, > throwable); > logger.error().message("This is a message with {} > arguments{}.").arguments(arg1, arg2).exception(throwable); > > No, no real difference. However, I /can/ see how it's more obvious that > throwable is an /exception/ and not an /argument to the message/. And while > I would probably, personally, use the first line, I can certainly > understand how someone might prefer the second line. > > We're not talking about changing the existing API methods. We're talking > about adding API methods to support this different style of programming > that some people prefer. If, after all, our goal is to further adoption of > Log4j, wouldn't it make sense to offer something like this that many people > use, even if we ourselves aren't familiar with it or don't prefer it? > > My $0.02. > > N > > On Jul 29, 2013, at 5:52 PM, Paul Benedict wrote: > > Whoever said this is a 2.1 feature, I concur. > > > On Mon, Jul 29, 2013 at 5:45 PM, Ralph Goers > <[email protected]>wrote: > > I actually started to work on this myself several weeks ago and came to > the conclusion that I just couldn't grasp how it is better - with one > exception. You can reuse the MessageBuilder and replace the message or > arguments, etc. But that seems dangerous as it wouldn't be thread safe. > > Ralph > > On Jul 29, 2013, at 1:48 PM, Gary Gregory wrote: > > On Mon, Jul 29, 2013 at 4:39 PM, Nick Williams < > [email protected]> wrote: > > I'm working on LOG4J2-242 to add the ability to log fluently. It's going > to work something like this: > > interface Logger: > + MessageBuilder trace(); > + MessageBuilder debug(); > + MessageBuilder info(); > + MessageBuilder warn(); > + MessageBuilder error(); > + MessageBuilder fatal(); > + MessageBuilder log(Level); > > + interface MessageBuilder: > message(String); > message(Object); > message(String, Object...); > marker(Marker); > exception(Throwable); > argument(Object); > arguments(Object...); > log(); > > Bruce (the requester) had suggested adding the methods that return > MessageBuilder to a different interface (as opposed to Logger) to keep from > cluttering the Logger API. The way I see it our options are: > > - Create a FluentLogger interface to house these methods. I don't like > this option because A) it complicates things significantly, B) it makes > users have to call a different method on LogManager (getFluentLogger) to > get a FluentLogger, and C) it means users have to have a Logger and a > FluentLogger if they want to use both APIs. > > - Create a FluentLogger interface that extends Logger. This option is much > better. It avoids cluttering the Logger API if that's all someone wants to > use, it doesn't require someone to have a Logger and FluentLogger if they > want to use both APIs, and it doesn't complicate the implementation > significantly (all implementations can just implement FluentLogger). It > does still mean LogManager (and related classes/interfaces) need getLogger > and getFluentLogger methods, which I don't necessarily like. > > - Just add these methods to Logger, which is what I intended to do from > the get-go and is what I still think is the best option. > > > - and there's option 4: Don't do it. > > At first glance, adding these methods to Logger looks confusing and > cluttered. The less messy solution seems to me FLogger extends Logger. > > Gary > > > > I'm going to proceed with #3 for now, but if someone has a strong opinion > otherwise please voice it so that we can discuss before I complete this. > > Nick > --------------------------------------------------------------------- > To unsubscribe, e-mail: [email protected] > For additional commands, e-mail: [email protected] > > > > > -- > E-Mail: [email protected] | [email protected] > Java Persistence with Hibernate, Second > Edition<http://www.manning.com/bauer3/> > JUnit in Action, Second Edition <http://www.manning.com/tahchiev/> > Spring Batch in Action <http://www.manning.com/templier/> > Blog: http://garygregory.wordpress.com > Home: http://garygregory.com/ > Tweet! http://twitter.com/GaryGregory > > > > > > -- > Cheers, > Paul > > > > > -- E-Mail: [email protected] | [email protected] Java Persistence with Hibernate, Second Edition<http://www.manning.com/bauer3/> JUnit in Action, Second Edition <http://www.manning.com/tahchiev/> Spring Batch in Action <http://www.manning.com/templier/> Blog: http://garygregory.wordpress.com Home: http://garygregory.com/ Tweet! http://twitter.com/GaryGregory
