16 ms·
Death by 1000 layers: the perils of over-abstraction in Java (2017)
- phoe-krk 6y ago> Unfortunately Java’s structure seduces the unwary programmer into excessive abstraction. Between demanding a class for everything and enforcing all types at compile time, it encourages you to lay down layer after layer of formalism in class and interface declarations. To me, it's not really about "seduction", it's about inviting the programmer to abstract away with tools that are heavily unfit for the job. If your only means of abstraction is a class, everything starts to look like a method call. That's why I enjoy Common Lisp's ability to create macros on multiple stages of the language's operation: reading code, compiling code, substituting function calls. These make it possible to introduce new syntax where necessary, which in turn makes the code shorter, and to write compile-time optimizations that do not get in the way of the main function bodies.
- FpUser 6y agoThe abstraction is abstraction. It does not matter how it is implemented. Might as well do 100 levels of function pointers or simple nested calls with no classes at all. I think the author's main idea is that your methods should carry some weight and be long enough so you can visually trace the logic. Do not write functions that do nothing but multiply 2 numbers.
- phoe-krk 6y agoI can agree with the second paragraph but I disagree with: > The abstraction is abstraction. It does not matter how it is implemented. To me, it does matter. A good abstraction should not get in the programmer's way. This directly depends on making the language's syntax support the abstraction in question. This, in turn, depends on the macro system of the language or lack thereof. Finally, that is a question of the given language's expressiveness, or lack thereof.
- FpUser 6y agoYou can have all the expressiveness in the world and still write those 3 liners. Or you can have plain functions and still write decent code with abstractions where needed. Basically good master will try to make decent job with any instrument and bad one will mess up everything disregarding the tools given. Of course on its own more expressive languages make job easier to write and read. Not denying that part.
- phoe-krk 6y agoYes. That is the part that I agree with.
- lmm 6y agoYou don't need macros, you just need a language that isn't awful. Plenty of languages make writing a plain datastructure and values of that datastructure easy, make "good code" just as concise as - if not more concise than - "bad code".
- ajuc 6y agoAbstraction is good when it lets you not thing about something and still understand how the system works. Abstraction cost is that the system becomes more complex overall. Good abstraction makes the system easier to reason about and leaks rarely, so you rarely have to think about the insides. But all abstractions leak under some circumstances. If you have 100 layers of abstractions at any given moment some layer leaks and you're constantly fighting the system without being able to understand how the whole thing should work. Language syntax only helps by removing the need for some abstractions by including them in the language.
- aidenn0 6y ago> Do not write functions that do nothing but multiply 2 numbers. Maybe I'm missing something, but doesn't Java already have a function that multiplies 2 numbers, as well as a fancy infix notation for calling said function?
- brundolf 6y agoThe problem is one that I've witnessed, but uh: > Good Java should resemble C The recommendations are a mixture of things that are... questionable, and things that really apply to basically any big refactor regardless of paradigm, language, or problem. But getting back to the issue at hand: what I see from the Java/C# world is a mentality of "abstract unless there's a reason not to", instead of "don't abstract unless there's a reason to". Charitably, this approach might be compared to the micro services pattern: if you're shipping your org chart, and your org chart is thousands of people across four continents, then maybe eagerly building out those fire-walls of decoupling can be useful. Stereotypically, at least, this seems to line up with the kinds of companies we tend to think of as using these languages. But where it becomes a big problem is when it's used in a one, two, five-person project, and all those walls just become massive speedbumps, not only slowing you down but making it hard to drive straight.
- raducu 6y ago> A well-considered class should own an interesting decision and the data needed to make it, not just one or the other. This is not about abstract/non-abstract, Java, C or C# . This is about 99% of people not being able to write decent OOP code. This is not about "programmers" not getting that first awe inspiring feeling when they first see decent OOP code, it is about not caring, not event after 15+ years of programming OOP languages. This is why I always see endless @Service and @Entity code, completely separated, like it's 1996 and we have procedures and structures in Borland Pascal.
- treve 6y ago> Good Java should resemble C If that sentence from the article is the only thing you took issue with, I'd wager you interpret it different than the author's intent. I took it as low on abstractions and mostly imperative.
- brundolf 6y agoIt wasn't the only sentence I took issue with, it was just the one that raised my eyebrows the highest. > low on abstractions I feel with this that the author is going to the opposite extreme. The takeaway isn't that abstractions should be eliminated categorically, just that they have a cost and shouldn't be fetishized. > mostly imperative I take issue with this too, though this part may be more a matter of personal preference. Yes, it's worse when your imperative logic is split across 15 files, but I see imperative logic itself as something to be done sparingly. Imperative logic means mutation of state, means easy-to-lose-track-of side-effects, means unpredictable behavior. This is sometimes unavoidable at the systems level (where C is typically used), but it is absolutely avoidable at the application layer (where Java is typically used). Here's another one that raised a red flag: > A well-considered class...should be easy to name, ideally with a noun that corresponds to something in the real world with a lifecycle of its own. Real-world-modeling was found a long time ago to be a bad approach to OOP. The author is right to say that classes should represent clearly distinct concepts that are easy to name, but there's no reason those concepts also need to map to real-world entities. Often, they shouldn't.
- Hermel 6y agoThe problem is not the language. It is possible to write very elegant and well-structured software in Java. The abstraction bloat usually seen in Java software comes from somewhere else, and I’m not sure where. Is it a symptom of corporate software? Is it Java’s popularity that attracts lots of mediocre programmers? Or is it that Java is often used for solving complex problems that are by definition hard to get right?
- tester34 6y agoI tend to believe in environments like Java or C# there's shiittton of focus on architecture, patterns, interfaces and generally testability there's shitton of discussions about those topics in those langs So it may be reason why people tend to over abstract stuff.
- eandre 6y agoIn my experience languages have a culture of their own. For example, C++ has a culture of caring about low-level details to squeeze out maximum performance. I once found myself writing something that wasn't performance critical in C++ due to a library I needed, and just minutes later I caught myself reading up on move semantics for maximum efficiency. I couldn't help myself getting sucked in by the language culture! Java's culture, in my opinion, is one of abstractions. There's little in the language to force you down that path, other than decades of it being the prevalent way Java is written, which bleeds into the standard library, core frameworks, and becomes the Java Way of Thinking.
- polotics 6y agoTotally! Java developer's over reliance on design patterns and abstractions tends to enable atrocious designs, very often the first idea that came to mind at a very early time in the design process, clambering on to a monstrous implementation that somehow runs. In Python, the relative flexibility and pseudo-code nature of the language means that more designs get tried, and simplicity wins. In C++, developer self-selected into being hard-core, so you get hard-core code...
- 6y ago
- deleted 6y ago[deleted]
- rho4 6y agoOne of my dear colleagues a few years ago went on a tear and added interfaces to basically every single class he could lay his hands on. C/C++ header style I imagine. To this day I cannot easily follow code because any time I Ctrl+Click on a method call I end up stuck in the interface and have to first find the single implementing class, open it and then navigate to the corresponding method.
- alanfranz 6y ago> have to first find the single implementing class This _can_ be a problem with Java, admittedly. Sometimes you've got a single meaningful implementation, but you need an interface either for using it with services that implement such interface at runtime to create proxies (e.g. Spring, Hibernate, others) that augment its functionality, or to properly mock a dependency. BUT: the IDE should be your friend. Almost every Java IDE supports "go to the implementation". And, what is the alternative? Fewer interfaces sometimes lead to even worse patterns (for testing: monkeypatching and concrete class subclassing). I prefer the clarity of declaring an interface wherever an interface makes sense. Using a lot of interfaces and defining APIs (which are, mostly, collections of related interfaces) makes the Java ecosystem highly pluggable. I can mix-and-match a lot of different libraries and/or implementations, as long as there's an interface they can work together in a rather good fashion. Consider Python: there're very few (and sometimes poorly defined) interfaces and API; so, quite often you need to pick a library/framework which implements everything and works poorly with other implementations.
- arkh 6y ago> I can mix-and-match a lot of different libraries and/or implementations, as long as there's an interface they can work together in a rather good fashion. But are you writing a library? If not, your product does not have to be plugable. Also if you end with multiple interfaces with only one implementation you should start with classes and extract interfaces when needed. And I think the Java abstraction root problem comes from the way of doing "unit-testing" at the class level. Your users don't care about your application architecture: they want functionalities. Method and class level unit testing is just fossilizing your code and giving you some kind of feel-good number. You should be able to drop all your code, start anew with a new stack and have your tests still usable. Refactoring should never mean having to rewrite tests.
- wintorez 6y agoI believe it’s called Lasagna Code; too many layers.
- tragomaskhalos 6y agoOr Ravioli Code - bajillions of little parcels
- commandlinefan 6y ago"All problems in computer science can be solved by another level of indirection, except for the problem of too many layers of indirection." -- David Wheeler
- alenmilk 6y agoI think that one part is the architecture. People use patterns to divide up code with duplication and interfaces. This makes the code more complex, but has some merit as the code is more testable and extendable. The second part is the use of object orientation to reduce code duplication. I am not a fan of this. It leads to deep stacks of inheritance where the code is smeared out in many layers. Modular code is much better in my opinion.
- mrkeen 6y ago> Remember that software is at its core procedural. > Computers do this thing, then they do that thing, then sometimes some other thing. High-level languages and object-oriented design are fanfare and pageantry distracting from our fundamentally humble jobs: pecking out if-then statements. Then just use C and reap the speed & ram benefits!
- svachalek 6y agoThis was the line that made my eyes roll the hardest. Just remember that all cars are at their core internal combustion engines!
- burade 6y agoAre they not? What's the sole purpose of a car other than to go from point A to point B?
- Twisol 6y agoBicycles are also an excellent means of going from point A to point B, and they're quite a bit simpler than a car. Internal combustion engines are useful for other tasks, such as powering a generator. We shouldn't confuse the task with the tool.
- commandlinefan 6y agoWell actually if you're just using the machine as the machine, you should be coding in Assembler anyway. If you're not unrolling your own loops, you're wasting processor time.
- durnygbur 6y agoThere doesn't exist a problem which cannot be solved by adding another iterable enumerator.
- meddlepal 6y agoI used to be a Java developer now turned mostly to Go and this is one of the things I dont miss at all about Java. So much abstraction and often not for good reasons. Theres a lot of stuff I miss about Java but the culture of layers is not one of them.
- latch 6y agoGo has its own set of problems though. There's the oft-mentioned error handling, "type" system and modules. However, more closely related to the OP, has anyone else struggled with the organization of even medium-sized systems? Obviously some people manage, but I don't know how. I used to do Go a lot more than I do now, but I think I've narrowed it down to (a) it's simplistic (boolean) visibility capabilities (b) lack of overloading and (c) lack of static functions. Instead of `User::new()` and `Role::new()`, you end up with `newUserWithPassword` and `NewRole`. You can do a package per module - but that doesn't solve the issue with overloading, and you can get into cyclical imports. You can solve overloading with a config objects, but now it feels like you're back to over-abstracting.
- ajuc 6y agoI've worked on a 2-layer warehouse management system written in PL/SQL on the backend with very thin C++ layer in Qt 3 on the front end. It was pretty nice, there was a proprietary framework to use one XML file per form with SQL and metadata to generate CRUD with SQL-backed grids, filtering, sorting, and simple actions, and everything else was added with straightforward C++ Qt code. Almost all business logic was in PL/SQL. It was simple and quick and the divisions were obvious. We moved it to 3-layered Java code with SQL (and some PL/SQL still) on the backend, then Jboss application server and EJB3 code, and Java Swing forms on the frontend. The goal was to eventually move all business logic from PL/SQL to Java and avoid Oracle Tax (it was before Oracle bought Java BTW - funny how that worked out :) ). That all would be fine, but our architects bought the cool aid and decided to overengineer the crap out of this software. What was PL/SQL + 1 XML file + 1 Qt form became like 10 layers of XML files (1 specifying how to get the data from database, another how to transform it to DTO format, another how to represent it on the frontend, another what actions should be possible on it in the frontend, another how to transform from DTO to action object for each action, etc. Yes you had to write less code in edge cases than in the C++ solution, but instead you had to juggle over 10 XML configuration files even for simplest cases where before 1 SQL wrapped in XML was enough. It wasn't 3 layers of abstraction - more like 12 in practice. And all that configuration bought you was the ability to potentially write slightly less code when using several forms together and passing data between them (which we almost never did anyway). It was developed for years and finally shipped (I think), but only to one customer out of dozens and we completely switched the technology again soon after for unrelated reasons.
- deleted 6y ago[deleted]
- UK-Al05 6y agoOne the worst systems I worked on was tons of untested PL/SQL. Could not change anything without unknowingly breaking something.
- ajuc 6y agoIt was pretty good code as far as PL/SQL goes. All the functions were divided into packages and followed this template: function (inParam1, ..., inParamN, outParam1, ..., outParamN, outMessage): ReturnType begin savepoint SP_begin; -- do stuff outMessage := '...'; return RESULT_OK; exception when ... when others then rollback to SP_begin; outMessage := '...' || exception details || ' ...'; return RESULT_ERROR; end; It's funny how I remember this after more than 10 years :) Made it very easy to add tests and to interoperate with container-managed-transactions in EJB3. I even added an debug-only interceptor on EJB that created a savepoint before calling any PL/SQL and checked if that savepoint was still valid after the call. If no - that's a PL/SQL that isn't following the template and the developer who changed it needs to be flogged ;)
- TrianguloY 6y agoRecently, for an academic project, I were given a one static one-function very long class that implemented an algorithm (was obviously programmed as a cpp algorithm). The algorithm consisted of steps (gather data, transform data, print data, etc) so as a 'what if' I refactored it by moving each step into a class (so the main function was now one line for each step). Also, what originally was multiple if/else to different outcomes (print to file vs print to console) was now one abstract class with one sub class each. The algorithm code was practically the same, the difference was where it were located. Instead of needing to scroll a lot, you now needed to switch between files. Was it worth it? Probably yes, not for the final code but for the experience of 'this is an exaggeration that you should not repeat' (although the resulting class diagram was a work of art). As usual, extreme abstracting is bad, but extreme lack of abstracting is too. You should find a common term that make the current work simple enough, but that also allows for future changes to be simple to implement. If you are making a list-like class because you need to keep a collection of strings which you are only comparing, don't use strings. Use <T> even if you only use it with strings, the extra cost while creating the class is almost nothing, but the cost of a future refactorization will surely be greater. "Try not to open doors you don't need, but keep them accessible in case you need them later"
- usrusr 6y ago> Use <T> even if you only use it with strings, the extra cost while creating the class is almost nothing, but the cost of a future refactorization will surely be greater. Allow me to question the "almost" in "almost nothing". Java generics are famously unreified, at runtime it's exactly the same. I have noticed this habit of what could be called redundant genericity in my own code as well. Sometimes the motivation seems to be hardly more than a coping strategy for the notoriously verbose class names of idiomatic java. But it can also provide self-describing value: at the use site, Bag<String> reads better than BagOfStrings and on the implemention side, class Bag<S> makes it clear that nothing in there will look at e.g. individual characters. Obviously, if you do need to consider individual characters, go with BagOfStrings - or go with class Bag<S extends CharSequence>, which would notify the reader right in the headline that somewhere in the implementing it requires access to the actual text nature of its data. As a bonus, even if production code only ever fills the angulars with one specific type, chances are that it's a type that is painful in a unit test. If you do esoteric set operations on WhateverFactoryFactories or something like that it's super-convenient if you can just play them through with strings.
- throwaway4good 6y agoI think Java programmers (and their buddies in C# and similar land) can benifit from adapting a straight forward functional style of programming. Not the stream, map, reduce stuff. But simply writing functions without side-effects and separating data from functions. "Remember that software is at its core procedural." That may be true in some sense. But most Java code is in fact not procedural but stateless in the sense that most often state is store in a database or another external system.
- leto_ii 6y agoIsn't this a bit the opposite of what the article is recommending? It seems the author would like full oop, stateful objects etc. Or maybe I got it wrong...
- throwaway4good 6y agoNo. I think you have got it right.
- selfhoster11 6y agoI agree and tend to create my code in this style. The bonus to this style of programming is that testing functions in isolation comes almost for free.
- cies 6y ago> can benifit from adapting a straight forward functional style of programming. Isn't Kotlin largely scratching this itch?
- alenmilk 6y agoTo be more specific, get rid of setters unless it is a data object. Have all fields be final and set them in one constructor. This makes the code more readable since you know no method will change the internal state.
- MichaelMoser123 6y agoi thing some clever layering of spring beans makes for good job security. The problem is that you have to reconnect the binary dependencies to the original source versions, but that's an 'implementation detail', isn't it?
- tragomaskhalos 6y agoThere's one point where I'd argue with this - little classes that encapsulate a single simple domain concept are extremely valuable; an example would be a Path type that facilitates building paths, canonicalizing them etc. The key is that they do not add to the cognitive burden, because their behaviour is (should be) obvious from the name and the name of the methods alone. Furthermore, by adding more nuanced type information, they improve the expressiveness and robustness of the code (as opposed to just using a String for everything). One of my biggest beefs with Java is that, by virtue of the one-class-per-file concept (pace inner classes), the class is elevated to the level of a big deal in the novice programmer's mind, so that a little class with a very clear and narrow scope seems to be unworthy of existence, and we get the String-for-everything syndrome. Anecdotally, I have encountered exactly this attitude on projects.
- elric 6y ago> a big deal in the novice programmer's mind That's an interesting take, and I think you're right. In retrospect I have wondered why my more junior coworkers so rarely create new packages or new classes. Perhaps this is the reason. Will have to take that into account when doing reviews.
- pgwhalen 6y agoI'm optimistic that Records will help at least a bit with this problem over time. Simple data aggregates will come with much less ceremony than before. I've always been against generic Pair classes, and with Records there will be such an easy and superior alternative. https://openjdk.java.net/jeps/359 https://openjdk.java.net/jeps/359
- giberti 6y agoNot unlike Goldilocks sampling the bears’ home, what is just right, is often a matter of perspective. A developers education, experience, and domain all impact how different abstractions are perceived. Sometimes having an abstraction can reduce cognitive load. Think of the configure vs convention arguments for frameworks. Knowing how to implement simple functionality the “right way” (within the paradigm of that abstraction) can make building software easier especially when collaborating with others. I personally find consistency more valuable than having the perfect level of abstraction. Consistency, even if slightly more or less verbose than I might otherwise choose, means I spend less time thinking about the abstraction itself. It allows me to focus on the problem domain, which is where customer value exists. It has the added benefit of simplifying collaboration with others who are also familiar with the abstraction.
- cutler 6y agoIt's easy to see Java culture for what it is when you embrace Kotlin which is fully Java-compatible yet doesn't ape the over-abstraction and verbosity of Java. Kotlin releases you from the OOP-only straightjacket of Java. I recently wrote an API with Kotilin/Ktor using only functions and it was a piece of cake. Not a single AbstractProxyServiceBuilderFactory in the whole codebase. Kotlin's multi-paradigm approach makes it an ideal candidate for projects begun in Ruby or Python which need to scale as all these languages are OO-based but with the option of going procedural or functional when required. PHP is weird. After PHP5 was released it's as if a spell was cast on the whole community compelling them to write their code as if the language suffered from the constraints of Java. Talk about culture envy. Procedural PHP seemed to just vanish as if it had been deprecated. So Java culture has infected other languages, notably PHP and C#.
- p2detar 6y agoFunny, I write both Java and Kotlin code. My Java code has 0 AbstractProxyServiceBuilderFactory classes. But then again, I don’t follow the common Spring culture. In one of my earliest jobs, I used to write j2me games. The code had 0 new allocations, mostly static stuff neatly organized in final classes. All of this due to hardware limitations. My point is, the language != culture.
- cutler 6y agoThat's fine when you work solo but Java, more than any language, was designed for teamwork and that's where what's idiomatic tends to weigh heavily.
- p2detar 6y agoI'm sorry if I implied that I do solo work with Java or j2me. That was/is rarely the case. But I don't really understand your point about idiomatic. Modern (new) languages, like Kotlin or Go, are less intended for teamwork or less idiomatic? That can't be true.
- elric 6y agoOne of the hardest parts of software architecture, in my mind, is striking the right balance between YAGNI and future-proof abstractions. Abstract everything to death, and you end up with what OP is describing. Abstract too little, and your codebase becomes rigid, hard to test, and so riddled with details that new developers will fail to see the bigger picture.
- ozim 6y agoI would say problem is that people worship DRY like it is some kind of golden rule. Where KISS, YAGNI and "premature optimization" are left in the corner crying. Pointing out DRY is easy and during code review all devs know that someone will be nagging about it. Where if you build an abstraction even if not needed or plain wrong there is a high chance that no one will have any comments, because reviewers will go with low hanging fruit and point out DRY violations. It will be more work to find out how abstraction work and point out its weakness, and don't ever even try to propose that code duplication might be a better solution than broken abstraction. Whenever I can, I try to push rule of 3 for dealing with duplicated code. Unless something is used 3 times it still is not a duplication.
- oftenwrong 6y agoToo little abstraction is rarely a problem. It's easy to change something simple and straightforward. When a bunch of stuff depends on a bad abstraction, it's both hard to change, and hard to keep.
- tarkin2 6y agoAbstractions, I think, should not be forced. They should evolve, parameter by parameter, as more and more configuration is needed in the original application, until they can be effortlessly lifted to another application. Everytime I've thought: "I'll abstract this so I can one day use it elsewhere" it's ended in failure--a working but overengineered, complex solution that I'd rather leave where it is and start afresh rather than reuse.
- rossdavidh 6y agoI was once told: never make the abstraction to something, until you're ready to make the 3rd instance of it. The reason is, that until you're ready to make the third one, you not only don't know if it will ever really be needed, but you also don't really know which parts of the thing really need to be different/customizable. If you abstract it before then, even if you do end up needing another someday, you will find that the way you abstracted it is the wrong way, and you will need to rewrite all the associated code anyway. Until you're making your third one (of whatever), don't make an abstraction for it.
- tarkin2 6y agoGood and pithy advice. I’d expand it slightly: “Until you’re making it a third time, don’t abstract, because you won’t yet know the what or the how.”
- chongli 6y agoThat’s sound advice for the day-to-day of programming but I think it still misses much of the power of abstraction. If you choose a different abstraction you might find a completely different way to express your solution which could be orders of magnitude less code. Perhaps the most absurd example of such a thing I can think of is when people figure out they can replace some gigantic mapreduce cluster with an awk one-liner and have it actually run faster.
- officehero 6y agoIs this related to the "build things that don't scale" motto? That one was conceived for startups in general if I remember correct. Is this same thing but in more detail?
- finikytou 6y agoeverything there applies as well to components frameworks like angular. most of the angular apps I have seen have more abstraction levels than Russian dolls. Components in Components in Components. It's like the dll hell remade for the browser
- oftenwrong 6y agoIt's inconceivable to me that one could write an article on this topic without mentioning Spring and Spring Boot. In many cases, it serves as a pre-built set of over-abstractions, and a great way to burden oneself by forcing all solutions to fit into an abstraction somebody else made. Like most major frameworks, it is undoubtedly convenient for throwing something together, but not conducive to making something well-crafted and maintainable. In my view, it is fine if you keep your code independent of it, but in my experience that rarely happens, and the code inevitably ends up as "a mess that works", and that can't easily be cleaned up.
- mattgreenrocks 6y agoThis is the result of every framework I’ve ever seen and used. It is just more apparent in Java due to being constrained to “OOP.”
- speed_spread 6y agoSpring works as a maintainable abstraction because it is known well enough within the industry that you can look for, and find, "Spring programmers". The framework's documentation, tests and release notes work to create a relatively coherent layer above the language, which would end being recreated a thousand ways by just as many creative coders if it didn't exist. Most of these in-house frameworks would be undocumented, poorly tested and unmaintained as soon as the lead coders left that department. Even for these standout projects that would be arguably better from a technical standpoint, none would offer the social advantage of a ubiquitous framework such as Spring provides. The desire to write new code is often so strong that I've seen Spring being itself re-wrapped in a local flavored "frameworks" that only brought value by ignoring parts of what Spring could do out of the box. The solution is most often to strip off the overwrapping and bring the app back to Spring primitives.
- logicslave 6y agoHonestly, after using spring and lombok annotation processing, I cant stand Java without them. So much code and functionality gets auto generated, the value is huge. Its just that if you havent worked with them before it looks like a huge abstracted mess.
- chrismsimpson 6y agoYou can't be a purest OOP or functional developer and also hold high the values of launching early and often (in my opinion). Instead, I think the pragmatic path ahead is codebases that balance and blend these two disciplines well, and largely use the GC (or reference counting/whatever mechanism exists) for managing resource allocation across an entire stack. That is to say, you intentionally use classes and all the baggage of OOP when you know a part of a given implementation resource and throughput heavy. Otherwise, the default 'starting point' when implementing something is to start with value semantics. It's fair to say many mainstream languages are adopting this approach. Swift is extremely functional, C# 9.0 adds record types, Go and Rust are largely functional but you can do OOP style things with them. Java I feel has reached an evolutionary dead end and will be the 90's answer to COBOL.
- throwaway777773 6y agoA lot of these abstractions come from consulting companies that need to pad their hours. I used to think it was very intelligent developers indulging in intellectual masturbation, but I’ve seen it happen too often to be a coincidence: some complex CQRS Mediator pattern on a small project where there will only ever be one implementation, or to facilitate unit tests that add dubious value. Not surprising in a field where ethics are a distant second to money.
- ternaryoperator 6y ago>The new features people ask for never seem to line up with the layers in your code. This has been my biggest objection to many tutorials, videos, and books on OO, architecture, and patterns: They're useful for greenfield code, but so often in large systems, they are nearly impossible of implementation. The trouble, of course, is that it's nearly impossible to teach how to do these things inside large codebases that are layered in ways that don't align with the intended change. Consider that other than Michael Feathers' book, there are few, if any, good books on maintaining code. And so we all struggle, and code becomes progressively more imperative and less coherent.
- hinkley 6y ago> They're useful for greenfield code, but so often in large systems, they are nearly impossible of implementation. This has been true of framework after framework, especially during that era, but we still have them regularly today.