Hacker News new | past | comments | ask | show | jobs | submit login
Java: Real or Not? (metagno.me)
183 points by mechazawa on June 6, 2015 | hide | past | favorite | 66 comments



It never hurts to study the masters in serious enterprise software: https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpris...


This is great but it brings up a serious question I've always had. Taken to the extreme, things like the single responsibility principal, the open closed principal, etc, result in messes like this. I've been wondering if anything has been written around a concrete methodology of doing OOP that doesn't naturally converge onto something like this, and why it happens.


You might enjoy this: http://mollyrocket.com/casey/stream_0019.html

I think the problem is that OOP is automatically considered "virtuous", despite the context. There's nothing wrong with the single responsibility principle and what not, but there is something wrong with thinking that classes and objects are always the best way to approach a problem. Java ends up being the target of jokes because by forcing everything into classes/objects even when it doesn't make sense, it leads to cartooned versions of those ideas.


I believe that humans are terrible at predicting the outcomes of complex systems over time and that software you get paid to write is always a complex system. Therefore, the best way to make your software better is to choose the option that produces less state. This has been my guiding principle of software development for about 6 years. The main problem I ran into is that going too far results in software that's hard to maintain because control flow jumps around.

My solution has been to think of code locality as being valuable. I start off writing something the straightforward way. When I go to implement something similar, I decide whether to abstract the code or not based on how much easier/harder it will be to naively trace the code. If I've done this thing 3 or 4 times, it's a concern and should be separated. If I'm just making something shorter/"nicer"/DRYer I should probably just write stupid code.


It is fancy around these parts to bash OOP and other things that aren't JavaScript/Clojure/Haskell/Rust/etc;

DRY, SRP, LSP, OCP are very valuable. There's a reason there's a score of enterprise-grade software being written with exactly those principles in mind. I am not discounting Functional Programming in anyway. But to dismiss OOP and the design patterns is a fool's errand. It has its place, and rightly so.

Look at what the programming Lords (Ken Thompson! Rob Pike! Lars Bak!) at Google came up with when they sat down to design a language-- Go (which is part-OO, part-imperative [1]), or Dart (OO again). OO detractors often point out that "popular opinion isn't always right" and that "people are afraid of change" and there's some level of truth to that, but the fact is, a lot of developers out there are proficient with OO, and see it as a good way to develop massive programs (1 million plus SLOC) unless some radical shift happens in the coming years [2].

[1] https://golang.org/doc/faq#Is_Go_an_object-oriented_language

[2] http://worrydream.com/LearnableProgramming/


The problem isn't that those principles are bad - they're useful - but the languages we're attempting to use them from are not sufficiently expressive enough to follow them all in a practical way. "Design patterns" and DRY don't mix very well - because the act of implementing a design pattern is largely repetitious. We create XFactory, YFactory, ZFactory for example, with largely the same structure but slightly different logic - then someone takes DRY to the extreme and tries to abstract it away into a FactoryFactory, using reflection or some other tool to get around the host language's lack of expressivity.

This is where the mess begins, because it becomes so cryptic to figure out how to use the FactoryFactory to create your own Factory to create some other types you need. It may be trivial to people who've been hacking with the same languages and frameworks for years, but the principle of least surprise is abandonded for new users attempting to use a framework for the first time.

Functional programming suffers from the same overuse of idioms which are unwelcoming to novices, and often throws away some useful ones in favor of ease of use. FP doesn't necessarily dismiss OOP, and it's often used in combination with functions to write practical programs.

Functional programmers don't see OOP as a problem - it's a very practical tool. The problem is that it's the wrong tool for many problems - particularly if you're just computing functions[1]. That a lot of developers are proficient with OOP and see it as a good way to develop programs is part of the cause - they're blind to alternative methodologies and shoehorning something into an object where it doesn't fit is seen as a being skillful. Also, anything that doesn't conform to the language's narrow view of "the right way" is considered an anti-pattern.

[1]:http://www.yegor256.com/2014/05/05/oop-alternative-to-utilit...


You imply the problem is one of fashion (those kids will see the value of OOP once they get over their javascript phase!), but I think OOP was basically a fashion in of itself. Essentially what we think of as OOP is just taxonomy mixed with structures that carry around function pointers. Yay? It's a nice wrench to have in your toolbox, but it shouldn't be your only tool. The notion that the people that helped invent all this in the first place are continuing to do that doesn't really make me think the principles are sound.


Is C++ OO? If you say yes, defend your position, given that Alan Kay disagrees.


SOLID are not rules but guidelines. Design patterns allow the code to be written in a reusable manner by decoupling some responsibilities. But YAGNI, no code should be written until it is needed.

That's why TDD is absolutely fundamental. In theory TDD can help fight over-engineering, and keep focus on relevant code. SOLID and design patterns are then here to help refactor code when a spec changes. They are recipes.

Obviously TDD fizzbuzz done correctly would have resulted in a single class implemented. Now imagine requirements changes and booze should be printed if the number can be divided by 20,breeze if the number can be divided by 40,bubble when divisible by 56, the easiest way to refactor that single class would be to introduce a CHAIN OF RESPONSIBILITY. Which again is not necessary at first place, if the number of cases remains small.


TDD means you write code that is easy to test, rather than easy to adapt to your use case. Find the use case for your code, code that (and now more), add tests as desired/needed.

In your example we can observe that we still only have one action: print $VARIABLE if $COUNTER mod $VALUE. This doesn't call for anything like a chain of responsibility, since it can be solved by a collection of tuples and a for loop.

My personal guess about the difference between an average programmer and a good one is that the good one knows when to add space for more features (because he can anticipate the customers needs).


I think there's a lot of truth to this. Adding flexibility on one dimension almost invariably makes other kinds of changes more difficult, so you come out far ahead if you can correctly anticipate the direction in which your application is likely to grow.


There is always a time when you go too far and a time when you don't get far enough. If you can, you refactor when it becomes clear.

In the case of Spring though, they have a tough problem to solve. They are gluing technologies together, so they are always going to have factories of factories, adapter of adapter, and that kind of things. And if in the bunch of tech they glue there is an outlier that behaves unlike the other, or a poorly designed one, they will need to handle it somehow.

Another feature that weights on Spring design is that almost the whole framework is public. Generally you would have a core architecture and well defined key extension points. Not with Spring, and that means more "useless" abstraction and therefore more mess.


I use Spring and I'm not agree that it's a mess. It has a lot of functionality but good architecture allows to keep it under control and easily enhance when needed. Spring is one of the best open source frameworks I've ever seen.


Both Spring and JavaEE (as compared to J2EE) have gotten a lot better by using annotations for meta-programming. I was about to give up on enterprise Java programming when the clutter/over-engineering started to get better.

Curiously, I'm going to at least partially credit Ruby for introducing the idea of convention over configuration.


Why curiously? RoR hit hit java web development like a ton of bricks, with its convention over configuration and quick start. The end result are java projects like Play and Spring Boot.

I am not really a ruby guy, but I'm very thankful RoR came along and shook things up.


I don't mind these kinds of guidelines until someone tries to use them to support their argument as if they were scientific facts.

My favorite example is the single responsibility principle, which, while a useful guideline, is 100% qualitative. All classes and functions do more than one thing.

Is making a sandwich one thing? Is putting mustard on the bread one thing? Is opening the mustard jar one thing?

The exception might be if you had a function call bitFliper that turned 0s to 1s and vice versa. But that's probably as close as you could get in most programming languages.


Unfortunately, it's more of an art than a science. The simple rule is: it should be as simple as possible, and no simpler than that. Obviously, everybody has a different idea of where exactly that line is.

Usually though, if you try to make the code clean and as small as possible while still allowing unit tests to be written, you normally hit a decent spot. YAGNI applies very heavily here too and it's often better to make the code less generic and refactor it later when required.


OOP is seldom the best model for software construction. A model (using relational, graph, set operations, etc.) can be implemented using enties given in an OOP language but if the software engineer 'thinks in objects' mess will probably ensue.


Only 85% coverage? Tsk tsk tsk...


The names are extremely predictable (as shown by this Markov chain), which is actually a Good Thing (tm). The bad thing is that things got complex enough to warrant these names.

It's the knee jerk reflex of decoupling everything, to the point that you have 80% configuration/wiring/setup vs 20% of code that actually does something useful.

Each extension point in the framework is represented by a couple of these classes to handle the layer of indirection. Maybe Spring should run a study and see which of their extension points is actually used, at all, or by more than x % of users, and then cut down all the useless ones. I'm not too familiar with Spring these days, but I'd expect that the vast majority of indirections isn't actually useful for anybody.

The other problem is that our mechanisms to introduce and handle these abstractions are too verbose. Each extension point spawns multiple classes where it's really just one little method that needs to be called instead of another block of code. That makes software systems extremely hard to understand and use, and the overall bloat does actually slow things down - if not in production, then in deployment, startup, and build.


> Maybe Spring should run a study and see which of their extension points is actually used, at all, or by more than x % of users

That last part seems key: I'd be shocked if you didn't find someone, somewhere for every one of those features – and, based on some of the enterprise apps I've seen, doing so because it allowed a quick hack rather than solving a problem more correctly and expensively. The question really should be “Is the value from having this work the non-trivial obscurity and maintenance cost?” to emphasize that features and extensibility aren't free.


What struck me is it looks seriously like Hungarian notation applied to function naming.


This is sort of like making fun of German for using long combinations of smaller words to denote a concept.

Or making fun of medical jargon. (ha ha, you said subdermal hematoma not bruise)

Once you know what the individual words mean, you can use them in different places, and know right away what the class does. Do you need to use 80% of these? No, but they're there, like parts in a car, in case you need to tinker.


And it's not like anyone is typing these words out. IDEs have auto-completion for that purpose.


Moreover, in Eclipse you can do camel-case completion. So you can type "ACV" and get "AbstractCookieValueMethodArgumentResolver". (I'm not sure if other IDEs do this)


I believe IntelliJ does this also, but Eclipse did it first.


Most of the atrocious stuff is in J2EE related frameworks (looking at you spring and hibernate).

I think core java libraries are amazingly designed and a good part of why the language became popular. You won't find many FactoryFactories there, The land of c,c++ libraries that came before is incredibly fragmented, inconsistent and difficult to use by comparison, not to mention the documentation. Good lord the docs ;x.


It's not surprising that a Markov chain could put together plausible sounding class names, because yeah, there are definitely patterns that class names fall into.

What's surprising is that one third of the names it's showing me are actually real. I mean, "MetaMetaContextHierarchyConfig" actually exists?


> I mean, "MetaMetaContextHierarchyConfig" actually exists?

Apparently.

https://github.com/spring-projects/spring-framework/blob/mas...

"Custom context hierarchy configuration annotation that is itself meta-annotated with MetaContextHierarchyConfig"


It's worth pointing out that this is test code.


I got "ConfigClassesAndProfileResolverWithCustomDefaultsMetaConfig.ResolverConfig" as real (which I failed to pick... I mean, really?) and had to doublecheck it really is.

Sadly, it's true. What the hell, Spring Framework?


Don't forget you can't test the ConfigClassesAndProfileResolverWithCustomDefaultsMetaConfig without a set of ConfigClassesAndProfileResolverWithCustomDefaultsMetaConfigTests.

And of course, what about testing the custom overrides of that config?

Well just use the ConfigClassesAndProfileResolverWithCustomDefaultsMetaConfigWithOverridesTests!

Seriously.


Are the generated names verified to be non-real? There could be some overlap.


There is definitely overlap, it tells me that HttpSession is not real, and guess what, https://docs.oracle.com/javaee/6/api/javax/servlet/http/Http...


The real ones are supposed to come from Spring, not the Java stdlib.


They're not, there is quite a bit of overlap because most of the names are reused (i.e. once you know what a Context is, Handler, etc., smashing these words together makes sense


Some answers are not 100% right. I got:

- HttpServlet

- AbstractXmlWebMvcResultProcessingInterceptorAdapter

- MockJtaTransaction

While there is HttpServlet class, it is considered wrong, and 3rd option is considered correct :(


It's only talking about classes from Spring specifically. HttpServlet isn't a Spring thing.


That makes it even-more-pointless. It's like people criticizing command-names in linux and going "LOL a computer made that one" even though the command actually exists in another distribution or shell.


Are you calling the Spring developers Markov chains?


I don't like complaining about submissions not working in my browser, but this time I feel like I'm missing a lot of fun.

On Firefox DevEdition nothing past "Pick the one that's not made up!" appears. On latest IE it's every time "ComplexPortletApplicationContext.EditController" vs "ModelMapBasedHandlerMethodProcessor" vs "AbstractPlatformTransactionAttributeSource". 16 times the same question. Well, this could be just bad luck if questions are random. With randomness you never know.


Trust me you are having more fun than anybody out here.Unless being humiliated in a way that you will never dare claim mastery on any thing (even when its the only thing that you think you are good at) sounds like fun to you ;)


"The principle of least surprise" is sadly missing from this API.


Not true. The reason these class names are so long is that they explain in great detail what the class does.


Note that some classes exist (even if not in Spring, at least in base Java) http://imgur.com/sNk4mE2

The key thing to keep in mind with generative models based on real data is that just because results were based on random generation doesn't mean they can't match something real.


Nice. We made fridge-magnets in my last project to help generate excellent names like these.


Haha, I need to try this but for the whiteboards at work. We sometimes try to come up with ridiculous names too


Spring is not the only framework with bad names; look at this class name from aspectj:

org.aspectj.weaver.patterns .HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor


It's utter bullshit to conflate Spring and Java like this.


It's been a few years since I've seriously used Spring, but I when I did, I used the hell out of it. I'm pretty surprised by how many times I was fooled.


Like any other primitive, dogmatic religion, Java will stay for ages, because there will never be a shortage of idiots to repeat the dogmas and mediocries to have a decent living by manipulating the crowd.

Java is triumph of the "packers mindset".

http://the-programmers-stone.com/the-original-talks/day-1-th...


This post perfectly sums up a mindset I detest. Engineers get shit done and don't care about whatever the most recent hipster programming language is. They can probably spell "mediocrity" as well.


I'm with you.

I really don't think people with that mindset could put together the sort of shit we do on the enterprise mindset side of things. The tools are carefully picked to be entirely the opposite to the contrarian mindset.

So we have a system that has about 500 HTTP endpoints, 600 service endpoints, 4MLoC, several TiB of data, several TiB of documents, handles 5000 concurrent users 24/7 ramping up to 2 million euro consumers (not concurrent) and 10 full 42U racks of kit in two facilities. Oh and strict security isolation through several layers.

Java+c# is the only answer.

But 50 times a day someone says, hey rewrite it all in Ruby and Monogo. That's a joke.


Out of curiosity does your system need to be this complex? Could it have broken down into smaller sub-systems that maybe aren't as integrated, but get the job basically done?


70% of this is required to be this complex as the sector we work in is very rule and workflow heavy and the customisation support is immensely complicated. 30% is hacked in stuff for single clients and legacy stuff from the dark ages that we had to hang on to.

We're breaking it down into tiny subsystems at the moment i.e. moving to a microservices architecture. I'm describing the "monolith" that we're starting from.

In time it'll have 1/2 the code, 2-5x the throughput and significantly less cost.


How come that most of recent 3G and 4G GSM systems runs Erlang order of magnitude more efficiently?


Good question. It's not about efficiency; it's about productivity. It would be impossible to build a system of this complexity for the budget specified with Erlang. This is not a limit of Erlang but a limit of who we have available to build it and run the platform.

I'd rather be using Erlang or Common Lisp myself.


Tell us that you at least use nginx at these 500 HTTP endpoints, not servlets...)


No we don't use nginx. F5 big-ips in front of a large IIS cluster serving through WCF + ASP.Net MVC.


Exactly! The very term you use is telling - "shit" is exactly what comes out of Java sweatshops. They call it Enterprise Software - write once, run away.

BTW, how many languages do you speak well enough to hold an intelligent conversation?


That was really offensive. I hardly see the need for personal insults.


Nice job blaming all of Java for Spring's foibles


The chained names are often too long; I find it hard to believe that my very rusty Java/Spring is the reason I got almost all of these right.


Rusty Spring? Reminds me of that literary classic by I.P. Knightly.


It amuses me that names in Verilog 1995 (a language with no structures) look pretty much the same: oc48_transp_decode_data.


HN goes reddit. Java, oink, oink, lol!




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: