4 ms·
Conversely I'd say that a language that doesn't enable an IDE to provide some of the features Java does (first and foremost: call graphs) is unusable, period.
by brazzy 6y ago
Conversely I'd say that a language that doesn't enable an IDE to provide some of the features Java does (first and foremost: call graphs) is unusable, period.
- anonymoushn 6y agoJava developers seem to habitually use metaprogramming facilities that make it impossible to determine what code is calling what other code by hand, let alone using single command in an IDE. When not doing this, they are usually creating interfaces with a dozen implementations that wrap and delegate to one another. So I would very much like to know what calls what, and this is a reason I cannot use Java.
- The_Colonel 6y ago> Java developers seem to habitually use metaprogramming facilities make it impossible to determine what code is calling what other code by hand I assume you mean reflection - this would be very untypical for normal business logic code and would get smashed very quickly in any code review. It's also far from nice and easy code. You can program "dynamically" in Java, but it gets ugly quickly which in itself discourages you from doing that habitually. Reflection is used mostly in frameworks only. > When not doing this, they are usually creating interfaces with a dozen implementations that wrap and delegate to one another. Sure, Java devs have so much time that they don't implement the business logic once, they create dozen different implementations just for the fun of it. Again, this situation (one interface, many implementations) happens mostly in frameworks and rarely in business code. If you want to hate on Java, use some real arguments ...
- anonymoushn 6y agoThe main metaprogramming facility in Java is annotations. Some annotations work like higher-order functions, except that my advanced Java IDE is unable to find what function is wrapping the annotated function. Some other annotations work more like macros, but there's not a convenient way to evaluate the macro to have a look at the code it would generate. I previously asked in another forum about this sort of thing and heard that I should read the docs. I suppose when working at a big company ships internal libraries that expose annotations and use inheritance extensively, but do not have docs, I should just pretend that I am not actually in such a situation, or something.
- The_Colonel 6y ago> Some annotations work like higher-order functions, except that my advanced Java IDE is unable to find what function is wrapping the annotated function. Intellij can show you which aspects have been applied for e.g. AspectJ or Spring AOP. I mean if you or your company really insist on writing your own metaprogramming library then yes, IDE can't do much to help you, but that hardly represents industry practice.
- michaelt 6y ago> I assume you mean reflection - this would be very untypical for normal business logic code No, a lot of java critics complain about it being hard to tell what's calling what at the framework-to-user-code boundary That means not only reflection, but also most Dependency Injection (Spring autowiring, Guice...), anything that runs on annotations (including @Test and JAX-RS), any code auto-generation (e.g. Protobufs, Jooq), most mock libraries (e.g. Mockito) and most configurable logging, especially the logging libraries that try to auto-detect one another. Of course, some would say those problem are with Corporate Java Culture choosing to use all those things, rather than the Java language itself.
- The_Colonel 6y ago> No, a lot of java critics complain about it being hard to tell what's calling what at the framework-to-user-code boundary That's rather an industry criticism since these problems exist everywhere and are often direct consequence of trade off for looser coupling. There are also often alternatives - e.g. Dagger for DI and MapStruct for mapping which go the code generation path which allow you to statically inspect the whole code path, you can also always trade the looser coupling for more directed paths e.g. for logging by avoiding the wrapper and using a logging library directly.
- valenterry 6y ago> That's rather an industry criticism since these problems exist everywhere and are often direct consequence of trade off for looser coupling. No they don't. Java is just not expressive enough, so library/framework authors have to decide between bloat or magic and they often choose magic for better or worse. There are languages that doing better in this regards.
- apta 6y ago> There are languages that doing better in this regards. Such as?
- 6y ago
- raducu 6y agoIt's funny, because I always complain about interfaces with just one implementation, I've never complained about an interface with dozens of implementations :)
- dkarl 6y agoThis is a real world problem, and I say that as someone who has been doing Java and Scala for many years. When you are exploring code trying to figure out how it works and what it does, it's easy to follow the chain of what method is this, where is it implemented, where is this symbol imported from, etc. Subclassing introduces some ambiguity in method parameter types, but at least you can get some information from the documentation of the interface or abstract class, and you can find usages of the method and see what concrete types are passed in different places. Where it really breaks down is dependency injection and annotations. When you hit these, it's no longer "command-click" or "google for Javadoc" to find out what's going on; it's a minor research project. With annotations, if you can't find the information you need in the documentation, you will have to search the source code of the framework and study the code that processes the annotation before you can even locate the code you're looking for[0]. You might be thinking this is pretty awful, but hey, software is complicated, you have to understand the code you're working on —- fine. It's reasonable to put this amount of effort into the code you are actually working on. But when you're working on service A and have a question about service B, it's nice to be able to pop over to service B's source code and find the answer without investing a lot of time understanding the technologies underlying it. This is why "enterprise" Java programmers end up obsessed with anointing "best practice" frameworks. Me relying on a big magical framework for everything I do is only problematic because some other people don't use it. Solution: let's establish my framework as the "de facto standard," and then nobody can complain that it's ridiculous overkill for simple applications. Let's make proficiency with my preferred framework part of the definition of being a professional Java developer, and then nobody can complain about how time-consuming it is to get up to speed with it. The alternative is to use libraries instead of frameworks, use as little magic as possible, and work in a language that is powerful enough that you can write straightforward code and still say everything you need to say in a reasonable amount of space. Consider the simple, ubiquitous case of writing a method to implement a POST endpoint in a database-backed CRUD web service. Suppose you need to authorize the request according to some business logic, deserialize the entity body, validate the body according to some business rules, get a database connection, construct a query, run the query, process the query results into a response object, set the status code and headers for the HTTP response, and serialize the response body. Why shouldn't all of this functionality be discoverable in the code via chains of method calls from the method that implements the endpoint? With a concise language and a well-organized codebase, this is entirely possible. Readers of your code can see: here's where to dig in if I want to see how the request is deserialized, here's where to dig in if I want to see how the database query is constructed. If your code becomes exhaustingly verbose when you express it in this straightforward way, then your language is failing you. As a fan of Scala, I have to admit that Scala introduces a similar difficulty with implicits (and the horrible practice of using wildcard imports to import entire menageries of implicit methods and values, which is epidemic in FP-style Scala.) Implicits are indisputably widely abused, but at least IDEs can show you how implicits are resolved at compile time, and in your own code, you can make implicits reasonably readable without IDE support by declaring them in an enclosing scope with a good name. [0] I'll make an exception for one style of annotation: annotations that point you directly to the relevant code, like @ExceptionMapper(MyExceptionMapper.class). This is almost always all the information I need, the only exception being if the person who wrote MyExceptionMapper misunderstood some subtlety in how it gets wired in via ExceptionMapper.
- Constellarise 6y agoA lot of problems with modern programming can be traced to the "pipe compiler" like model, where your development environment is nothing more than a file editor with a shortcut to run the compiler. It doesn't understand the code, and it can't really help you, and the compiler only really outputs errors.