Skip to first unread message

Илья Фофанов

unread,
Mar 18, 2014, 12:24:49 AM3/18/14
to clean-code...@googlegroups.com
In one of the first episodes, Uncle Bob did touch the problem of logging, but very briefly.
I don't remember exactly, but Uncle Bob offered in that episode to make logging by spawning special logger classes which inherits from normal classes.
Typical logging approach is to create a Logger instance and invoke everywhere where it needed logger.Error("Some text about error"), logger.Trace("") and so on.
Sometimes, for unfortune, it is required to do comprehensive logging.
The problem with that is that the code starts to look ugly, crammed by all those logger invokations amidst code.

It would be great to discuss this problem for more details.

Bartosz Borowik

unread,
Mar 18, 2014, 5:45:04 PM3/18/14
to clean-code...@googlegroups.com
My usual approach is to define a separate logger interfaces for every object that needs logging. And then let some implementations of this interfaces be injected into those objects. The objects use then logging methods defined on its logger's interface instead of reaching directly to some sort of logger.
Let's say you have a RentABookUseCase which needs to log some information. Let it be book_not_found, book_reserved_by_someone_else and book_successfully_rent.
Then you would have an interface RentABookUseCaseLogger which would define 3 methods:
logBookNotFound(BookTitle, BookAuthor)
logBookReservedBySomeoneElse(Book)
logBookSuccessfullyRent(Book, DateTime)
Your RentABookUseCase would simply call one of these methods on some logger object injected into it and this logger object would take care of properly building log messages from the given parameters.
My usual approach is to have each of the logger implementation classes typically implement more than one such interface, so I have logger methods concerning similar topic in one place. 

Vlad GURDIGA

unread,
Mar 19, 2014, 5:09:03 AM3/19/14
to clean-code...@googlegroups.com
One approach that I have found useful is the one described by Mark Trostler in his “Testable JavaScript” talk. The idea is to extend the class you’re trying to do logging for.

Say I have an AuthenticationService class. To keep it clean, I implement LoggedAuthenticationService that overrides the methods I want to add logging to, with ones that only call the overrode ones, and also do some logging before and after them. If you find yourself needing to do logging in more than before and after, this may be a sign that your method is too big.

James Green

unread,
Mar 19, 2014, 5:28:08 AM3/19/14
to clean-code...@googlegroups.com
I might argue that logging is in fact merely a technician's audit trail.

We have no problems accepting that during a financial transaction we must record activity. Why then do we have problems recording technical progress within our software? Perhaps the two are in fact much the same, it's just that an accountant want to watch financial value, whereas marketing wants to watch behaviour and technical wants to watch data.

Logging comes across as a temporary matter. We often put logging in to trace execution. We then do not want a log file polluted by tracing we are no longer interested in. The act of logging is usually no longer expensive in memory or CPU time but can be when writing to disk. Same then as recording other activities...

Perhaps this is why many companies adopt log aggregation and filtering technologies. Because logging is considered essential within our classes, even if you don't think you need it right now.



--
The only way to go fast is to go well.
---
You received this message because you are subscribed to the Google Groups "Clean Code Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discu...@googlegroups.com.
To post to this group, send email to clean-code...@googlegroups.com.
Visit this group at http://groups.google.com/group/clean-code-discussion.

Илья Фофанов

unread,
Mar 20, 2014, 12:27:10 AM3/20/14
to clean-code...@googlegroups.com
I understand that you want to separate the responsibilities. But it still doesn't make much sense to me, because 1) this will not reduce the amount of code, actually it will be a blow of the code base (not so huge, but it will be a bit :) ), 2) all those invokations still reside amidst the business-classes, so the code stays a bit ugly 3) it's quiet predictable that nobody ever will need to make his own implementation of the extracted interface. If so, why we have to do all this "overstaff"?

Илья Фофанов

unread,
Mar 20, 2014, 12:29:27 AM3/20/14
to clean-code...@googlegroups.com
Can you give an example (maybe it will be sufficient to give it in pseudo-code)?

Ben Biddington

unread,
Mar 20, 2014, 12:35:36 AM3/20/14
to clean-code...@googlegroups.com

How about running off notifications?

Logger listens for events and does as it pleases.

--

Vlad GURDIGA

unread,
Mar 20, 2014, 4:44:54 AM3/20/14
to clean-code...@googlegroups.com
Sure! Here is a JS example:

https://github.com/gurdiga/xo/tree/master/app/authentication-service

I have the AuthenticationService interface, then one of its implementations is FirebaseAuthenticationService which doesn’t contain any logging code. Very soon after developing FirebaseAuthenticationService I felt the need to add some logging to it. Then I remembered that talk I’ve mentioned and implemented LoggedAuthenticationService.

The trick here is that because both these classes implement AuthenticationService interface, whenever I need logging I can wrap the FirebaseAuthenticationService instance into a LoggedAuthenticationService instance without the production code to see the difference.

For example, in my main partition I have this:

XO.authenticationService = new XO.FirebaseAuthenticationService(XO.Firebase.SimpleLogin);

and when I want to enable logging for authentication, I will just add this new line after the previous:

XO.authenticationService = new XO.LoggedAuthenticationService(XO.authenticationService);

With this approach I have the code that does the actual work—in this case¹ FirebaseAuthenticationService—separated from logging code², which I find makes easier to understand and change each of them, or swap any of them with some other implementation without any other of the collaborating pieces to be disturbed.

¹ or any other implementation of AuthenticationService
² or any other additional behaviour, like benchmarking



--
The only way to go fast is to go well.
---
You received this message because you are subscribed to a topic in the Google Groups "Clean Code Discussion" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clean-code-discussion/5_WO9TQSgvw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clean-code-discu...@googlegroups.com.

Vlad GURDIGA

unread,
Mar 20, 2014, 5:00:25 AM3/20/14
to clean-code...@googlegroups.com

On Thursday, March 20, 2014 6:27:10 AM UTC+2, Илья Фофанов wrote:
I understand that you want to separate the responsibilities. But it still doesn't make much sense to me, because 1) this will not reduce the amount of code, actually it will be a blow of the code base (not so huge, but it will be a bit :) ),

The point is not to have less code: it’s to have it organised in a manageable way.
 
2) all those invokations still reside amidst the business-classes, so the code stays a bit ugly

The my example in the other response shows a way to separate them. In my case it’s JS code, but I guess a similar approach could be employed for other languages too.
 
3) it's quiet predictable that nobody ever will need to make his own implementation of the extracted interface. If so, why we have to do all this "overstaff"?

I think the talk suggests that programming to interfaces makes it more resilient to changes in the long term by keeping the concerns separate. But n the end it greatly depends on the specific project’s needs. “Context is the king.” ;)

Wim Deblauwe

unread,
Mar 20, 2014, 6:23:28 AM3/20/14
to clean-code...@googlegroups.com
In Java, you can use AspectJ to do this. See example: http://stackoverflow.com/questions/8839077/how-to-use-aop-with-aspectj-for-logging

That said, there are some drawbacks to using AspectJ, notably, the tooling is not yet up to par (e.g. IntelliJ support, code coverage support, ...)

regards,

Wim


--
The only way to go fast is to go well.
---
You received this message because you are subscribed to the Google Groups "Clean Code Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discu...@googlegroups.com.

daniphp

unread,
Mar 22, 2014, 6:01:28 AM3/22/14
to clean-code...@googlegroups.com
In PHP you can use Traits and in Ruby mixins (multiple inheritance concept).
In Java or any language  you could use the same dependency injection like you do with db connections. 

witali mik

unread,
Mar 24, 2014, 12:07:48 PM3/24/14
to clean-code...@googlegroups.com
i personally use the logger inside my controllers but not inside my interactors, since my controllers know the request and response of my interactors i have all required informations to log. currently i didnt had any usecase where logging is required inside my business logic
Reply all
Reply to author
Forward
0 new messages