Funny to see this considering my opinion is pretty much a polar opposite to Chris'.
In the last couple of years C# has gotten better than ever. LINQ, Lambdas & Generics combined with the IDE's autocomplete and refactorings have made the language really nice for power devs.
The next release will include a Compiler as a Service which could be a game changer if it's embraced by the community and if it's not borked by Microsoft.
A good rule of thumb for .Net is that anything from Microsoft which is built around a tool should be avoided like the plague. For example Entity Framework and WPF are horrible tool-bound monsters. They don't play well with version control, don't play well with clean coding (POCOs) and almost feel designed to sell other tools (SQL Server / Expression Blend).
Entity Framework is especially bad. It combines terrible performance, terrible scaling (it has terrible support for large schemas) and until recently didn't even support "code first" development.
Thankfully, like other dinosaurs that kind of thing is going the way of VB6.
To add a bit of context: I have a pretty broad background - been coding for 21 years (started at 10) and have experience implementing something significant in: C64 (BASIC/6510asm), Pascal/Delphi, VB, Java, PHP/HTML/JS, TSQL/SQL, C# and ActionScript/Flex. I've dabbled with Ruby and the beautiful Python.
I abandoned dynamically typed languages for serious projects (those expected to work for > 5 years) because of the poor refactoring support and the dominance of style over substance in the community. I work in the Enterprise, and there software maintenance quickly dominates the cost of projects making the big two static languages a better choice.
I still, of course, turn to dynamic language when they're the best solution to the problem. For example for situations where speed of development dominates returns (think opportunity cost) or where a language is deeply embedded in a specific community (Python and NLP).
I remember the joy of saying goodbye to the limits of BASIC when I switched to C. Ah, the power, the control....
After a while, I was sick of debugging memory and having to rely on "libraries" just to do anything useful with strings, and it was such a relief to discover Perl. Talk about power! I was suddenly creating little utility programs for everything. It occurred to me that I could have been writing these utilities in C all along but I never did because the time to write and debug them was more than the time they would have saved. What a joy to discover Perl (which then led into learning the Unix command line and its utilities.)
But after a while, I noticed how often I still had to look up the "clever" syntax of Perl. There were so many other ways to do things that I couldn't read other people's Perl without a reference book beside me and, heaven help me, sometimes I couldn't even read my own. That had never happened in C, But I wanted to create commercial GUI apps. Perl's answer? Use Tk? Yeah, right.
So, I switched to C++ for GUI apps, and what a treat to have that kind of power compared to Perl. But then I rediscovered memory debugging, what it's like to not have a string datatype, and I learned that the usefulness of OOP was offset by all the ridiculous little gotchas that meant you always had irreproducible bugs that you hadn't yet discovered.
What a relief when Java came out. Almost all the power of C++, plus built-in strings, arrays, even Unicode, but without most of the hidden gotchas. I could concentrate on the demands of the problem instead of the demands of C++. Like lots of programmers, I found Java much more fun than C++.
But of course there were things I missed--structs, enums, regular expressions, GUI apps that looked native--and every time I complained to Sun reps in a meeting, they would simply explain to me that they knew more about programming languages than I did, and they knew that I didn't really need these things. They held that position ("No, trust us, you don't really want that") for years.
But the Microsoft reps were always EXTREMELY interested in anything we wanted from Java but that Sun wouldn't give us. "What do you wish Java had and how would you use it?" They took lots of notes. Superb marketing.
When C# was released, it was with great relief that I finally got the language, native GUI app builder, and other things I'd been longing for in Java for so long.
Building GUI apps with C# is still a joy, but I'm always frustrated at being limited to Windows. I use Macs and Linux boxes, too, and Mono has never quite been what I had hoped for. I need to do a lot of web programming, cross-platform number crunching, and all sorts of things. And having to (repeatedly) buy all of those Microsoft tools and be a "registered developer" and all that nonsense, phooey!
Thank goodness, I found Python. Free, available on every platform, great built-ins AND great libraries.... Like Perl, but with a syntax I remember without looking things up. I can read other people's code without a reference.
But I wish it had the flexibility and macros of Lisp, the power I've found in functional programming, the easy GUI creator of C#, the speed of C... and a pony.
I understand the OP's feeling of relief at leaving annoyances behind. Believe me, I do. Every system I've used has had problems I'm glad to rid of and features I still miss. But that's what you get when you change a relationship, move to a new house, sell your car, get a new job. And, with programming languages, you can go back when you need to.
It's often good to move on, but it doesn't mean what you left behind was bad. Sometimes you just need different problems.
The idea of attempting to refactor a 100k+ loc codebase, without static typing and a compiler that can identify issues at compile-time versus runtime is equivalent to asking to be punished. If you must, consider that the role of a type-checking compiler is simply to perform a first round of automatic unit-tests, tests that are conveniently available after providing some typing annotations. To escape static typing - if there is a demonstratable and exceptional need (loose coupling), simply wrap the required events up as objects and switch and downcast on them with enums or use a visitor pattern.
Unfortunately associating dynamic languages like ruby, python and javascipt with some narrative of hacker agility and contrasting against a clumsy slow-moving 'enterprise' culture is confounding the issues. This is not to say that there aren't plenty of vendors/consultants selling FUD and over-hyped and over-complicated 'solutions' in 'enterprise' but it's a non-technical issue.
First, lets assume your 100k+ loc codebase would be about 10k+ loc if coded in most of the "overhyped" languages. That's the primary reason there are not that many huge codebases in them - huge codebases aren't needed. That's also a reason no multi-year development is done with them - it just doesn't last that long.
Next, remember not having to upcast and downcast objects considerably simplifies the code, simplifying the tests you need to write. Less code means less places a bug can hide.
And, finally, understand that, while not passing compilation proves your program is wrong, passing it doesn't make it any closer to correct.
Trust me. I've seen enough "enterprise" codebases in my life. They aren't that special.
Assumption #1: 100k+ loc codebase in X == 10k+ loc in Y (somehow... magic)
Assumption #2: Assumption #1 is the primary reason not many huge codebases in Y
Assumption #3: Static type implies upcast/downcast objects (despite the presence of generics...) == simplifies code == simplifies tests.
Fact: Less code == less places a bug can hide
Fact: BTW! we all are using tried-and-tested libraries to cut down code to be written
Fact: FindBugs (or static code analysis) does actually find bugs to eliminate most technical bugs and leave you with business logic (and quite possibly race condition bugs).
Argument: Compiler isn't special, see, I just show you it doesn't proved your code to be correct, there's the logic bug in your Business Logic. (Except that happens as well in dynamic language, AND on top of that you gotta work a little bit extra since you ain't got no compiler).
I think this has become your typical nerd holy war between static vs dynamic with no end.
Here's my biggest problem with Ruby or Python community: your libraries tend to have short-lived (i.e.: orphaned).
When I looked at Java community, they're quite stable and rock solid since 2004-2005 (Apache Commons, Maven, Ant, FindBugs, Eclipse, EclEmma, Spring Framework family, JUnit, Hibernate). Newer libraries tend to have good internal codebases (GWT, Google Guava, Mockito). Most APIs are stable and solid.
The stupid ones tend to get kicked out of the crowd (i.e.: Struts, JSF)
This is what I'm looking for. I can focus on writing code that matters, instead of refactoring my code once every 4 months because things changed and I have to keep up.
> Assumption #1: 100k+ loc codebase in X == 10k+ loc in Y (somehow... magic)
Have you ever worked with any significantly complex (as in "does a lot of stuff") in Ruby, Python or Smalltalk? Do you sincerely think you could express that same level of functionality with C, C++, C# or Java?
> Assumption #3: Static type implies upcast/downcast objects (despite the presence of generics...) == simplifies code == simplifies tests.
Generics are nice until you have to implement something that accepts them. I gave up once.
> Fact: BTW! we all are using tried-and-tested libraries to cut down code to be written
And language features that do just that (see Assumption #1)
> ... static code analysis) does actually find bugs
Actually, they are one step above syntax errors.
> Except that happens as well in dynamic language
No. Not really. Of course, I may pass a list to something that expects a file but, provided I embraced the idea of duck typing, that would probably work just fine. And yield correct results.
And avoid implementing a similar function that receives a string instead of a file.
> AND on top of that you gotta work a little bit extra since you ain't got no compiler
Most errors a compiler catches are traditionally caught in tests with dynamic languages. But having compilers doesn't allow one to skip writing proper tests with statically typed languages. In fact, considering you'll have to deal with more situations, you'll have to write more tests to go with your less concise code.
> I think this has become your typical nerd holy war between static vs dynamic with no end.
I think statically typed languages have their place. I have written tons of C and Java (and a bit of C#). I just admit my ST code was not significantly better than my DT code and was considerably more complicated, with more functions, classes, interfaces, configurations, indirections, and much more verbose. The 10x loc difference is very real. In the end they were all, ST and DT, correct.
> Here's my biggest problem with Ruby or Python community: your libraries tend to have short-lived (i.e.: orphaned).
I'm nos as familiar with Ruby (the language mentioned in the article) but I can tell you Rails (the framework mentioned) is very solid and very well maintained. Compatibility can be broken from time to time, mostly for good reasons. And you don't need to rush to update your code - you can be perfectly happy using older libraries. I can tell you, however, Python libraries are remarkably stable. The impending move to Python 3 is the only significant example of code breakage, but, again, it's for great reasons.
> they're quite stable and rock solid since 2004-2005 (Apache Commons, Maven, Ant, FindBugs, Eclipse, EclEmma, Spring Framework family, JUnit, Hibernate).
A couple of them gained significant functionality in the past couple years. If you want to use the new functionality, you'll have to refactor your code, often extensively.
> I can focus on writing code that matters,
Ditto here. I just write less code (in less time) for the same amount of "matters"
> instead of refactoring my code once every 4 months because things changed and I have to keep up.
With the extra time you get by writing less code in less time, you certainly have the time to refactor. With good tests, you have the certainty the refactoring was successful. Besides, nothing is compelling you to switch to incompatible versions every 4 months (I don't even think that's possible unless you are doing so deliberately). What is the problem here?
I use Guava extensively and it has helped me quite significantly to reduce some of the code normally Java developers wrote.
I use Rails for CRUD app and I use Spring MVC too.
I used Python a lot a few years ago from writing tools (testing, scripting, automation), to small web-apps.
Saying that 100k can be cut to 10k (or 1k) is like pulling number out of thin air, that's what I find... "magical". It's like some CEO of a startup giving a deadline to the developer to write Hadoop in 4 hours; pulling the number out of thin air.
Compiler => helped syntax errors and types (95%, 5% consist of reflection hackery that might bite).
Static code analysis => One level up from syntax errors, focused on common pitfalls and bug patterns
One step, two step, three step, doesn't matter, it helps, that's the bottom line.
What I refer to "except that happens as well in dynamic language" is to the business logics, the app logics, not syntax and whatnot, you _got it wrong_. We all got business logics bugs that can't be caught by anything other than testing the app themselves (QA, automation, whatever).
So we agree that dynamic languages requires you to write more testing code because there's no compiler? Gotcha.
I never say anywhere that using a static language requires NO testing.
What I found is that a bunch of old-timers who wrote Java back in 98-2003 and didn't use more modern Java frameworks and tools but already jumped the band-wagon to Rails or Node.js keep singing the same tune.
When I use Rails, then Spring MVC + Spring Data, I noticed that the amount of business logics that I have to write is more or less the same. 10x is again out of thin-air. I admit writing code in Java requires more typing albeit Eclipse helps a lot (and please don't bring the old argument of "But You need an IDE!", who cares what I need as long as it helps me to do my job).
Picking one example to refute the epidemic that occurs in the ecosystem is probably not a strong argument (Rails is well maintained, I give you that, although it takes Rails up to version 3.x to realize that they need to cool down and stabilize but I give you that, but that doesn't mean the other plugins and libraries are held the same level of quality and commitment with Rails).
> So we agree that dynamic languages requires you to write more testing code because there's no compiler? Gotcha.
No, we don't. I never said that. Since there is less code structured in simpler ways, there can be less tests (there are less code paths). Since the tests themselves are written more concisely, the tests themselves are smaller. The syntax errors will be caught in the tests because most dynamic languages actually compile the code. They just do it as needed.
Again, the 10x number is not out of thin air - we keep a lot of Java applications here and, more than once, we rewrote them in dynamic languages. We saw better than 10x ratios, although with the more recent, nicer Java code is more like 5x.
> Picking one example to refute the epidemic that occurs in the ecosystem is probably not a strong argument
I am not very familiar with the Rails ecosystem, but if most of the libraries someone picks tend to be abandoned, maybe the problem isn't in the libraries, but in the selection process.
If 90k of your 100k codebase is generated code - and there's a good chance that it is - then the size of the codebase is no reason to switch to an interpreted language.
Are you sure generated code is a good thing? Isn't it just support for limited expression power, something you shouldn't be able to get away with in your language of choice that your tools help you with by writing lots of code that are required to express what you intended?
Wouldn't it just be nice if you could get away with just the code you wrote?
Static typing is not a pre requisite for quality code. Quality developers is. If you have your codebase maintained properly, maintenance is easy and cheap.
(Hint: don't argue with me at this point, it's just random geeks meaningless debate. Really. I mean it. Y'all don't have a good proof that dynamic typing implies better developers or static typing implies bad developers and I'm a bit tired to hear "Good developers, not tools" that kind of crap when most Python/Ruby developers are just as average as Java developers).
> Y'all don't have a good proof that dynamic typing implies better developers or static typing implies bad developers
I never said (nor implied) that. I said dynamic typing leads to more concise and readable code. Most of the time, you'll be reading the code, so, it makes sense to optimize for readability.
> most Python/Ruby developers are just as average as Java developers
Wouldn't it then make sense to give them better tools? I don't use Python because I'm better than my colleagues who prefer Java - I use it because I want to get the job done and keep it done with less effort.
The argument of "readable" code is like saying Steak taste better than Chinese food: it depends on your audience.
I used to buy the whole dynamic language argument (heck I even lead local Python user group) but not any more these days.
To me, Ruby is less readable than Python. To me, when reading a large code base, Java is more readable than Python. To me LISP is weird (even though I kind of like it).
Now you said "it makes sense to optimize for readability" the problem with this statement is that less code != readable code (and I don't mean to jam everything in one line a'la Perl). I find that I need to read, re-read, think, and re-think a few times just to understand what the Ruby crowds refer to short, concise, and elegant code.
Whereas in Java, albeit more terse, I can just read within seconds to know the intention of the code.
So it all depends. Hence me not buying the dynamic vs static debate.
> the problem with this statement is that less code != readable code
Never said that. When writing code I never go for the least possible number of symbols (if I did, I'd write traditional APL). Still, more concise code is often closer to what you want done than the details of how you'll get it done. While I find Ruby's syntax a bit confusing at times (and that's why I prefer Python) I cannot deny idiomatic Ruby is very close to intention than to implementation (to a fault).
Perhaps that's because most people who think that the claims are BS have never worked with codebases that are expected to exist and be maintained for at least a decade with minimal downtime.
Within large companies those types of codebases are normal. The upfront development cost of applications is significantly less than the long term maintenance cost - especially once you've factored in the cost of hardware over the time period, and having to keep institutional knowledge of the applications amongst development teams, sys admin teams and network teams.
Oh I have worked with codebases (in large financial institutions and in engineering applications) that are meant to be contiguously maintained for more than a decade. They have been working nicely 16+ years and are easy to maintain with no downtime. Obviously, none of it involves the CLR or .Net. On the other hand, I've also seen seriously big projects ruined by .Net with no handover or documentation. But worst, no accountability. I've also seen a few successful ones but I would expect that culture to deliver continuous quality -- but it surely hasn't.
That's why I am saying that most of these claims people bandy around about enterprise computing are nonsense.
We don't do marketing BS since well.. we'd like to use Rails occasionally as well.
All I can say is that YMMV since this debate typically goes to no end.
If we have a super-hacker on our team that can fix any problems ranging from C to Assembly to Linux Kernel to everything under the sun, we'd take the risk of using cutting-edge technology such as Node.JS to do SOAP/WS-*. Otherwise, it's all Java/.NET plus outsourcing the risk to Microsoft/IBM/Oracle support when shit hits the fan.
Certain things don't apply to internet companies by the way. They can write a SOAP library, put it on Github and blog about it how much they save the money but Enterprise project has deadlines and impatient customers.
It depends on what you're building. That's why it's good to know a broad range of languages : you can pick and choose the best options from the general purpose languages, or use your knowledge to build your own simple DSL..
When appropriate : language/framework choice depends on more than just technical factors...
In the last couple of years C# has gotten better than ever. LINQ, Lambdas & Generics combined with the IDE's autocomplete and refactorings have made the language really nice for power devs.
The next release will include a Compiler as a Service which could be a game changer if it's embraced by the community and if it's not borked by Microsoft.
A good rule of thumb for .Net is that anything from Microsoft which is built around a tool should be avoided like the plague. For example Entity Framework and WPF are horrible tool-bound monsters. They don't play well with version control, don't play well with clean coding (POCOs) and almost feel designed to sell other tools (SQL Server / Expression Blend).
Entity Framework is especially bad. It combines terrible performance, terrible scaling (it has terrible support for large schemas) and until recently didn't even support "code first" development.
Thankfully, like other dinosaurs that kind of thing is going the way of VB6.
To add a bit of context: I have a pretty broad background - been coding for 21 years (started at 10) and have experience implementing something significant in: C64 (BASIC/6510asm), Pascal/Delphi, VB, Java, PHP/HTML/JS, TSQL/SQL, C# and ActionScript/Flex. I've dabbled with Ruby and the beautiful Python.
I abandoned dynamically typed languages for serious projects (those expected to work for > 5 years) because of the poor refactoring support and the dominance of style over substance in the community. I work in the Enterprise, and there software maintenance quickly dominates the cost of projects making the big two static languages a better choice.
I still, of course, turn to dynamic language when they're the best solution to the problem. For example for situations where speed of development dominates returns (think opportunity cost) or where a language is deeply embedded in a specific community (Python and NLP).