Yep. A lack of typing puts an upper bound on the complexity of the code that effectively limits the line-count and relegates the language to 'glue' status. The reason is simple: typing functions as guard rails and guard rails are what keep you safe on the road when you are driving for 1000's of km. They have no function if you just putter about town at low speed.
High line count projects almost always gravitate towards languages with such safeguards built in because otherwise the accumulation of subtle errors leads to too many runtime issues, and typing takes care of whole classes of bugs.
IMO any mechanism that shifts that time of bug catching to development rather than operations should be preferred, ditto for any mechanism that forces a program to end when an undefined situation is detected, the closer to the root cause the better.
>A lack of typing puts an upper bound on the complexity of the code that effectively limits the line-count and relegates the language to 'glue' status.
I disagree. I work(ed) at two of the more famous Python shops: Yelp and Reddit. These companies have many millions lines of Python code combined. Also FB was mostly a PHP shop until they started Hack in 2014, 2 years after they IPO'ed.
Testing and monitoring can be used to combat type errors. Runtime type errors still happen occasionally, but honestly these are some of the easiest bugs to squash.
I think you might be conflating static typing with strong typing when you infer that Python has "lack of typing." Python has a dynamic, but strong type system.
I've coded professionally in many other languages (C, Java, Rust). I think C and Java have the worst ROI when it comes to type systems. In my opinion if you're going to use a type system on a new project today, then use something that provides stronger guarantees like Rust or TypeScript (and lowers the burden by inferring or deducting many types).
Python isn't perfect, but it's still the first tool I reach for anything web, ops or data science related.
And bricks will fly if you add enough engine to them. It's all a matter of resources and what is the optimal path. That FB was a success even though it was built in PHP is not a testimony for PHP, it is a testimony for the engineers at Facebook who were able to pull that off despite PHPs obvious shortcomings. The fact that they built their own in-house compiler for the language speaks volumes in this respect.
Yelp and Reddit also have above average resources to throw at the problems they try to solve.
Python is the first tool of choice for quick solutions to immediate problems for me as well, but that does not make me blind to its obvious shortcomings.
You’re completely discounting that PHP has qualities that may have helped early Facebook grow. In fact one the engineers did a talk about exactly that.
The language that you start in may not be the most appropriate tool in the longer term. Facebook grew so fast they did not have enough air to switch, hence their incredible investment in making PHP better.
Look, I've built I don't know how many websites in PHP, and my company still earns a lot of money with a tool I threw together in a day or two in it so I have nothing but admiration for what it can do. But you'll be the last person to hear me argue that there aren't better tools for the majority of the jobs at hand. We are all looking forward to the day that it can be retired, but in the meantime we will definitely keep using it and we will continue to pray to the PHP gods. It is a very productive little language that has a ton of warts and some serious issues, but it does have a niche and it is useful.
That's a fair point, I'm sure there are ways to build things that have the benefits of PHP today that may not have been as abundant back when Facebook was starting out.
I work at Pivotal, arguably one of the most test-obsessed companies in the world.
Tests and types are not direct substitutes. My view these days is that types become more valuable as a codebase grows. I have worked on Ruby on Rails codebases where, quite frankly, I found myself wishing it out loud was Java on Spring Boot. (Many of my peers in Labs are flatly enthusiastic about Kotlin on Spring Boot, FWIW)
In the same genus as the "just use tests" argument is "business logic only belongs in the app, not the database". Yeah, well, it turns out that no amount of testing is a substitute for constraints and transactions.
Yes, in my experience on coding PHP & Java is that everything is so cumbersome in Java with little gain coding wise (there are of course other benefits with Java)
Hard to move code around, comment out code, prototyping, create samples of data structures etc.
What is important on a large project is enforcing contracts, if it is on function calls, HTTP calls, database calls etc.
With function calls you have type hinting in many dynamic languages, with that you can catch most type errors & avoid writing some tests.
How the types work within the function body is quite irrelevant.
And statically typed languages have recognized this by adding var, auto & what not.
> Hard to move code around, comment out code, prototyping, create samples of data structures etc.
With some IDE skill, this is easy in Java, but then developers get used to this way of developing caused in no small part because of the language and think that features of the language (like static types) enable and entail the IDE features (auto-refactoring, intellisense, code generation), rather than the IDE features being developed partly in response to the limitations of the language.
Dynamic languages often have a tooling problem, at least from the perspective of Java developers, but often you don't even need those heavy IDE features to get equivalent or better work done and so tooling suffers or isn't evangelized much. A coworker complained he can't just find callers of a JS function (unless within the same JS file) with eclipse; I pointed out that vim trivially does this after generating ctags and demoed it... Still, in lots of code bases that aren't in Java, I find myself needing to know "who calls this" not as often. Besides, old school find | xargs grep or ag work to find that info usually too. Even better, if it's a Web Service name, a string-based tool will find the usages on both the client in JS and on the server in not-JS.
Meanwhile there have been dynamic languages like Common Lisp that have IDE features like debugging built-in to the standard language itself, there are strong types that implementations can and do use to produce optimized machine code (not just correctness -- and you can verify an optimization with 'DISASSEMBLE, another standard function), modern implementations like SBCL have at-compile-time warnings for type issues or typos or whatever, and ancient tooling (slime) has things to tell you who-called-what, etc.
I wouldn't think that you run into type errors often with a mature code base. But that's because you have to deal with this problem sooner or later. In a statically typed language, it is quite obvious what fits where. From my (albeit limited) experience with js, python and ruby, you have to invest a lot of effort into documenting and testing things like function parameters, which would be completely unnecessary in a language with static typing, even if that language has a boring, Java like OO type system.
When you test expected function behaviours, sufficient type testing tends to fall out of that pretty much for free - if your test suite is testing function parameters for the sake of testing function parameters and not for the sake of verifying it gets the right output, then the test suite is deficient.
> Testing and monitoring can be used to combat type errors.
I agree, though IMO this is another upper-bound. You can only test and monitor so much before resources and performance start becoming a bigger issue.
I think companies can definitely go without types if they have solid documentation and a good review system to both prevent bugs and help with onboarding.
What is the upside of having no types, though? We're out of C land and modern advanced typed languages offer generics, type inference, interfaces and inheritance. You can pretty much do whatever you need without ugly casting or compromising your data structures.
Dynamic typing solves things you have in C, not so much in C#.
In my experience: Far less up-front specification, far fewer names/concepts, fewer lines of code, far fewer of those "oh, this should work, but how do I wrestle the type system into understanding it?".
Now, there's a continuum here.
When designing the main data store for a project, you want to iterate on that and get it just right.
Or if you're working on a library to be used by lots of people, it's definitely nice to be able to specify things that lets the compiler help people get their code right.
On the other hand, in almost all the applications I've worked on, there's also a much larger fraction of absolutely necessary and often complex code where each little module is working on some details. There the data structure doesn't really matter so what JSON provides (untyped arrays + simple objects/dictionaries) results in much less cognitive overhead than a fully specified and typed thing. A few black-box tests both documents and checks functionality, and also ensures that the thing keeps working after a refactor.
Surely the most common argument was that dynamically typed languages need less lines of code to do the same thing, combine that with the time it takes to write code is roughly proportional to the size in lines, and the size of the unit tests similarly proportional, and it becomes a pretty hard argument to refute.
For a long while you were comparing languages line Python to something like Java, and it was pretty much a no brainer - the argument was right. But nowadays if you compare something like Javascript to Typescript, it's not near so clear. Type inference is really biting into the size advantage line dynamic typing had over static typing.
The other thing is the claim 1 line of statically typed code of takes as long to write as 1 line of dynamically typed code. It's true as stated, but change it to "correct line of code" and it's not true. You don't have to write tests for type declarations, and statically typed code has less bugs after it's accepted by the compiler / interpreter, so while the writing takes the same amount of time the testing and fixing takes less for statically typed languages.
The final advantage of dynamically typed languages is statically typed languages just need more head space - just ask someone who has used Rust. Granted Rust with it's explosion of types caused by lifetimes is a bit of an extreme case, but it's still true for most languages. But it's not so true for the Typescript vs Javascript comparison, and I suspect really careful standard library design might make this mostly go away too.
> A lack of typing puts an upper bound on the complexity of the code that effectively limits the line-count and relegates the language to 'glue' status.
That's an opinion, not a fact.
> IMO any mechanism that shifts that time of bug catching to development rather than operations should be preferred
That's probably true of an existing product, but that's not the only concern in product development.
High line count projects almost always gravitate towards languages with such safeguards built in because otherwise the accumulation of subtle errors leads to too many runtime issues, and typing takes care of whole classes of bugs.
IMO any mechanism that shifts that time of bug catching to development rather than operations should be preferred, ditto for any mechanism that forces a program to end when an undefined situation is detected, the closer to the root cause the better.