4 ms·
Something that people are missing about annotations: in order to test the annotated class/method one needs to start running extra code, sometimes a lot of extra
by AugustoCAS 3y ago
Something that people are missing about annotations: in order to test the annotated class/method one needs to start running extra code, sometimes a lot of extra code.
Using spring as a toxic example, many things have to be tested using @SpringBootTest which is incredibly slow to start. On top of that because of the use/abuse of @MockBean tests stop being thread safe. So one ends up with slow test that need to be run sequencially. I'm working in a 'start up' that went the spring boot way and quite simple services take 15+ minutes to run all their tests, which is insane.
On top of that, annotations make it impossible/very dificcult to know what code is actually executed (and also it not possible to navigate to the code in an IDE). As I rule of thumb, I'm always happy to swap one annotation for one or two lines code.
- ivan_gammel 3y ago> On top of that, annotations make it impossible/very dificcult to know what code is actually executed (and also it not possible to navigate to the code in an IDE) I have never understood this argument. What is exactly the problem with identifying the executed code?
- jakewins 3y agoIf you use a “dumber” imperative style framework, the way to find out what code is executed is to go-to-definition of the library code when you call it. With an annotation-based framework, how do you do the same? You could find usages of the annotations, and then manually read the thousands of places “@GET” is referenced?
- ivan_gammel 3y agoSearch by usages is usually grouped by library/package, sk it is quite easy to identify the code in the framework responsible for processing it.
- moring 3y agoHow do you identify the executed code? I don't even know how to start. You cannot single-step into it from the annotation, nor can you select the annotation, "go to definition" and see the code. You can "find usages" for the annotation which gives you a lot of places that may or may not be the code that gets executed. Imagine I'm looking at a class that is annotated. What is the next step to find the code that gets executed for the annotations?
- stcroixx 3y agoLook at the annotation classes code? That’s how I do it. It can’t be anywhere else.
- ivan_gammel 3y ago1. Download the source code of the framework (one click in IDE) 2. “Find usages” on annotation/annotation properties leads you to init stage, where metamodel is usually built 3. “Find usages” on metamodel classes leads you to the implementation of the behavior defined by annotation 4. Run your code with the breakpoint inside the annotated code. Check the stack trace at the breakpoint, look at the methods and fields of the framework classes in it to validate your understanding of how it works from step 3. The RetentionPolicy.SOURCE annotations are handled by an annotation processor at compile time, so it is a bit different, but the general idea is the same.
- darthbanane 3y agoSome of the aspect oriented stuff like cacheable will add a proxy to the annotated bean which can break reasoning about the code. If you inject the bean and call the method you will get caching (because you are using the proxy). If you call the method from within the bean itself however you're not using the proxy and you won't get caching. It's stuff like this on steroids when you start mixing annotations that makes it really difficult to reason about the code.
- Shaanie 3y agoHehe, that specific case is probably something that most people run into at least once. I've seen several cases of it in production too, where someone refactored something years in the past and accidentally disabled the cache without anyone noticing.
- ivan_gammel 3y agoI know this case. Indeed it adds some complexity in debugging and it does require that the user of such annotation understands how it works and what are the side effects. However this is probably the only case that causes so much trouble and it would deserve a dedicated compiler or IDE warning* for inexperienced engineers. There are many ways to shoot in the leg by using some tool or API incorrectly - it doesn’t mean the tool is bad. *I would do it by introducing a new annotation: @ProxyImplementation public @interface Cacheable {} Compiler can trigger a warning when a method invokes another method of the same class which is annotated with annotation marked as implemented by proxy. Maybe Sonar or similar tool already does this kind of analysis.
- gofreddygo 3y agoAnnotations lead to an undocumented interface. IDE's are incredibly unreliable at finding implementations from compiled libs. That is 80% of my frustration around annotations. There are no standards, no patterns, almost nothing to find details on why some annotation isn't working as expected and what it expects from the developer.
- ivan_gammel 3y ago>IDE's are incredibly unreliable at finding implementations from compiled libs It’s usually one click in IDE to download the sources of an open-source lib like Spring and one click to find the usages of the annotation in those sources (or better, reads of the properties of that annotation). I do not think it is really a big problem to find how the code works both at init and at execution stage.
- AugustoCAS 3y agoHi Ivan! From my exprience there are multiple reasons - The main one: I've learned tons from reading code. The ability to jump into code that does X to see how it's implemented is worth a lot to me. This is something I love about the jvm ecosystem which is unfortunately not present in many other languages. - Many libraries/frameworks (Spring Data comes to mind) provide very leaky abstractions. Understanding how the underlying technology is used can make a big difference. - Address questions when the documentation is not clear enough. - And last: to discover bugs in libraries. This is not common, but it happens.
- ivan_gammel 3y agoMy question is rather why it seems to be so difficult? The value of learning from the source code is indeed great and in modern IDEs it is easily accessible. Ever since annotations were added to Java, I've had no problem figuring out how some frameworks use them.
- okeuro49 3y agoYou would only use @SpringBootTest at the top of the testing pyramid. Spring Boot provides "test slices", so you'd also be using @DataJpaTest or @WebMvcTest, which run a lot faster, as they don't boot the entire application.
- ElectricalUnion 3y agoOn the other hand, Spring is one of those frameworks that you can probably test most of your stuff without those test fixtures and just use the annotated classes as if they are plain classes. That of course means you're limited to constructor based dependency injection (but most people should be using constructor based dependency injection, right? The @Autowired/@Inject "magic" rarely really helps anyone most of the time) and requires isolating side effects (and therefore those pesky side effect inducing annotations) from the rest of the business logic.