I always find it fascinating looking at the number of lines of code which do the same thing in different languages. Foundationdb maintains official bindings in Java, Go, Ruby and Python. The implementations have almost complete feature parity. They're all maintained by the same team, and as far as I can tell they all follow best practices in their respective languages.
The sizes (minus comments and blank lines) are[1]:
Python: 4053
Ruby: 2397
Go: 3968
Java: 10077
38% seems like a lot but language expressiveness dominates that. If ruby and java code were equally difficult to write, you'd be paying a 320% tax moving from ruby to java for an equivalent program.
I'd love to see a "programming language benchmark game" that only allowed idiomatic code and compared languages based on code length.
I have no idea what the equivalent size ratio is for javascript and typescript, but having worked with both, I find typescript projects end up bigger. I write more typescript because the type system and the tooling encourages verbose and explicit over terse and clever. (In typescript I end up with more classes, longer function names and fewer polymorphic higher order functions).
The typescript tax is real. That said, I believe the defect rate increases by 38% too. Depending on what you're doing the tax might be worth it.
[1] Measured from commit 48d84faa3 using tokei "code lines". Includes JNI binding code and makefiles, but not documentation
Do they have a Haskell or OCaml client? I'd expect them to be fairly terse and have even better compile-time and run-time guarantees.
Whether it’s true or not, it would be interesting to consider languages in their ability to produce correct code more quickly.
While I don’t like the idea of writing 3x the amount of code, if one implementation is only 30% longer, for example, and is more likely correct on the first run, it’s still a huge productivity improvement.
I find that whatever "savings" there are in terms of code volume in dynamically typed languages is usually more than made up for in the need for more tests.
Look at a file like this: https://github.com/apple/foundationdb/blob/master/bindings/j...
You have equals, hashCode, toString which are all uncommon in other languages.
Yes. I'm making two claims. First to disagree with the GP's claim that a 38% difference between languages was 'whopping':
> What greater 'tax' could you possibly conceive of than a whopping 38%
The fact that the type system isn't entirely to blame is also clear looking at the ruby and python sizes. Ruby and python have very similar type systems, but the ruby code is only about half the size of its python equivalent.
My second claim is that if we did the same comparison with javascript and typescript, typescript would be bigger. I don't have any stats for this though - just lots of experience. The type system seems to push code in a bit more of a classical OO direction because there aren't higher kinded types, associated types, or any of that fun stuff.
As others have said it'd be fascinating to compare typescript and purescript / elm codebases. I'd expect the haskell-derived languages would come out way ahead on expressiveness. Its constantly surprising to me that we don't have any actual numbers.
??? You're comparing LOCs and number of bugs. That 320% larger java code might have 50% less bugs and may have taken 50% less time to write. Terse code is harder and usually takes longer to write than expressive code.
I also wonder how many Java "lines" are just a closing brace or something trivial.
In my opinion whatever perceived tax a type system entails is superficial—sure, coming from a dynamic language, having to specify types for everything seems like taking on an extra chore—but this is just the surface experience of using a type system—once you’ve used one for a while and furthermore, had the benefit of reading typed code, you really start to appreciate having types around and any so called “tax” involved quickly becomes negligible.
While it might be a “tax” when writing code it’s defintely a boon when reading code—it’s much faster to look at types to get a handle on an api than it is to have to dig through and read the actual implementation to try and decipher what exactly a function expects and returns. When using a Haskell library, for example, I rarely ever have to read documentation extensively or read implementations—looking at the types of functions and a brief description (one sentence) is often sufficient. It takes a couple of seconds. This is the norm with Haskell code. Contrarily, this is an exceptional case for dynamic languages—if the documentation isn’t superb you always wind up having to peek at the implementations at some point—this typically takes longer than glancing at types and a one sentence description.
Dynamic languages might be more “expressive” from a writers perspective (since you can leave out types) but they’re far from expressive from a readers perspective—since the writer convenience often puts the onus of sussing thing out on the reader. In enterprise systems, reader convenience is arguably more important.
It is. Number of bugs per line of code is nearly the same across languages. So the best way to reduce bugs is to reduce LoC
1-line Perl programs are far from being representative of real systems and generally only exists for code golfing.
Has this been studied?
In the original post AirBnB said 38% of their bugs could be prevented by static typing. This would bring this to 0.9-3%. Not insignificant, but LoC is still more important.
You might be interested to hear about type inference.
You just described the old Debian language benchmark game. You could select the various coefficients to apply to code size, program speed etc. I remember it played an important role when I decided to give OCaml a try: I selected 1 for size, 1 for speed, 1 for RAM and zero for everything else, and that resulted in OCaml and Pascal, the two languages I was prejudiced against from school years. Of course I went with OCaml.
From the same era:
http://blog.gmarceau.qc.ca/2009/05/speed-size-and-dependabil...
Also relevant: https://redmonk.com/dberkholz/2013/03/25/programming-languag...
Everything is just taxed differently. No such thing as duty free programming.
{
and }
it hardly does that.You might have also noticed that Go is statically typed, and it's actually less lines of code than Python (maybe a lot less if trailing braces are counted in that LOC number).
Is there a link where they say they spent 38% of their development time on this? The slide just says 38% of bugs and fixing bugs is not the only way development time is spent and not all bugs are equal in terms of time to debug.
The kinds of bugs which TypeScript prevents are those which could have been caught by the simplest of integration tests using the simplest inputs.
Every time I rename or change something in TypeScript, I have to change it in so many different places. In JavaScript, changes where much more localized.
No there is not. The comment you're replying to has no factual basis for this claim.
Nor is there a basis in the article for 'what these Javascript devs are calling "The Typescript Tax"'. In the article there's one comment that refers to such a tax, but the commenter doesn't claim to agree, and every reply disagrees.
Nor is there a basis in the article for "Surely Node.js is going to be looked back upon as one of the worst mistakes in the history of 21st century programming." The article says nothing about the total quantity of bugs, bugs per line of code, or other comparable metric.
The comment you're replying to seems to have a predetermined agenda tangentially related to the article.
Why is that? There were dynamically-typed backend languages long before Node.js became popular. And you now can easily have a TypeScript-based Node.js backend, which gives you the nice benefit of having the exact same language and types for both your backend and frontend. I'm not saying the Node runtime is perfect, but I don't understand why having a runtime that lets you use JS/TS as a backend or local language is quite such a bad thing.
Edit to add: on further thought, I think it would be a mistake not to look at dependency management and type-safety at the same time. If my external dependency exposes a defined interface, that gives me more information about that dependency which I can use to manage it (replacing it, for instance) than without.
Another thing to consider is that maybe you might not need a given dependency. Sometimes it is faster to include a bunch of dependencies at the beginning of a project just to produce something functional in the shortest time. As a product matures there is a lot of opportunity to clean up the code and slowly refactor the code to not need certain dependencies.
Then again, I’m a big proponent of avoiding “undifferentiated heavy lifting” at every layer of the stack.
As an example using a framework to avoid touching the DOM is an external reinvented wheel. As a leaky abstraction the need for that framework may dissolve over time as requirements evolve. That evolution of change can result in refactoring or a growth of complexity. Accounting for those changes means reinventing the same wheels whether or not the abstraction is in place. That is because a framework serves as an architecture in a box, but if you are later making architectural decisions anyways you have out grown at least some of the framework's value.
Instead provide a business (not code) template to define requirements for integration. This should define what is needed in their documentation, what they output/return, their inputs, automation test requirements, and so forth. That list delicately does not include code style or any more of vanity. Most of this can be automated but you need code reviews to hold people to account and to use as a training opportunity. Be honest and critical during the code reviews. If people find respectful honesty offensive talk to them about it outside the group and if they still can’t get with it transfer them out of your team.
And on the backend, if one developer liked log4net for logging, the other Serilog, and yet another developer likes to build his own logging framework that’s okay?
Let’s take this to a logical extreme, since one person is an old school VB developer and another likes F#, let’s just do that and throw in a little COBOL.Net for good measure....
And when a new dev comes in snsr takes forever to ramp up. No big deal. While we are at, let’s not follow the REST semantics either and no one needs those pesky frameworks like Express and ASP.Net. Let’s just go bare metal...
Or you could just have agreed upon standards....
If you’re going to have standards anyway, why not just use frameworks where you can open a req for the required framework that lets you get some developers who you can make sure already know the basics?
You’d be surprised at how many cheap developers you can get to throw together your yet another software as a service CRUD app using React.
The expectation is that developers are literate in their line of work, even though most companies don't hire like that. Since developers are expected to be literate don't waste time worrying about how to write code. If a developer suggests a tool that helps them on the "how to write the code" reject the tool.
Set business principles that specifically communicate the acceptable scope of work. Such principles can be something like this:
* code will execute within X milliseconds.
* code will allow up to X total dependencies (choose wisely).
* code will not exceed X bytes total size. If they want to include jQuery their code solution just increased 69kb.
The common failing is confusion around standards. Many developers find it easier if everybody just did everything the same way so that things appear standard. That approach ignores everything relevant to product quality and the goals of the business, which is stupid. It is stupid because it sacrifices simple for easy at the lowest level of leadership by lazy or weak managers. You don't get to offload management onto a framework and still hope to be a strong effective manager. Ultimately the success of a manager is tied to the work of that manager's team whether the team can retain/promote effective people.
When you set concrete and specific business limitations the limits are easily understood and based on objective criteria. Innovation and creativity are not stifled as developers are free to work within the constraints anyway they please.
This all makes sense once you accept that the group is worth more than the individual, but the product is worth more than the group. Sacrificing business goals for group cohesion is backwards just as sacrificing group integrity for an individuals option is backwards.
> You’d be surprised at how many cheap developers
That is also a common failure. Developers are never cheap unless you offshore. In hoping for cheap you will actually get developers that cost the same, do crappy work, don't value themselves, and that aren't valued by the organization. That is toxic. Instead hire people with potential to do great things and manage them effectively.
:)
As opposed to 86 percent of all statistics, which are basically made up. (Or presented grossly out of context, which is pretty much just as bad as "made up").
Seriously, it takes a lot more to trigger an assessment of "whopping" significance in my mind than a side-angle photo of some random slide presented with no background context whatsoever.
Surely Node.js is going to be looked back upon as one of the worst mistakes in the history of 21st century programming.
Wholehearted agreement with you there, at least.
Why? You did not elaborate on this.
You seem to have arrived at the opposite conclusion, which is that developers would require the same (or more) effort to prevent and fix these bugs while using TypeScript. I think you've missed the fact that most type issues don't take that much effort in the first place. Once you set up the "guard rails" by making a decision about types (or just assigning a value to a variable), writing the rest of the code is pretty effortless.
I would take it a step further and say that TypeScript development is actually more productive than plain JavaScript. (Again because of the better autocompletion and instant type checking in my editor.) I make far fewer mistakes, but I also write code faster.
Lost reputation is much, much worse than being wasteful with dev hours.
That can work - see Twitter.
Unless I’m working at a job where I’m serving some greater good, my definition of success is did I help achieve the company’s objectives, get paid well, and will I be able to use my coworkers and management as references in the future.
No matter how great my Perl code was running 15 years and 5 companies ago, I doubt they are still using it.
The code that runs Amazon.com, Google.com, etc. is nothing like what they ran 10 years ago.
Besides, we aren’t talking about feeding starving children here. We are talking about the death of a social media platform. But more generically, if yet another software as a service CRUD app dies, whose hurt besides the investors who expect most of their startups to fail and the developers who can walk down the street and get another job in a week?
As an individual, why am I going to fight the loosing battle of trying to implement great code quality and test coverage when I’m being incentivized by how many features my team can pump out as cheaply as possible by hiring a bunch of poorly paid developers overseas?
We call what we do “engineering” but there is a world of difference. If my program fails that is running a SAAS app, the user gets a 500 error. If a mechanical engineer rushes, people die.
In practice though, most companies never seem to polish a shipped feature -- they instead focus on adding more mediocre features.
I would love to see this trend reversed of course! But software in our age seems doomed to short lifespans and mediocre quality.
The vast majority of user-seen bugs are not common. The common ones are usually caught with testing.
But the kind of type systems your average dev has to deal with improved a lot in their expressiveness since 90s. Type inference is basically mainstream, too. There are still things that cannot be described nicely, but they tend to be a lot more "magic" - the kind of stuff that lets you write code faster, but not necessarily write more readable and understandable code.
Type-inference has never been the cause for bugs in any languae.