
The memory safety problem isn't bad coders - steveklabnik
https://medium.com/@sgrif/no-the-problem-isnt-bad-coders-ed4347810270
======
_bxg1
I remember when I first added ESLint to our large JavaScript codebase, and
then again when I added Flow. I'm a perfectionist when I code, but it was
shocking to see some of the things I'd written. Mistakes that I thought were
so unlike me, but had been sitting there for months anyway, waiting to blow
up.

The human brain wasn't designed to handle the complexity of large codebases.
There are just too many compounding implications of everything for us to hold
them all in mind at once. The very best coders miss things all the time.

Instead of seatbelts, I would compare tool assistance to aviation instruments.
It's not primarily something that just catches you before a disaster; it's
something that helps you make the most effective use of your mental resources.
We don't ask pilots to fly commercial airliners without advanced software and
dozens of readouts and displays to guide their attention and decision-making
in an overwhelming sea of information. We shouldn't expect the same of
programmers.

~~~
phaedrus
The comparison with aviation instruments is apt: I remember seeing a TV
special that talked about how in the early days of aviation (circa WWI) the
pilots' culture of seat-of-the-pants flying and bravado was resistant to
suggestions that human senses are just not equipped to differentiate between
certain inertial reference frames, of which one leads to getting into a death-
spiral.

It was not until an early aviation safety pioneer came up with a demonstration
on the ground (something like a spinning chair and blindfold - I forget the
details) that pilots who went through the demonstration were shocked to
discover they "fell for" the physical illusion they believed they were immune
to.

I feel like programming is in the same state today. Especially the more C/C++
code I see in my career: I'm _absolutely convinced_ humans should just not
expected to manually manage some of the things they try to do now.

~~~
_bxg1
C/C++, and in many cases Lisp, seem to be the most entrenched communities when
it comes to the "culture of seat-of-the-pants flying and bravado". For
contrast, JavaScript has as much flexibility and nearly as many foot-guns as
those languages, but its community has been much more receptive to safety
rails and static analysis. (Hopefully this doesn't start a flame-war; that
isn't my intention)

~~~
AdeptusAquinas
How. Dare. You.

More seriously, JS has had its own resistance movements. TypeScript was
actively disdained until, as far as I can tell, Angular switched to it.
Probably partially because it was MS, but also because there was a lot of
resistance to static typing despite the demonstrated safety benefits.

~~~
cm2187
Doesn’t static analysis requires static typing? There certainly has been a
strong resistance to the introduction of static typing in the js community.

~~~
core-questions
I'm not a very good developer, though I do have plenty of released-and-
working-well things out in the world. I will say, it seems to me like static
typing would reduce my creativity and flow and require me to spend more time
planning stuff, which is not fun, and would make updates take more time as I
patch stuff in all over the codebase. It's sort of the polar opposite of Ruby-
style "duck typing".

Do they really help enough to be worth it?

~~~
Zarel
I'm actually kind of surprised that programmers, of all people, would oppose
guard-rails.

At university, it was a meme that no one's C program ever compiled the first
time they tried.

I can't imagine even the best programmer in the world can avoid that kind of
problem, without static analysis and static typing. Maybe you can have a 90%
success rate on short programs, I'd believe that (my first-compile success
rate on AoC was closer to 50%, and I was like #30 or so on the leaderboard
[1]). But to do it perfectly, in real-world code? That I don't believe.

The nice thing about static typing is about catching mistakes earlier, and
making it easier to figure out what your mistake was. Without the type
annotation on the function, when you get a crash a few days later, it's harder
to figure out "is the function wrong, or is the code calling the function
wrong?" With it, those questions are automatically answered.

The best I've heard is that for short scripts, static typing doesn't help
_enough_ to be worth the extra time it takes. But with modern type inference,
it takes very little extra time at all.

And the extra time it does take, to write out interfaces and stuff, you can
avoid in TypeScript with type assertions and `any` assertions. But honestly,
it's usually worth it: It's not like you _don't_ plan out the interface; you
just used to keep them memorized instead of writing them down, and then regret
it a few weeks later when you want to make a change.

[1] To be fair, it was 50% because I was optimizing for programming speed for
the leaderboard rather than accuracy; I'm sure I could have gotten closer to
90% if I were optimizing for accuracy. But anyone who argues that avoiding
static types saves time has to accept that you make a lot more mistakes if
you're trying to save time.

~~~
_bxg1
> it was a meme that no one's C program ever compiled the first time they
> tried

Ah but see, the compiler _is_ a guard-rail. Technically, it's a static-
analyzer. I don't think anyone is against making existing guard rails more
helpful via editor integration; the conflict comes with adding _new_ guard
rails. Take the following example:

    
    
      let foo = {
        bar0: 12,
        bar1: 14,
        bar2: 16
      }
    
      // example 1
      console.log(foo.bar0);
      console.log(foo.bar1);
      console.log(foo.bar2);
    
      // example 2
      for(let i = 0; i < 3; i++) {
        console.log(foo['bar' + i])
      }
      
    

Example 1 can be statically verified by a JavaScript type checker. Example 2
can't. There are advantages of being able to do the second thing - more code
reuse, possibly less refactoring needed. But it's impossible to verify that
those properties exist on that object without _running_ the code. The argument
is that oftentimes, the type checking is more valuable than the loss of
"creative" freedom. But it does mean limiting the kinds of things you can do.

~~~
recursive
In case anyone missed it, example 2 _is_ allowed in typescript.

~~~
Zarel
It's not, not without an assertion:

[https://i.imgur.com/DJjzPDF.png](https://i.imgur.com/DJjzPDF.png)

Well, it's allowed in that it will still compile the code (because TypeScript
is a superset of JavaScript), but it'll still yell at you.

~~~
recursive
Yes, without an assertion. Just change your compiler options.

[https://www.typescriptlang.org/play/#src=%20%20let%20foo%20%...](https://www.typescriptlang.org/play/#src=%20%20let%20foo%20%3D%20%7B%0D%0A%20%20%20%20bar0%3A%2012%2C%0D%0A%20%20%20%20bar1%3A%2014%2C%0D%0A%20%20%20%20bar2%3A%2016%0D%0A%20%20%7D%0D%0A%0D%0A%20%20%2F%2F%20example%201%0D%0A%20%20console.log\(foo.bar0\)%3B%0D%0A%20%20console.log\(foo.bar1\)%3B%0D%0A%20%20console.log\(foo.bar2\)%3B%0D%0A%0D%0A%20%20%2F%2F%20example%202%0D%0A%20%20for\(let%20i%20%3D%200%3B%20i%20%3C%203%3B%20i%2B%2B\)%20%7B%0D%0A%20%20%20%20console.log\(foo%5B'bar'%20%2B%20i%5D\)%0D%0A%20%20%7D%0D%0A%20%20)

------
wheelie_boy
In general, in favor of as many correctness and other checks at compile time
as possible. Make tools as powerful as possible. I really liked this tweet:

"What if...

\- your programming language required you to write useful docs,

\- using those docs, it checked your program for mistakes,

\- it even used the docs to speed up your program,

\- this feature already exists!

And what if it was called static typing."

\-
[https://twitter.com/DWvanGeest/status/1092095822559358976](https://twitter.com/DWvanGeest/status/1092095822559358976)

~~~
risubramanian
The problem with that reasoning is that nearly every language with static
typing also has some kind of type inference. You'll just wind up with a bunch
of autos/vars.

~~~
jschwartzi
I don't really use auto unless I'm interfacing with some templatized nightmare
body of code where the typename is very difficult for my tiny human brain to
interpret. Using "auto" is usually a code smell, because it means your type
system is too complex for you to reason about.

~~~
scarface74
This is a valid, strongly typed C# object:

var foo = {bar = 1, baz = “Hello”, boo = “World”};

You get auto complete help and compile time type checking.

foo.bar = “Goodbye”;

Won’t compile. What would it buy you to not use ‘var’ and create a one time
use class/struct?

~~~
gmueckl
It would make me ask why you need a one time use struct at all and probably
remove it.

~~~
scarface74
More complicated example:

var seniorMales = from c in customer where c.age > 65 && c.Sex == “male”
select new {c.FirstName, c.Lastname, c.Age}

foreach(var customer in seniorMales) { Console.WriteLine(customer.Firstname +
“ “ + customer.Lastname); }

Why would I create a class/struct for that use case?

Side note: this is why I find ORMs in most languages besides C# useless. Here,
“customers” can represent an in memory List, a Sql table or a MongoDB
collection and the LINQ expression will be translated appropriately to the
underlying query syntax.

The “ORM” is integrated into the language and yes anyone can write a LINQ
provider.

~~~
gmueckl
This us one of the cases where I would want you to write an explicit type for
seniorMales. Reasoning about the LINQ expression is just complex enough that
by not constraining its type to your expectations you can easily obscure a
mistake in your thinking that would otherwise show up in the data types.

~~~
maxxxxx
I think the anonymous type is much better. It's type safe, you can easily see
how it's defined but you don't pollute the rest of your code with one-off
classes that make only sense within the function.

If I had to review the code and saw an explicit type I would recommend an
anonymous type.

~~~
gmueckl
It is not better. I don't know what type FirstName or Age is. Can Age be
negative? Is FirstName an array of char or a string? Can FirstName be more
than 10 characters long? It could be a double value for all I can tell from
that line of code!

~~~
scarface74
The select statement is projecting the Customer type from either an external
data source or an in memory source. That information wouldn’t be encoded into
the POCO whether or not it was anonymous.

Changing select new {...} to Select new SeniorPeople {...} wouldn’t give you
any more information. At most if I was writing that as part of a repository
class I would be sending you back an IEnumerable<SeniorPeople>.

If you were to send me an expression to use in the where clause you would send
me an

<Expression<Func<SeniorPeople,bool>>

You have no idea what that expression is going to be translated to until
runtime.

Either way, you are just working with non concrete Expression Trees that could
be transformed into IL, SQL, a MongoQuery etc. All of the constrainsts would
be handled by your data store.

You don’t even know before hand whether you are iterating over an in memory
list, or streaming from an external data source.

I could switch out Sql Server for Mongo and you as the client wouldn’t be any
the wiser.

And we haven’t even gotten to the complication if the result set was the
result of a LINQ grouping operation.

~~~
gmueckl
You are comstructing an elaborate strawman that does nothing to work in your
favor. If anything, yur essay just makes it clear that it is impossible to
glean the data type from the LINQ expression itself.

Yet, any code using its result will contain implicit assumptions about that
data. Therefore, in order to maintain type safety, the expected type of the
return value must he stated.

That type must also be independent from whatever LINQ does internally to
produce that return value. Otherwise, the LINQ providers wouldn't be as
exchangeable as you claim.

~~~
scarface74
You also included information about “constraints” like is it a positive or
negative number and string length. That wouldn’t be encoded in the type. Why
would I go look up the types either way? I’m using a strongly typed language,
the IDE would tell me that anyway. While I am writing code, I see a red dot
showing me immediately if I’m using the type incorrectly. Any assumptions that
were incorrect, I would get immediate feedback.

~~~
gmueckl
Not necessarily. Is Age unsigned or not? This constrains the possible range of
values. In other contexts, there is a lot more information inferred by the
integer type used.

------
FilterSweep
> “The problem isn’t the use of a memory unsafe language, but that the
> programmers who wrote this code are bad.”

This really goes to show how _anti-worker_ the media is even among high-skill
jobs.

In my mid 20s I now mentor a bit in coding. I’ve worked with young devs that
inherently know many of the obvious security pitfalls that have caused massive
security breaches a la Equifax.

Are devs at the front of these breaches bad? I don’t believe so. Many went
through grueling multi-part interviews to land the position.

No, the issue a management one. Anti-worker is a meme in America and this is
just another manifestation of the disingenuous “lack of tech talent” whining
used to recruit more H1B.

It’s also why unreleastic growth targets cause gaming tech workers to face
layoffs despite record breaking sales.

~~~
adrianmonk
Well, although it could be anti-worker, it could also be one-upmanship among
programmers with fragile egos: _I 'm_ not a bad programmer; _they_ are.

And I think ego is a barrier to accepting tools that prevent errors. To accept
the tool is to admit to yourself and others that you are going to make the
error (sometimes) without it.

~~~
dx87
I've seen the ego issue pop up a lot in some communities. The biggest example
I can think of is the OpenBSD mailing list. Any time I'd see an outsider bring
up Rust or other safer languages, the overwhelming sentiment is that languages
with built-in safety features are for people too stupid to write C, and that
safety features restrict good coders ability to write performant code.

~~~
yellowapple
While that sentiment is certainly alive and well, that's not the _actual_
reason why the OpenBSD crowd is not gung-ho about Rust:
[https://marc.info/?l=openbsd-
misc&m=151233345723889&w=2](https://marc.info/?l=openbsd-
misc&m=151233345723889&w=2)

The takeaway of that thread is that OpenBSD's "shut up and code" mantra is
applicable here. If you want a Rusty OpenBSD, then start replacing pieces of
OpenBSD's C codebase with Rust (you might have to fork OpenBSD for awhile in
the process).

You'll probably run into quite a few issues. Most severely, OpenBSD must be
self-hosting (i.e. able to compile itself) on every hardware platform on which
it runs; if a modification causes that to be no longer true, then either that
hardware target must be dropped or the modification must be rejected.
Considering that Rust doesn't support compiling for all the hardware platforms
OpenBSD supports (let alone compiling a rustc that actually does run natively
on each platform), Rust is immediately a nonstarter.

------
jaggederest
Even if the problem was "bad coders", the answer is still better tooling.

The tooling we have now is pretty poor, in general. Sure, we can catch certain
classes of bugs. Many bugs still occur in areas that aren't covered by those
classes, even in the most robust languages.

Obviously memory-safe languages would help enormously. I also think that
compilers are still in their infancy.

------
jondubois
>> I wanted to avoid spawning a thread and immediately just having it block
waiting for a database connection...

>> The problem is that the database connection would sometimes use a re-
entrant mutex when it was acquired from the pool...

>> with a normal mutex we would be fine, since you only one lock can exist and
it doesn’t matter if we unlock it on a thread other than the one we locked it
from...

>> Fundamentally, we just can’t have a re-entrant mutex be involved and also
be able to pull the connection from the pool on a different thread than it is
being used...

Truly good coders are very rare because it's not just about mastering all the
available tools and abstractions, it's also about the ability to come up with
abstractions that make it simple for anyone looking at the code to understand
what is happening.

Good coders can write simple code to do complex things.

------
rinchik
I can see how this article might be comforting for some, but "bad coders" is
still a problem. There are a lot of amateurs in this industry (even ones with
years of "experience").

You can create an extremely opinionated language which doesn't give any
freedom for creativity, solutions and expression, and devs will still find a
way to duck everything up.

IMHO, OP saw a problem but didn't arrive to the right solution.

~~~
Rusky
I don't see how the article is trying to be "comforting," or dismissing the
value of skill and education. I also don't see how the `Send` trait featured
in the article "doesn't give any freedom for creativity."

I read it as claiming that skill and education are _insufficient_ to prevent
these bugs, and that automation is still valuable no matter how skilled the
programmer is.

~~~
_bxg1
In a broad sense, the forces of safety and flexibility in a language tend to
be at odds. Rust does a lot of clever things that push that curve some, but a
big part of what makes it safer than C++ is what you _can 't_ do.

~~~
tomjakubowski
Rust is actually looser than C++ in some respects. For example, there are no
type-based aliasing rules to worry about in Rust. This makes writing "type
punning" style code less of a headache for me, personally.

------
adrianmonk
One thing that clouds the issue here is that it really is true that better
coders do write _fewer_ of these kinds of bugs. That's a real correlation and
not a fictional thing.

So I think what we need to do is acknowledge that but keep it in perspective.
While better coders write fewer security bugs, even the best programmers still
write some. So it can't be our only line of defense.

Also, suppose for the sake of discussion it were true that top programmers did
write zero security bugs. Realistically, as an organization, how would you
ensure you employed nothing but exclusively these programmers? Even if you
make it a top priority, you can't guarantee it.

Especially since the way you become a great programmer is by starting off as a
less-great programmer and getting experience. And while you're doing that,
you're churning out software which is by definition written by a less-great or
not-yet-great programmer.

~~~
kelnos
And to take it further, let's just consider that we as programmers have a
_lot_ of work to do. The current scope of "things people are writing code for"
is nowhere near the total scope of possible useful things we could be working
on. We want to enable more people, even if they are not "the best"
programmers, to build software, safely.

People who suggest "well, just hire better programmers" are incredibly naive
and probably have never actually had to deal with the challenges around hiring
programmers.

------
pcwalton
In fact, I think it's the case that the most consequential security issues
tend to come from the _best_ programmers. That's because the best programmers
tend to be the ones working on high-impact projects such as the Linux kernel.
The more widely used the software, the more impact the security issues in that
software have.

------
weliketocode
No need to say 'bad', but there is definitely a shortage of experienced
coders.

\- Competition/Compensation for experienced coders has risen sharply

\- There are many more inexperienced SDE's coming from colleges/bootcamps/etc

\- Senior titles are often given to individuals who are still very early in
their careers

Now, these factors might be necessary/good in the short term as software
continues to eat the world.

But, let's not pretend that the talent shortage isn't a problem.

~~~
WilliamEdward
Somewhat hilariously, the problem isn't lack of talent in programmers, but
lack of talent in companies. Someone on this thread claims everyone is being
stolen by top tech companies, that means it's you who needs to make your
business more attractive, not that there's a shortage of coders.

Experienced programmers know they don't have to settle for less.

~~~
weliketocode
The two issues aren't mutually exclusive.

The supply/demand balance for experienced engineers is such that many
companies are (explicitly or not) choosing to go with less experienced
engineers.

------
applesvsoranges
>> With a normal mutex we would be fine, since you only one lock can exist and
it doesn’t matter if we unlock it on a thread other than the one we locked it
from.

Sorry if this is a dumb question, but I'm confused. Aren't mutexes always
supposed to have ownership which implies that only the locking thread can
unlock them?

~~~
scottlamb
> Sorry if this is a dumb question, but I'm confused. Aren't mutexes always
> supposed to have ownership which implies that only the locking thread can
> unlock them?

Mutexes are supposed to ensure that exactly one thread can accesses resource
("have the lock") at a time. There's no fundamental reason you can't pass the
lock from one thread to another, as long as they don't both have it at once.
But it may not be supported by the particular mutex implementation. It's not
supported by the recursive mutexes the author was using, and I'd bet there are
also non-recursive mutex implementations which don't support it. I agree with
the author that it's great Rust can catch this sort of mistake.

btw, I think recursive mutexes and handing off locks are bad ideas. Both for
the same reason: I want short critical sections to improve contention.

* Code that uses recursive mutexes tends to be sloppy about this; it's unclear from reading a section of code whether it even has the lock or not. (This also sounds like a recipe for deadlock when you need multiple locks.) I'd much rather structure it so a given piece of code is run only with or without the lock. In C++, I use lock annotations [1] for this. If I need something to be callable with or without the lock, I might have a private "DoThingLocked()" bit, and a public "DoThing()" bit that delegates while holding the lock. This should also be more efficient (though maybe it's insignificant) because there's no run-time bookkeeping for the recursive mutex.

* Handing off the mutex to another thread also feels like a smell that you're holding the lock longer than you need. I don't recall a time I've ever needed to do it. From the description here, it seems totally reasonable to hold a mutex while getting a connection from the pool and while returning one to it, but not between. I'd think you could get the connection, then create the new thread (passing the connection to it).

[1]
[https://clang.llvm.org/docs/ThreadSafetyAnalysis.html](https://clang.llvm.org/docs/ThreadSafetyAnalysis.html)

~~~
applesvsoranges
Thanks, this adds a whole new perspective for me wrt mutexes. I wasn't aware
of all these other usage patterns for them at all.

Most of my work is in the OS, drivers and low level space, and I'm a beginner
there as well, hence the short critical sections under a single owner are the
only places I had encountered them before.

------
xiphias2
The main problem is that being secure doesn't increase the revenue of
companies substantially, otherwise C/C++ programs would be rushing to Rust.
Still, the speed of improvement is great.

I'd love to see Firefox take over Chrome in speed and show that C++ is getting
closer to being an outdated language.

------
pron
Contrasting C and Rust completely misses the issue. Yes, obviously Rust will
do away with some important classes of bugs and security vulnerabilities, but
it's got nothing to do with addressing the problem. The problem is that there
are billions of lines of C out there, and it will take many decades to replace
them with software that's written in a memory-safe language. The issue is what
do we do with all that existing software, as rewriting it at any reasonable
cost or time frame is simply not an available option. A possible solution
could be something like sound C static analysis tools that can _guarantee_ no
overflows etc. without a significant rewrite. The question we should be asking
is how easy it is to use those tools, how scalable they are etc.

~~~
burntsushi
No, it is the issue. Before one can even consider the proposition that it
might not be wise to write X in C, you first need to convince people that the
tool (that is, C) is actually a problem. That's what the OP is targeting:
people think the problem isn't the tooling, but the programmer.

The task of figuring out how to actually use the language is an entirely
separate, though valid, problem. But it's not some giant mystery. The folks
working on Firefox haven't set out to rewrite the entire thing in Rust.
They're choosing targeted places where it works. Insomuch as I know, this has
been a success.

~~~
pron
But even if (assuming that safe languages have reached a point where they can
be a suitable replacement to C in all circumstances, which they haven't yet)
not a single new project is written in C from now on, it will take decades for
our software to become more secure. The question is what do we do until then.
There are some excellent tools that can be used, but aren't.

~~~
burntsushi
Who are you arguing with? Not me, because I didn't claim otherwise. And
certainly not the OP. You're missing the part where people don't even
recognize the problem in the first place. You have to fix that first.

~~~
pron
I think enough people recognize the problem with C. But a rewrite is just not
a relevant solution to the actual problem we're facing. It's a long-term
solution, but that's not what we need _now_.

------
Derek_MK
TL;DR: "[Coding perfectly and anticipating any possible change to how the
tools work] are not reasonable expectations of a human being. We need
languages with guard rails to protect against these kinds of errors."

I definitely agree with this. And it also applies to a lot more than what the
article is focused on (low-level security). It seems that right now the entire
programming ecosystem seems to jump to "you just don't understand it" rather
than "this should be more intuitive, or at least safer by design."

~~~
DannyB2
There are several quasi-related variations. Arguments against higher level
languages and abstractions.

Examples:

If you have to use a garbage collected language (eg, just about any modern
language) it's because you're too stupid to know how to manage memory
properly.

[ various arguments against type safe languages, turning runtime errors into
compile time errors ]

Higher level languages and abstractions are just bloat. [or are too bloated,
etc]

Managed language runtime systems are too [ big | expensive | bloated | slow ]
etc. (eg, the Java runtime, or .NET runtime, to a degree also Python,
JavaScript, Lisp(s), etc)

Counter arguments:

Any sufficiently complex program will need the managed runtime, garbage
collection, abstractions, type safety, etc.

Greenspun's tenth rule:
([https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule](https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule))

Any sufficiently complicated C or Fortran program contains an ad-hoc,
informally-specified, bug-ridden, slow implementation of half of Common Lisp.

We could just write everything in assembly language, er, . . . um . . no, in
hex code. And key it into the front of the machine on toggle switches with
blinking lights. We could! Yes, really! So why aren't we? Why isn't, say,
LibreOffice written in assembly language?

I use high level languages, runtime systems, GC, etc because I'm not
optimizing for cpu cycles and bytes. I'm optimizing for DOLLARS. A long time
ago, in a galaxy far, far away, computer hardware was the most expensive
resource. Today developer time is the most expensive resource. Everybody is
happy to have their word processor upgrade a year sooner even if it means it
uses a mere extra 500 MB of memory.

~~~
alexanderdmitri
The devil is in the details usually here. Bloat can absolutely affect your
bottomline in many ways.

~~~
DannyB2
One man's 'bloat' is another man's features.

Consider both Microsoft Word and Notepad.

Which is more bloated? Which is more light weight?

Which has more powerful features, some that you don't even notice right away,
like spellcheck, grammar check, etc?

Which has fewer features?

People usually complaining about 'bloat' in a high level language or its
runtime are really complaining about features that they either don't use,
don't understand, or don't even realize are there.

~~~
alexanderdmitri
> Which is more bloated?

Microsoft Word

> Which is more light weight?

Notepad

> Which has more powerful features, some that you don't even notice right
> away, like spellcheck, grammar check, etc?

Microsoft Word

> Which has fewer features?

Notepad

Users who are complaining about bloat are usually complaining about either
application performance, ease of use and basic task completion complexity
and/or general cluttering of the UI. Longer than expected load times can lead
users to believe an application is bloated as well. It's true that all these
things might be caused by something other than bloat, but these are typical
repercussions of adding general cruft and also these tend to be design
decisions and implementation details separate from the feature that the bloat
was added for.

Developers complaining about bloat (not the ones on HN giving a critique of a
github repo after browsing it for a couple minutes, but the ones who are
actually knee deep in source code trying to meet a deadline for a specific
feature or bug fix and to whom the bloat is literally a gravity well affecting
their development pace and agility) are usually referring to previous
development cycles that they believe unnecessarily introduced complex
libraries for simple tasks or outsourced application logic to dependencies
that are not under control of the in-house development that have unnecessarily
made the code base unwieldy and created more rotten code overall from a
maintainability/extensibility vantage.

In both these cases, a good early signal of detrimental bloat would be someone
taking out a PR that introduces 500MB to the application. Justifying it as I'm
maximizing for DOLLARS makes me think of someone who just won the lottery
deciding that as a result of their net worth increasing a thousand fold,
they're going to start willingly paying 1000x the price for things and also
buy 1000x the amount of things. Should anyone try to convince them of how this
logic is going to work out (perhaps someone stuck behind them in line at the
store as they ring out the tens of thousands of grocery items, each of which
provides a special value most people don't use, understand, or even realize is
edible), the lottery winner calmly explains to the well-meaning individual
(who happens to have just as high a net worth as the lottery winner it turns
out but has achieved this over time and will have a higher net worth going
forward from here) that perhaps this well-meaning simpleton just don't realize
how much money has just been won.

And sure, an application like Microsoft Word that has been actively developed
for more than 35 years will likely have bloat, especially when maintained to
preserve backward compatibility. There's a statistical minimum in this regard.
Whether or not the bloat is as bad as it needs to be is another thing.

If the development team behind Word has simply been adding 500MB here and
500MB there and defending it with "we're not going to write the new features
in assembly" or "this helps me as a programmer be more productive" or "this
source modification is so large because of all the features you don't know
about" or "what?! we're not in North Korea" or all of the above, they are 100%
creating more work for themselves and this extra work definitely comes with a
price tag. In fact, without really have much insight into the general culture
or incentives over there, it's a reasonable bet they've taken steps to prevent
developers from introducing tech debt and bloat with this sort of defense.

Either way, it's weird to point to Microsoft Word's accumulated debt and
overall decreasing performance specs as a result of multiple decades of
evolving development as a reason to dismiss bloat as a non-issue. If I were a
career non-bloat advocate, traveling from university to university on my
canola oil powered moped I'd be pointing to Word as a reason to take bloat
seriously and a reminder that the feature your adding now will likely be on
the opposing force of a future person's battle with bloat and you should fight
it with all the flower power you can muster or risk them tracking you down
with a vendetta after they realize it was your commit making their job shit
right now.

------
smileypete
Possibly sounds like a bit of a design issue to me, author /assumed/ that
reentrant mutexes wouldn't be added to the code, and this wasn't documented or
tested for properly...

------
fulafel
I think this argument grants too much to the C-believer crowd by presenting a
case where even an infallible programmer would have ended up making the
mistake. The author is arguing with people divorced from reality on their
terms.

Next, you'll get counterarguments from the peanut gallery proposing that the
merging the changes was just the fault of bad process, and as long as people
don't make the mistake of applying a bad process, evrything would be fine.

------
brianpgordon
> This wasn’t caught when I finished writing the code. It was caught weeks
> later, when rebasing against the other changes of the codebase. The
> invariants of the code I was working with had fundamentally changed out from
> underneath me between when the code was written and when I was planning to
> merge it.

Aside from the wider question about bad coders, I don't understand why he
didn't catch this when he wrote the code. Didn't it fail to compile?

~~~
eridius
I believe the implication is that when he wrote the code it compiled just
fine. There were no reentrant mutexes, so one can assume the database
connection he was working with conformed to Send at that point, and it was
only with the addition of the reentrant mutexes that the connection lost the
conformance to Send.

------
alexeiz
> ... use a re-entrant mutex when it was acquired from the pool ... normal
> mutex we would be fine, we unlock it on a thread other than the one we
> locked it from ... re-entrant mutex remembers which thread it was locked
> from, we need to keep the resource on the same thread

Sounds like a "bad coders" problem to me! This design is so screwed up that no
tool or smart compiler can save you from problems here.

------
amaccuish
This article hits the nail on the head. When speaking with someone who argues
that we don't need memory-safe languages, just better programmers, I always
like to ask if they've ever had to use a debugger/ever made a single mistake
programming. What you're asking of programmers is that they never make
mistake, whether it be a memory-safety bug or just a regular bug. It's simply
not possible.

------
taeric
I have argued many times it isn't the language that is the problem,
necessarily. Never have I argued against tooling, though. Rather, toolchains
can be added to without being replaced.

That is, my problem with this blog and most posts like it. Your tooling should
not begin and end with your compiler. It is a vital part of your tooling, no
doubt. But if all you did was compile it, you are playing a risky game.

------
ithilglin909
The problem often is needing to fight with less technical higher-ups for
adequate time and resources for tooling/testing/infrastructure work.

------
graphememes
Reading the argument laid before me in this post. I disagree. It most
certainly is due to negligence. Human negligence. Poor communication, and
project management.

Maybe, you can't correlate this to "bad coders", however, if the coders have
the issues described within this post then most certainly I would consider
them "bad coders" when paired together.

------
metalrain
As a python user I understand the need for better invariant checking, but
should it be encoded in types, contracts or conventions?

~~~
rabidferret
My goal wasn't so much to promote any specific answer, just to rebute the
argument that the solution to memory safety bugs is to have better C
programmers

~~~
jschwartzi
Yes. Often the difference between a mediocre programmer and an excellent
programmer is ability to use tooling effectively to understand how their
program works and where it fails.

------
cm2187
The problem isn’t bad coders for security bugs _at Microsoft_. But outside is
the realm of sql injections vulnerabilities, unpatched software, default
passwords left unchanged, hardcoded passwords in code, unprotected mongo dbs
exposed to the internet, xss vulnerabilities, etc etc.

There the problem lies between the chair and the keyboard.

------
seba_dos1
The argument "it isn't language, it's bad coders" is a pretty good way to
identify bad coders.

------
tomc1985
Is anyone else bothered by the use of the word "coders"? Like, coding is
something you do to medical records. We're _programmers_ , god damn it!

------
sifoobar
What is it with these people and controlling the choices of other, quite
possibly more experienced, programmers?

Why is it not enough to offer better tools and let the rest take care of
itself? Or to solve problems using a tool that fits your way of thinking? Why
do you need a cult/marketing effort if the language is as good as it claims to
be?

The more of this bullshit I'm confronted with, the less inclined I am to ever
let Rust slip into a project I'm involved in.

~~~
pas
Because ecosystems are driven by mindshare (popularity), convenience, adoption
potential barriers, public shaming (eww, that's nasty, but .. people are
people), and other psychological micro-foundations. Basically it's a cold war
of persuasion. Sometimes leading by example works, sometimes by showing how
awesome, cool, fast, safe your shiny stuff is, sometimes it works by appealing
to people's sense of the "greater good" (how many Korean, Chinese, Iranian,
Saudi, etc. democratists are in secret prisons, because broken C code).

And of course there's some truth to it. Look how Py2 is still not dead,
because rewriting twisted is hard. (Which no one said it was easy.) And how
long it took for distros to make it the default, and how long it took for
anyone to not default to it. And of course there were people even complaining
about how Py3 broke all their nice code that worked before by accident.

So if collectively everyone had made a push some years ago, we would be long
over. But of course organizing these things is an even bigger problem than
just sitting down and firing off PRs to twisted.

------
jaabe
You shouldn’t rely on your tools protecting you because they won’t.

I do part time work as an external examiner, sometimes for first year CS
students, so I get to see a lot of silly code. Like the result of having been
tasked with doing Fibonacci recursively. Which, as most of you no doubt are
aware, can be done correctly in several different ways. The most basic is to
simply implement it with its two base cases and run it until you meet them for
every sequence. A more efficient way is to implement it with a way of keeping
track of Fibonacci sequences that you have already computed, as to not do them
more than once.

Both these ways work perfectly fine within the toolset, one just does it a lot
better.

~~~
jschwartzi
> This is a very basic example, but most students solve it the inefficient
> way, but in most situations you’d really rather have the ones who did it
> better.

I would much rather have the student who solves it the inefficient way but who
runs a profiler on their code with a real-world input, determines that their
naive algorithm is unacceptably slow for certain inputs, and makes an
adjustment to optimize it.

If I'm only ever going to use the first 16 Fibonacci numbers I don't really
care if they're brute-force computed recursively. I'd much rather spend
valuable engineering time on optimizing something that actually matters.
Requiring students to prematurely optimize some ivory tower algorithm as a
precondition to working in the real world is precisely why we have a shortage
in the first place. You should be training the students to optimize the
algorithm when it needs to be optimized, and not just hiring people who've
memorized a few very specific algorithms and can bark them on command during
your interview.

~~~
hinkley
My response would be “just use a loop and get it done so we can move onto the
next task”. There are only two pieces of state here. Let’s not drag out the
big guns and make something hard to read.

Fibonacci is too simple a case to demonstrate the power of recursion, and
people have beef with the textbook examples. It has a confounding factors that
actually makes recursion an over complicated solution, and not _enough_
factors to make it a good example for dynamic programming. Also it simply
doesn’t scale to inputs that only take microseconds to calculate.

It’s like those interview questions that leave you with more questions than
answers, like “are they bad at interviews or just crazy?”

~~~
jschwartzi
Exactly. It's like a golden opportunity for me to demonstrate some engineering
chops and instead the interviewer expects me to just whip out some caching
implementation for some nebulous reason because that's what they would have
done. If there's a real problem with either of our naive implementations the
proper thing to do is to tell us what the problem is and leave us free to
solve it.

------
bfung
The problem here is the author’s development process. There’s an “old”
programmer adage in regard to version control: merge early, merge often. It
addresses the author’s issue directly.

So yes, it’s not the code that’s bad. It the development process. Bad (ok,
fine, inexperience) developer.

[https://queue.acm.org/detail.cfm?id=1643030](https://queue.acm.org/detail.cfm?id=1643030)

~~~
unionpivo
That's the point.

There is always something you haven't thought of (or did wrong), once you get
to certain level of complexity.

~~~
sifoobar
Regardless of language.

You'll have different kinds of bugs, but as long as there are programs they
will contain bugs. Or the languages themselves will, or the libraries used, or
the OS.

Assuming the presence of bugs/failures and providing powerful tools to deal
with them like Erlang is a more realistic option if you ask me.

