Arguments Against Annotations

2019-01-30 22:15发布

My team is moving to Spring 3.0 and there are some people who want to start moving everything into Annotations. I just get a really bad feeling in my gut (code smell?) when I see a class that has methods like this: (just an example - not all real annotations)

@Transaction
@Method("GET")
@PathElement("time")
@PathElement("date")
@Autowired
@Secure("ROLE_ADMIN")
public void manage(@Qualifier('time')int time) {
...
}

Am I just behind the times, or does this all seem like a horrible idea to anyone else? Rather then using OO concepts like inheritance and polymorphism everything is now by convention or through annotations. I just don't like it. Having to recompile all the code to change things that IMO are configuration seems wrong. But it seems to be the way everything (especially Spring) is going. Should I just "get over it" or should I push back and try to keep our code as annotation free as possible?

11条回答
ら.Afraid
2楼-- · 2019-01-30 22:44

Maybe you have a problem with redundant annotations that are all over the code. With meta-annotations redundant annotations can be replaced and your annotations are at least DRY.

From the Spring Blog:

@Service
@Scope("request")
@Transactional(rollbackFor=Exception.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyService {
}

@MyService
public class RewardsService {
…
}

Because Java evolves so slowly people are putting more features that are missing in the language into annotations. This is a good thing Java can be extended in some form and this is a bad thing as most of the annotations are some workaround and add complexity.

查看更多
聊天终结者
3楼-- · 2019-01-30 22:46

I think annotations are good if they are used with measure. Annotations like @WebService do a lot of work at deployment and run time, but they don't interfere in the class. @Cachexxx or @Transactional clearly interfere by creating proxies and a lot of artifacts, but I think they are under control.

Thing begin to mess when using Hibernate or JPA with annotations and CDI. Annotations grow a lot.

IMO @Service and @Repository are interferences of Spring in your application code. They make your application Spring dependant and only for Spring use.

The case of Spring Data Graph is another story. @NodeEntity, for instance, add methods to the class at build time to save the domain object. Unless you have Eclipse and Spring plugin you will errors because those methods don't exist in source code.

Configuration near the object has its benefits, but also a single configuration point. Annotations are good with measure, but they aren't good for everything, and definitively bad when there are as much annotation lines as source code lines.

I think the path Spring is going is wrong; mainly because in some cases there is no other way to do such funny things. It's is as if Spring wants to do xtreme coding, and at the same time they lock developers into Spring framework. Probably Java language needs another way to do some things.

查看更多
我欲成王,谁敢阻挡
4楼-- · 2019-01-30 22:49

Annotations often introduce dependencies where such dependencies do not belong.

I have a class which happens by coincidence to have properties which resemble the attributes from a table in an RDBMS schema. The class was created with this mapping in mind. There is clearly a relationship between the class and the table but I am happy to keep the class free from any metadata declaring that relationship. Is it right that this class makes a reference to a table and its columns in a completely different system? I certainly don't object to external metadata that associates the two and leaves each free of an understanding of the other. What did I gain? It is not as if metadata in the source code provides type safety or mapping conformance. Any verification tool that could analyze JPA annotations could equally well analyze hibernate mapping files. Annotations did not help.

At one contract, I had created a maven module with a package of implementations of interfaces from an existing package. It is unfortunate that this new package was one of many directories within a monolithic build; I saw it as something separate from the other code. Nonetheless, the team was using classpath scanning so I had to use annotations in order to get my component wired into the system. Here I did not desire centralized configuration; I simply wanted external configuration. XML configuration was not perfect because it conflated dependency wiring with component instantiation. Given that Rod Johnson didn't believe in component based development, this was fair. Nonetheless, I felt once again that annotations did not help me.

Let's contrast this with something that doesn't bother me: TestNG and JUnit tests. I use annotations here because I write this test knowing that I am using either TestNG or JUnit. If I replace one for the other, I understand that I will have to perform a costly transition that will stray close to a rewrite of the tests.

For whatever reason, I accept that TestNG, JUnit, QUnit, unittest, and NUnit owns my test classes. Under no circumstances does either JPA or Hibernate own those domain classes which happen to get mapped to tables. Under no circumstances does Spring own my services. I control my logical and physical packaging in order to isolate units which depend upon either. I want to ensure that a move away from one doesn't leave me crippled because of all the dependencies it left behind. Saying goodbye is always easier than leaving. At some point, leaving is necessary.

查看更多
Fickle 薄情
5楼-- · 2019-01-30 22:51

Annotations have to be used sparingly. They are good for some but not for all. At least the xml configuration approach keeps the config in one file (or multiple) instead of spread all over the place. That would introduce (as I like to call it) crappy code organization. You will never see the full picture of the configuration if it is spread across hundreds of files.

查看更多
Explosion°爆炸
6楼-- · 2019-01-30 22:52

It's 2018 and this point is still relevant.

My biggest problem with annotations is that you don't have an idea what the annotations are doing. You're cutting some code off and hiding it somewhere else.

Annotations were introduced to make the language more declarative and less programmatic. But if you're moving the majority of the functionality to annotations, you are effectively switching your code to a different language (and not a very good one at that). There's very little compile-time checking. This article makes the same point: https://blog.softwaremill.com/the-case-against-annotations-4b2fb170ed67

The whole heuristic of "move everything to configuration so that people don't have to learn how to code" has gotten out of control. Engineering managers aren't thinking.

Exceptions:

  • JUnit
  • JAX-RS
查看更多
可以哭但决不认输i
7楼-- · 2019-01-30 22:53

I was also initially skeptical about annotations, but seeing them in use, they can be a great thing. They can also be over used.

The main thing to remember about annotations is that they are static. They cannot change at runtime. Any other configuration method (xml, self-description in code, whatever) does not suffer from this. I have seen people here on SO have issues with Spring in terms of having a test environment on injecting test configurations, and having to drop down to XML to get it done.

XML isn't polymorphic, inherited or anything else either, so it is not a step backwards in that sense.

The advantage of annotations is that it can give you more static checking on your configuration and can avoid a lot of verbosity and coordination difficulties in the XML configurations (basically keeping things DRY).

Just like XML was, Annotations can be over used. The main point is to balance the needs and advantages of each. Annotations, to the degree that they give you less verbose and DRYer code, are a tool to be leveraged.

EDIT: Regarding the comment about an annotation replacing an interface or abstract class, I think that can be reasonable at the framework boundary. In a framework intended to be used by hundreds, if not thousands of projects, having an interface or base class can really crimp things (especially a base class, although if you can do it with annotations, there is no reason you couldn't do it with a regular interface.

Consider JUnit4. Before, you had to extends a base class that had a setup and tear down method. For my point, it doesn't really matter if those had been on an interface or in a base class. Now I have a completely separate project with its own inheritance hierarchy, and they all have to honor this method. First of all, they can't have their own conflicting method names (not a big deal in a testing framework, but you get my point). Second of all you have have the chain of calling super all the way down, because all methods must be coupled.

Now with JUnit4, you can have different @Before methods in different classes in the hierarchy and they can be independent of each other. There is no equally DRY way to accomplish this without annotations.

From the point of view of the developers of JUnit, it is a disaster. Much better to have a defined type that you can call setUp and teardown on. But a framework doesn't exist for the convenience of the framework developer, it exists for the convenience of the framework user.

All of this applies if your code doesn't need to care about the type (that is, in your example, nothing would every really use a Controller type anyway). Then you could even say that implementing the framework's interface is more leaky than putting on an annotation.

If, however, you are going to be writing code to read that annotation in your own project, run far away.

查看更多
登录 后发表回答