Some time back, someone here on HN posted a comment about rewriting a Java app in... Java. Same basic story of large savings, without changing language at all.
Studying the actual effects of language is hard (time/effort/budget beyond constraints), so people don't do it.
: "It is faster to make a four-inch mirror then a six-inch mirror than to make a six-inch mirror."
My favorite is when they make another post half a year later saying they changed from Y to Z.
It seems that following the trend and using the latest and greatest tools doesn't necessary mean the new tools are better, but that you got to rewrite your applications from scratch, with much more knowledge about the problem domain then before.
2 years later...
LinkedIn: Our iOS app is native! Simple and fast! We save money!
Sometimes I wonder if the real subtext is "we have such high turnover that almost nobody was around when the first system was designed. We rewrote it in a new language, and now we're all much happier because we all understand it much better, having been involved in its design." Wait a year, repeat.
Very rarely do I hit anything near to an optimal solution the first time out of the gate.
1st iteration: 'does it' (barely) but kinda looks hacky 2cnd iteration: better. actually works. 3rd iteration: looks clean, concise, pro, something to be proud of!
3rd time is a charm in software.
It's unbelievable how much clearer and more concise the code is 3rd time around.
If you can ever actually get away with this on a project ... highly recommended.
The modern counterpart is probably scalability — I see a lot of parallels in all of the Google/Facebook-envy applied to “big data” problems which can fit on an iPad.
If people keep trying to force code organization around the business jargon, they will keep getting the same awful result. It does not matter if they are writing OOP, Abstract Data Types, FP, or direct bits manipulation with assembly.
Unfortunately, explicit interfaces were a very late idea (at least in terms of implementation in a major language, not sure if the idea was around earlier) in OOP implementation, and wasn't on v1 of any major language as a core approach, so we've got a bunch of languages where we accept multiple inheritance being messy or we don't have MI at all to avoid it being messy.
But if you had exclusively explicit access to interface (including inherited) methods, MI would be clean.
- Apple, MacApp
- Microsoft: MFC, and others
- Borland: I forget what they called their stuff
- Anyone remember Taligent? Apple, HP and IBM, all getting together in a money-burning party...
- NeXT / Apple revival: NextStep / OpenStep, etc.
- Any number of minor players, including folks with Honest to Goodness Smalltalk implementations (none of which have survived to this day, I believe)
- Java stuff that I have mercifully forgotten
... they were nearly all crazy, and nothing was portable. So much for the promise of OOP :-)
Many C++ game engines also moved away from huge class hierarchies of game objects to property-based game objects that were collections of behavior handlers.
What is clear to me is that Rust does incredibly well without it, but wouldn't be hurt by having it. Most of the egregious sins of OOP are mitigated by having far better abstractions available in Rust. ML-style modules, ADTs with pattern matching, type classes, first class functions, etc. Much like scala, if you give them capable FP, OOP stops being abused and starts being used appropriately.
Rust traits and Scala traits (or abstract classes) are more or less equivalent with this one exception. I was just pointed to a proposal that would allow for this in Rust, but it is not yet implemented [0]. Essentially, you would be able to define type members, and then "link" them to a member of the struct/enum that is being "impl"-ed. While ergonomically not quite the same as scala, it is effectively the same as inheriting an abstract class with a constructor parameter.
(The gist was that avoiding mutation and keeping everything purely functional allowed them to roll back and forth in time with no problem, or try out multiple different futures. That's somewhat orthogonal to inheritance.)
[1] https://books.google.co.uk/books?id=ka2VUBqHiWkC&lpg=PA81&ot...
What we can do is compare similar types of projects in different languages. And the things we can say there are pretty significant. For instance, at my last job using Angular we experienced a particular bug in production a couple times. In my current job our frontend is written in Haskell. I don't make definitive statements that often, but in this case I can definitively say that there is a ZERO chance that bug will happen in our codebase. I can say that because the type system guarantees that that class of bug can't possibly happen.
The fact of the matter is there never will be absolute proof of these questions. The naysayers will always have straws to grasp at.
Every time I've been involved in a rewrite, including ones using the same language before/after, the outcome has been good. The act of doing a full rewrite is where the benefit comes from, it's hard to separate that from a language switch.
edit: To clarify this thought a bit, obviously you can transpile code in a type safe language to JavaScript. At the abstraction level of the code written, the project is type safe. The generated JavaScript itself is not; however this isn't a problem if the transpiler is correct. The same principle applies to Haskell compiling to non-typesafe machine code.
So, anyone doing this should consider trying to get a sample of people who are more or less indifferent between the options, so they don't sabotage the test
Right, yes. Perhaps this entire exercise is a complete waste of time. Perhaps we should be investing in skilled people who understand their problem domain and then just trust them to do the best they can, rather than trying to find silver bullets inside programming languages.
As we were going to do the rewrite anyway, we considered more alternatives than just Python. For programs that have to be reliable and maintainable, I prefer a language with a strong static type system. Haskell has that, and it has a few practical benefits over other tools that made it an excellent choice for our use case.
I think that is one of the big factors stopping that from actually happening with OO code. A rewrite is a lot harder if you tap into what exists elsewhere in the codebase.
I bet you have a lot more insight into this than me though.
In the end, it's all up the the programmer.
I was also until recently quite convinced OOP was the only way to go, but I'm seeing signs everywhere that a lot of the design-problems I've met over the past few years are at least magnified by OOP.
The abstraction promised by OOP is a good thing, however very few people are able to consistently make good, reusable and maintained abstractions. To the point where it becomes a weakness rather than a strength. I don't want a billion wrapper-objects that obfuscate my code, and makes the surface area of it bigger than it has to be. Often I struggle understanding code more because of how it was separated, than because of the complexity of what it actually does.
I liked Rich Hickeys talk "Simple made Easy" [1] and "Brian Will: Why OOP is Bad" [2]
[1]: https://www.youtube.com/watch?v=rI8tNMsozo0 [2]: https://www.youtube.com/watch?v=QM1iUe6IofM
(The actual argument for functional programming is its adoption by elite programmers like Standard Chartered's Strats team, Facebook's anti-spam group, and Jane Street as a whole.)
That said, isn't it also fair to say that with a better understanding of the requirements and problem, you may determine that a different language / paradigm is a better choice, in the same way you may decide a different class division is better?