Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I am looking to understand the pros and cons of centralizing all applications logs into separate files with AOP (e.g. with AspectJ).
Logging is know for being a cross-cutting concern. However, I have never met anyone that centralized all logs into a single or bunch of files. Therefore, I'm left wondering why.
What would be some of the pros and cons of doing it?
I am looking to understand the pros and cons of centralizing all
applications logs into separate files with AOP (e.g. with AspectJ).
I will be using the terms AOP and AspectJ interchangeably. Notwithstanding, AOP is the paradigm and AspectJ implements it, just like OOP and Java.
The benefits of centralizing cross-cutting concerns (CCC) into their own modules (e.g., aspect) using AOP are similar to those of modularization concerns with OOP. Those benefits are described in the literature in papers and books such as:
Aspect-Oriented Programming
Towards a Common Reference Architecture for Aspect-Oriented Modeling
Impact of aspect-oriented programming on software development efficiency and design quality: an empirical study.
AspectJ in Action: Enterprise AOP with Spring
and many others. One can summarize some of those benefits as follows:
reduces code duplication; Instead of having a functionality (e.g., logging) duplicated in several different places, one has it in a single aspect. That functionality can then be applied to those several places using the concept of pointcut;
reduces the coupling between domain-related and crosscutting-related concerns (i.e., separation of concerns); For instance, removing the logging from the domain code follows the single-responsibility principle;
the enhancing of code reusability; Because of the aforementioned separation of concerns, one (for instance) increases the reusability of the modules encapsulating the based code and the modules encapsulating the logging;
dealing with code tangling and scattering issues; as illustrated in the image below
Instead of having logging 1 and 2 tangled directly with the domain-code, duplicated and scattered across separate modules (i.e., Class A and Class B), we have those logging-related functionality encapsulated into one aspect.
There are in the literature some papers about the benefit of AOP regarding the modularization of cross-cutting concerns such as logging namely:
S. Canditt and M. Gunter. Aspect oriented logging in a real-world
system. In First AOSD Workshop on Aspects, Components, and Patterns
for Infrastructure Software (AOSD-2002), March 2002.
The downsides of AOP that one can read in the literature are those typical of a learning/integrating a new technology, namely:
Hiring skilled programmers
Following an adoption path to ensure that you don’t risk the project by overextending yourself
Modifying the build and other development processes
Dealing with the availability of tools
Other downsides reported by papers such as:
An exploratory study of the effect of aspect-oriented programming on maintainability
Using aspect-orientation in industrial projects: appreciated or damned?
Using and reusing aspects in aspectj.
A Case Study Implementing Features Using AspectJ (this one is particularly good a show-casing some of issues with using AOP
can be summarize to:
having to learn a new paradigm;
lack of tool support;
the performance of the weaving;
making it harder to reason about the code, since the CCC related code was moved elsewhere. The same argument can be applied to subclassing or the use of the decorated pattern for instance. However, IDEs mitigates those problems, in the case of AspectJ by showing the joinpoints that are being intercepted. Another solution is for instance to use annotations and intercept those annotations:
#Logging
public void some_method(){...}
When the programmer looks at the annotation immediately knows that that method is being intercepted by a pointcut. The downside of this approach is that you kind mixing again the CCCs with the domain code, albeit just in a form of an annotation.
On the other hand one can argue that since the domain-related concerns and CCCs are now encapsulated in different modules it is easier to reason about them in isolation.
Pointcut fragility; This problem is similar to the fragile base class problem. From source one can read:
changes to the base-code can lead to join points incorrectly falling
in or out of the scope of pointcuts.
For instance, adding new methods, or changing their signature might cause pointcuts to intercept them or stop intercepting them. There are techniques to mitigate such problems. However, in my option the solution is tooling. When one renames a method in Java one expects the IDE to safely apply those changes.
the granularity of the joinpoint module. With AspectJ (even worse with Spring AOP) it might be difficult to get local context necessary for the logging, for instance local variables, which might force you to refactor your code so that you can expose the desired joinpoints -- known in requirements engineering as scaffolding. On the other side, refactoring your code might actually improve it. From: "21. Why can't AspectJ pick out local variables (or array elements or ...)?" one can read:
Users have sometimes wanted AspectJ to pick out many more join points,
including method-local field access, array-element access, loop iteration, method parameter evaluation
Most of these have turned out not to make sense, for a variety of
reasons: it is not a commonly-understood unit for Java programmers
there are very few use-cases for advice on the join point
a seemingly-insignificant change to the underlying program causes a
change in the join point
pointcuts can't really distinguish the join point in question
the join point would differ too much for different implementations of
AspectJ, or would only be implementable in one way
We prefer to be very conservative in the join point model for the
language, so a new join point would have to be useful, sensible, and
implementable. The most promising of the new join points proposed are
for exception throws clauses and for synchronized blocks.
You need to evaluate if in your context it pay-off adding an extra layer (i.e., transversal modularization) into your code base; and also evaluate against alternative approaches such as code-generators, frameworks or design patterns.
In the case of the logging some of the aforementioned issues are not as problematic because if things go wrong... well you just lose or add some logging.
Opinion base part
Logging is know for being a cross-cutting concern. However, I have never met anyone that centralized all logs into a single or bunch of files. Therefore, I'm left wondering why.
Is separation of concerns a bad practice?! (unless you take it to the extreme no). I would definitely say that is not a bad practice, is it worth?! well that is more complex and context depended.
I personally hate to see a beautiful snippet of code mixed with logging functionality. IMO given that software has to deal with so many other variables than just the code per si, such as tight deadlines, not having logging mixed with base code seems to not have a higher priority.
Related
I'm currently working on a project that i need to use Aspectj in it. In the documentation , for every aspect i wrote, i need to explain what were the reasons for using this aspect and not just write the code in the main program.
In generally, i only think about reasons like code-reusing, or flexibility (meaning the program can deal without this aspect, but the aspect will make the program more effective, like check things that maybe do some trouble in the future for example), but i think it is not enough.
While searching for more reasons, i saw that many programmers wrote "cross cutting" - what is the meaning of this and why its so important reason?
EDIT:
This question was asked during my school days, when aspects were something not so common in the projects. Now, 3 years after that, and a lot of backend programming in Java (Spring) I can answer to myself with simple example: the Repository aspect - This annotation(#repository) is used on Java classes which directly access the database.For example, when an exception occurs in the class there is a handler for that exception and there is no need to add a try catch block. It doesn't restrict to particular Class, doesn't care about the domain logic, it's to all of the Classes that want to interact with databases - this is a cross cutting problem.
Cross cutting, in my eyes, is mainly to have separation of concerns, i.e. you can separate the code that handles e.g. technical things (like e.g. logging, authorization, transactions etc.) from code that handles field of domain things.
But why and when is this useful?
It is especially useful if your development organisation also separates theses things, i.e. if some developers are responsible for field of domain programming and others for technical layers.
So different persons can write their code in different places, not disturbing each other.
If the same persons write the different aspects it may still be useful to have this separation of concerns, but it is not that urgent in this case, at least not so urgent, that you want to mess with AspectJ, which introduces some additional complexity.
I am trying to have an annotation #FeatureDependent be used on methods to signal that the method requires certain things to be enabled in order for it to work. And I was wondering if it was possible to have a method called everytime a method with #FeatureDependent was called which would check if the criteria were met for the method to be called.
It sounds like you are describing Aspect Oriented Programming (AOI). This technique allows you to address "cross-cutting" concerns, tasks like logging, security, and transaction management which tend to affect many methods in the same manner. Your use case sounds like it would be a good fit for AOP.
There are two common approaches to AOP. The first mechanism is to create objects in a container (e.g. a Spring container). The container can then scan the class, detect any advice that needs to be applied, and apply the advice via dynamic proxies (Googling Spring and AOP is a good place to start with this). The downside is that your components will need to be constructed by a container so it makes sense for larger components.
The second approach is an extra compilation step (sometimes done at compilation, sometimes done as a separate compilation phase, and sometimes done by a weaving class loader) to wire in the additional methods. This is typically called "weaving" and AspectJ is a common library to look into for this.
Both approaches will allow you to apply "advice" (code run before and after a method invocation) based on annotations on an object. Explaining either in more detail would be beyond the scope of a SO answer but I hope it can get you started.
I should warn that AOP has gotten a bit of a reputation for complicating the flow of an application and tending to be difficult to understand and debug. As a result it has declined in popularity lately.
Another approach is to use something like Servlet Filters, basically a single choke point for all requests and workflows where you can apply various logging & security mechanisms. Such an approach tends to be a little easier to understand and involve a bit less "black magic".
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 4 years ago.
Improve this question
I find my self writing again and again the same programming patterns in many new projects.
I have been thinking about creating my own reusable library of typical implementations of such patterns -not trying to cover all possible design patterns, but only them that experience has shown that it makes sense to put such typical implementations in a library (e.g., adapter, factory, etc ...)- but before I would like to know if there is not an existing library for this purpose already available for Java?.
I know that it is very difficult to completely generalize programming patterns in a way that they could be reused across different implementations with complex requirements (e.g., composition of patterns, classes participating in more than one pattern, etc ...). However, most of the time the pattern instantiations I need are quite simple and standard, and in many situations the implementation work could be sped up a bit with the use of such a library.
Thanks for your feedback.!
Design pattern are just... patterns. They aren't classes ready to use for anyone, but common concepts found across several projects. That's why you won't find a Design Pattern API.
This is precisely the reason why I created PerfectJPattern. Just make sure to check out and understand the code examples. They are available for download as well as in the site documentation pages for each of the Pattern implementations. If you read the GoF book, then you will understand the examples more easily.
For instance, if you want to use the Composite Pattern in your code, and if you use PerfectJPattern you only need to specify which interface (generic parameter and class instance) you would like to use as Composite and the rest is provided to you, see PerfectJPattern Composite. At the bottom of that page, a working example is provided that shows how to accomplish that.
Another aspect you should also take into account, is that in PerfectJPattern you do not necessarily need to reuse the generic Pattern implementations (e.g. perfectjpattern-core Maven submodule), you also do have the choice to only reuse the pure abstract level (perfectjpattern-api Maven submodule) and provide the implementation yourself. In PerfectJPattern you have the flexibility of reuse at different levels of abstraction since there is a fine-grained layered design reflected also in the Maven project structure. Reusing the perfectjpattern-api gives you an abstract template guideline if you wish, that will help you speed up your own Design Pattern implementations. However, ideally you should reuse as much as possible.
Update: following up on a comment below, it is worth noting that not all Patterns can be fully compotentized see From Patterns to Components. Some Patterns can be only partially componentized and some others not at all like the case of the Singleton. The Singleton depends too much on the context and that's why you can only find an interface in PerfectJPattern. However in PerfectJPattern the following Patterns are fully componentized e.g. Observer, Command, Adapter, Decorator, Composite, Proxy, Visitor, DAO, etc.
I disagree with the other answers that no reuseable implementations can be created for design patterns. However, it might not always be straightforward, and involves a lot of abstract programming.
Coming from C# I was missing the simplicity of the observer pattern in Java. (events in C#) After finishing a reusable generic observer for Java I came across the PerfectJPattern library.
It might be worthwhile to check it out.
A componentized pattern is in essence a context-independent, reusable
and type-safe variation of the original pattern that covers at least
as many use-cases as the original pattern and that does not require
developers to re-implement the same boilerplate code in every
different context. Design Patterns are reusable in terms of design,
componentized patterns are reusable in terms of design and code.
Kudos for wanting to reduce any form of duplication possible. "Don't repeat yourself" is one of the most important principles in programming.
As some extra arguments design patterns can be centralized in a library I give you some further examples:
Lazy initialization in C#.
Entire LINQ is based on IEnumerable.
Java's attempt at a reusable Observer pattern. (I didn't say all are good.)
Several patterns integrated in the Spring framework.
As in Pangea's answer: Java JT framework.
What you are looking for is PerfectJPattern.
Checkout dp4j. It allows you to implement the Singleton pattern with #Singleton and lazy initialize it with #Singleton(lazy=true). It is a "collection of reusable componentized Design Patterns implemented in Java".
For the Singleton recommend dp4j. To implement a Singleton you annotate your class with #Singleton and to lazy initialize it you annotate with #Singleton(lazy=true).
If you find yourself repeating similar code in multiple projects, it might be a good idea to extract the portions that are repeated into a library of reusable code in hopes of avoiding repeating yourself in the future.
This is unlikely to lead to fully general reusable implementations of design patterns.
JT Design Pattern Framework for Java/j2EE
A lot of the patterns are built into the Java SE - you may not notice.
Decorator is all over the java.io package.
The java.sql package is AbstractFactory.
All the wrapper classes are Flyweights.
I stand with those who say don't look for a pattern library. They should be discovered as you write your code.
It is possible in a languange which offers higher order functions and some other stuff. Here are some slides which references a paper which discusses 'the origami pattern' library. It shows 'library code' for the following patterns: Composite, Iterator, Visitor, Builder. So if you want to try that out on the jvm you can today, just use scala. http://www.slideshare.net/remeniuk/algebraic-data-types-and-origami-patterns
Do you see a forest or trees?
Design patterns should become apparent rather than be selected up front. By the time they become apparent, you don't need the pattern because the code exists. Then you marvel at how the solution solved itself and your brain subconciously selected the right approach. It gives you that warm fuzzy "i trust that code" feeling.
If you build a design pattern library, you have built yourself a big hammer (or hammer factory, or hammer factory factory [1]) and everything becomes a convenient nail (including screws) resulting in lots of sore thumbs and bowls of spaghetti in your development team.
[1] http://discuss.joelonsoftware.com/default.asp?joel.3.219431.12
Whilst there are many good examples on this forum that contain examples of coupling and cohesion, I am struggling to apply it to my code fully. I can identify parts in my code that may need changing. Would any Java experts be able to take a look at my code and explain to me what aspects are good and bad. I don't mind changing it myself at all. It's just that many people seem to disagree with each other and I'm finding it hard to actually understand what principles to follow...
First, I'd like to say that the primary reason you get such varying answers is that this really does become an art over time. Many of the opinions you get don't boil down to a hard fast rule or fact, more it comes down to general experience. After 10-20 years doing this, you start to remember what things you did that caused pain, and how you avoided doing them again. Many answers work for some problems, but it's the individual's experience that determines their opinion.
There is really only 1 really big thing I would change in your code. I would consider looking into what's called the Command Pattern. Information on this shouldn't be difficult to find either on the web or in the GoF book.
The primary idea is that each of your commands "add child", "add parent" become a separate class. The logic for a single command is enclosed in a single small class that is easy to test and modify. That class should then be "executed" to do the work from your main class. In this way, your main class only has to deal with command line parsing, and can lose most of it's knowledge of a FamilyTree. It just has to know what command line maps into which Command classes and kick them off.
That's my 2 cents.
I can recommend Alan's and James's book Design Patterns explained -- A new perspective on object-oriented design (ISBN-13: 978-0321247148):
It's a great book about has-a and is-a decissions, including cohesion and coupling in object-oriented design.
In short:
Cohesion in software engineering, as in real life, is how much the elements consisting a whole(in our case let's say a class) can be said that they actually belong together. Thus, it is a measure of how strongly related each piece of functionality expressed by the source code of a software module is.
One way of looking at cohesion in terms of OO is if the methods in the class are using any of the private attributes.
Now the discussion is bigger than this but High Cohesion (or the cohesion's best type - the functional cohesion) is when parts of a module are grouped because they all contribute to a single well-defined task of the module.
Coupling in simple words, is how much one component (again, imagine a class, although not necessarily) knows about the inner workings or inner elements of another one, i.e. how much knowledge it has of the other component.
Loose coupling is a method of interconnecting the components in a system or network so that those components, depend on each other to the least extent practically possible…
In long:
I wrote a blog post about this. It discusses all this in much detail, with examples etc. It also explains the benefits of why you should follow these principles. I think it could help...
Coupling defines the degree to which each component depends on other components in the system. Given two components A and B ,how much code in B must change if A changes.
Cohesion defines the measure of how coherent or strongly related the various functions of a single software component are.It refers to what the class does.
Low cohesion would mean that the class does a great variety of actions and is not focused on what it should do. High cohesion would then mean that the class is focused on what it should be doing, i.e. only methods relating to the intention of the class.
Note: Good APIs exhibit loose coupling and high cohesion.
One particularly abhorrent form of tight coupling that should always be avoided is having two components that depend on each other directly or indirectly, that is, a dependency cycle or circular dependency.
Detailed info in below link
http://softwarematerial.blogspot.sg/2015/12/coupling-and-cohesion.html
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I've been a fan of EasyMock for many years now, and thanks to SO I came across references to PowerMock and it's ability to mock Constructors and static methods, both of which cause problems when retrofitting tests to a legacy codebase.
Obviously one of the huge benefits of unit testing (and TDD) is the way it leads to (forces?) a much cleaner design, and it seems to me that the introduction of PowerMock may detract from that. I would see this mostly manifesting itself as:
Going back to initialising collaborators rather than injecting them
Using statics rather than making the method be owned by a collaborator
In addition to this, something doesn't quite sit right with me about my code being bytecode manipulated for the test. I can't really give a concrete reason for this, just that it makes me feel a little uneasy as it's just for the test and not for production.
At my current gig we're really pushing for the unit tests as a way for people to improve their coding practices and it feels like introducing PowerMock into the equation may let people skip that step somewhat and so I'm loathe to start using it. Having said that, I can really see where making use of it can cut down on the amount of refactoring that needs to be done to start testing a class.
I guess my question is, what are peoples experiences of using PowerMock (or any other similar library) for these features, would you make use of them and how much overall do you want your tests influencing your design?
I have to strongly disagree with this question.
There is no justification for a mocking tool that limits design choices. It's not just static methods that are ruled out by EasyMock, EasyMock Class Extension, jMock, Mockito, and others. These tools also prevent you from declaring classes and methods final, and that alone is a very bad thing. (If you need one authoritative source that defends the use of final for classes and methods, see the "Effective Java" book, or watch this presentation from the author.)
And "initialising collaborators rather than injecting them" often is the best design, in my experience. If you decompose a class that solves some complex problem by creating helper classes that are instantiated from that class, you can take advantage of the ability to safely pass specific data to those child objects, while at the same time hiding them from client code (which provided the full data used in the high-level operation). Exposing such helper classes in the public API violates the principle of information hiding, breaking encapsulation and increasing the complexity of client code.
The abuse of DI leads to stateless objects which really should be stateful because they will almost always operate on data that is specific to the business operation.
This is not only true for non-public helper classes, but also for public "business service" classes called from UI/presentation objects. Such service classes are usually internal code (to a single business application) that is inherently not reusable and have only a few clients (often only one) because such code is by nature domain/use-case specific.
In such a case (a very common one, by the way) it makes much more sense to have the UI class directly instantiate the business service class, passing data provided by the user through a constructor.
Being able to easily write unit tests for code like this is precisely what led me to create the JMockit toolkit. I wasn't thinking about legacy code, but about simplicity and economy of design. The results I achieved so far convinced me that testability really is a function of two variables: the maintainability of production code, and the limitations of the mocking tool used to test that code. So, if you remove all limitations from the mocking tool, what do you get?
I totally agree that Testability is not an end goal, this has been one of the things I have realized when developing PowerMock. I also agree that writing unit tests is one way of getting good design. Using PowerMock should probably be an exception rather than a rule, at least features such as expectations on constructors and static mocking.
The main motivation we have for using PowerMock is when using third party code that prevents your code from being testable. A good alternative is using an anti-corruption-layer that abstracts the third party code and makes it testable. However, sometimes I think the code is cleaner just using the standard APIs. A good example of this is the Java ME API. This is full of static method calls that prevent unit testing.
The same problem can occur with legacy code. Some organizations are extremely afraid of modifying their existing code and in this case PowerMock can be used to introduce unit testing in the parts you are writing at the moment, without forcing big refactorings.
Our problem is specifying a set of best practice rules when to use PowerMock or not that a rookie developer can follow. Creating good design is really hard and since PowerMock gives you more options, maybe it just gets harder for a beginner? I think a more experienced developer appreciates having more choices.
(founder of PowerMock)
I think you're right - if you need PowerMock, you probably have smelly code. Get rid of those statics.
However, I think you're wrong about bytecode instrumentation. I mock out concrete classes all the time using mockito - it keeps me from having to write an interface for every. single. class. That is much cleaner.
Only you can prevent code smells.
We've had many of the same questions arise in the .NET arena, regarding Typemock Isolator.
See This blog post
I think that when people start to realize that Testability is not an end goal, and that design is learned in other ways, then we will stop letting our fear dictate which tools we use, or not use a more advanced technology when and if it becomes relevant.
Also, it makes sense to be able to choose the way you design, based on the application needs. don't let a tool tell you how to design - it will leave you no choice.
(I work at Typemock, but was once against it)
I think you're right to be concerned. Refactoring legacy code to be testable isn't that hard in most cases once you've learned how.
Better to go a bit slower and have a supportive environment for learning than take a short cut and learn bad habits.
(And I just read this and feel like it is relevant.)
The layer of abstraction that Powermock provides over reflection seems attractive, but it makes the tests brittle. More specifically:
Reflection relies on string names of the methods/fields etc. Any renaming would break the tests, followed by fixing all tests accessing this method through reflection. Compared to a test that doesn't require reflection, all renamings would be refactored by the IDE.
Powermock's features of stubbing new, static method calls etc. makes you look into implementation details of the function. Tests should ideally test the functionality eg.
functionOldImplementation(){
List l = new ArrayList();
}
// old implementation changed to new
functionNewImplementation(){
List l = new LinkedList();
}
Mocking the new ArrayList() call would break the tests for the above refactoring. Tests are needed most for running regressions and they fail if done this way.
Recently came across this article, it addresses most of the points asked in the question, thought I'd share it.
Some key points from the article:
It took to 1.5 years to make PowerMock + Javaassist compatible with
Java7 since its introduction. Here is note from PowerMock change log:
Change log 1.5 (2012-12-04)
---------------------------
Upgraded to Javassist 3.17.1-GA, this means that PowerMock works in Java 7!
PowerMock site says:
"Please note that PowerMock is mainly intended for people with expert
knowledge in unit testing. Putting it in the hands of junior
developers may cause more harm than good".