Jaws is not a two-note theme

They recognize it as soon as it starts – on the first note, even, as the reaction of this crowd shows at 16 seconds.

We are talking about John William's main theme for Steven Spielberg's classic film Jaws (1975).

When the thing starts, it already has a certain personality, definite choices in the orchestration, that enable anyone to know what it is. It's like a tutti of the lowest orchestra. The contrabasses and cellos are helped, as the video immediately shows, by a contrabassoon and two bassoons. I think there is no bass clarinet, I can't hear it.

Actually, low strings doubled by bassoons... that's a very common orchestral sound. But I suppose if you know it's Williams, then on the first note you know what this is.

It is a truism that the theme has only two notes. I understand what people mean when they say that. Journalists have said that often when John Williams is interviewed, and he won't correct them, he accepts the number two. He says "yes, and".

But that's wrong. Of course the theme does not have only two notes, nor could it. It's a horror film, therefore it has all twelve notes.

As you probably know, there are normal people, and there are musicians. Normal people haven't counted the pitches. But any composer will – it's not a case of "ackchually", but a necessity for understanding the language and the material.

We have only examined the introduction so far, which is insinuating the theme. When it stops lurking and launches into the fast ostinato, at 40 seconds, two things happen. First, a piano joins the texture, probably to give it a very definite attack. But most importantly, you get the same 2 alternating notes, Mi and Fa – but also a third note in the accents: Re.

So the main idea, the main subject of the film, requires three notes, not two. And Re is the lowest – the note we would hear as the bass of any implied chord there. Re is used in the accents, you couldn't write the actual theme without this third note.

With 3 notes given so far, one could be forgiven for thinking we are probably in the key of D Minor. The composer is now quick to prove that wrong – at 48 seconds the texture becomes more complex. The 4-horn call is incredibly important, contributing only pitches that are a minor second apart from the 3 pitches of the ostinato. This means it could not sound more dissonant in relation to the ostinato, it could not be in a more foreign "key". The pitches are Mi Bemol, Sol Bemol, and Re Bemol.

One can play all the pitches mentioned so far by dropping one's closed hand on a piano, from C# to F#. This fact suggests a kind of dodecaphonic thinking. A composer realizes if you expand that with only one more neighbour note, you get the range of a tritone, and then you can apply dodecaphonic procedures to that, like transposing the whole thing up a tritone to use the rest of the 12-note scale.

But that is not what Williams does here. I would say the thinking is more along the lines of pitch sets, combined with polytonality, because we easily hear the two simultaneous musical events (the ostinato and the horn call) in two different "keys".

So here a public that has already forgotten polytonality (except that jazz never forgot it) is exposed to an advanced instance of it. Darius Milhaud, author of the best polytonal music, "Saudades do Brasil", would be proud.

The accents in the trombones... there is something weird about them, in this recording they sound like La Bemol. This surprised me because, as I started writing this, I was pretty sure it was Si Bemol. This video soon becomes too audio-distorted to remain useful, we must switch to a studio recording now. In the studio recording, the trombone accents are Si Bemol, definitely. (0:30)

This kind of difference is something that always happens with Williams. For his most famous pieces, he always created a Boston Pops version, with a more normal set of instruments, such that it can be played by any orchestra without hiring many extras. Thus the original film music always sounds a bit more "custom" than the orchestral suites made for concerts. But he doesn't stop at orchestration – there are changes in the discourse, in the order of the sections, and in tiny details such as this, the pitch of the trombone accents.

Would you like me to speculate about why he would change B flat to A flat? OK. Both are possible as part of the horn call scale. But B flat sounds much more in harmony with the ostinato. In fact, B flat dangerously undermines the atonality because it "wants" to become the root under the ostinato, which would then become a simple B Flat Major chord (Si bemol, Re, Fa). A flat does not have that problem, being an "ugly" tritone away from the Re.

Now (0:36) the pitches Fa and La Bemol also become a secondary part of the horn call. The end of the horn call has longer notes in this version, while in the Boston Pops version the notes are very short.

Speaking as a composer, the horn call is the actual main theme of this piece. This is because the ostinato is not amenable to development – it is most useful if it remains there doing its thing without change.

A simpleton like Hans Zimmer could also compose the ostinato – anyone could. But to make the rest of the texture and the rest of the piece, John Williams' taste, knowledge, creativity and development skill are necessary. Therefore, the value of the piece isn't really in the ostinato, it's in everything else!

One wonders if normal people have heard the rest. I think they have, but they can't talk about it, they don't have the vocabulary for it. So they talk about the two-note theme. It's a sort of musical bikeshedding that happens. If I were to interview Williams, I wouldn't ask him about the same tired old things, I would make a technical interview, a composer's interview.

At 1:00 a huge tutti is building up, the violins carry the melody, and guess what, the melody is based on the horn call. There is still something oscillating in the background in the interval of a minor second (piano?), but that is "drowned" by the rest. It is also two times slower as the oscillation in the ostinato.

At 1:20, on top of a chaotic atonal texture, flutes play some kind of American march fragment. Or maybe it's not a march, maybe it's a children's song. Either way, we are reminded of the general public having fun in the beaches – those that the main character, a reluctant hero, needs to save. This song is again superposed "in a different key" from the rest. The polytonal procedure is important in the language here. It makes sense because these people are unaware of the danger – the dangerous shark and the people having fun are in two different realities.

These are the most interesting things I could say about the Jaws theme. To sum up:

  • It's never just 2 notes. In fact, it's 3. In fact, it's a horrible chromatic cluster. In fact, it's polytonal.
  • The polytonality is a musical way of expressing two simultaneous, conflicting realities. But it is a latent conflict: we can hear the conflict, but the two individual situations cannot, each being "happy" in its own key.
  • Anyone could have composed the ostinato. But only a jazz musician like Williams would have remembered to use polytonality to express the latent conflict.

The entire music of the film is genius of course. Not just the recognizable theme. Witness, for example, the "father and son" scene.

Here, I believe the piano and harp representing the child are in the scale of D Major, but really in G lydian. (The lydian scale is the brightest one available.) The most important thing in the melody is the C# resolving to B natural.

The innocent youth is incapable of understanding the depths of gravity that a responsible adult will have to go through. This scene drives home the simultaneous realities of the youth on vacation and the policeman on whose shoulders the responsibility for the dead girl weighs.

Of course he can only think about his problem, nothing else. What is more insistent than a 2-note ostinato? A single held note. John Williams will not mention the shark musically here, since there is no danger. An even worse alternative would be to invent a theme for the politician. Let's not do those. Not when one note will suffice.

Therefore, polytonality is used again. Guess what note is in the bass? C natural. Why?

  • It's the lowest note cellos and contrabasses are able to emit.
  • It's right between the C# and B natural I just mentioned, just a semitone apart from both, therefore it maximizes dissonance to the child's melody.

If the shark isn't just 2 notes and actually requires 3... at the same time, John Williams can convey an idea with a single bass note if he wants to. That's amazing!

One character imitating another... that reminds me of another Spielberg movie with another perfect musical score. In that one, the imitation is the very first act that humanizes the hideous deformed monster who, by the end of the movie, will have become your best friend in the entire galaxy and leave you in tears for his absence. But in Jaws, the point is the contrast between their two mindsets, and Williams put that contrast in the music.

Usually film music will seem to be from the point of view of one character. This is a rare example of two POVs, simultaneous, accomplished through bitonality.


When Spielberg first heard the shark theme on the piano, he didn't seem to like it. If memory serves, it went more or less like this: "Really? That's all?" "You have to imagine the orchestra, of course." "Yeah but that simple?" "It's a very primal movie you've made here, Steven."

Williams' accusation that the movie is "primal" is not true. Let us just say his scores have more complexity and truth than his assertions. Or rather, in trying to defend himself, he went for the wrong argument. The correct response would have been, "of course that's not all, that is only the ostinato. On top of that we'll have modernist techniques, an entire orchestra playing in polytonal layers." Because that is what he actually did. The music for Jaws is not based on two notes, that's nonsense.

"Jaws" was a great success, and remains one of the greatest accomplishments in cinema, not because it was primal, but because it is sophisticated. Since all the sequels lack sophistication, they are failures. This sophistication is obviously in the music, but also in the director's technique. Watch this analysis of a single scene to understand how.

Dart versus TypeScript

In recent posts I have shown that the web only has crummy technologies, but at the same time, Flutter deployed on the web is not yet free of its own crumminess, since it runs slower than in any other platform.

In this post I shall convince you, beyond any doubt, that to develop frontends, you should use the Dart language rather than TypeScript. We'll examine:

  1. Problems with JavaScript
  2. Ignoring those problems like ostriches
  3. Problems with TypeScript
  4. Problems with functional languages
  5. Dart as a solution
  6. Problems with Dart
  7. Conclusion
  8. Futurology

1. Problems with JavaScript

JavaScript was created in 10 days and now we have to tolerate it forever!? WAT. It is the only language I know with so many evil parts, other than INTERCAL.

The best book about it is called "JavaScript – the good parts". Everyone has read that book. However, its author now says it's time to stop using the language.

The design problems in the JavaScript language are too numerous to list here, but here are some of the most egregious:

  1. this keyword
    • Context sensitivity: The value of this can change depending on the context in which a function is called, leading to unexpected behavior and countless debugging sessions for thousands of developers.
    • Binding issues: Developers often need to use .bind(), call(), or apply() to explicitly set this, which is cumbersome and unheard of in any other major programming language.
    • Arrow functions: Arrow functions do not have their own this context, which can be both a benefit and a source of confusion when switching between arrow functions and regular functions.
  2. Arrow functions
    • Implicit return: The concise syntax can be misleading, especially with object literals, where {} is interpreted as a block rather than an object.
    • Arrow functions do not have their own arguments object, which can be limiting in certain scenarios.
    • No own this: While it solves some problems, it can also be confusing when developers expect a traditional function's this behavior.
  3. Type coercion
    • Implicit coercion: JavaScript's automatic type conversion is a severe misfeature that leads to unexpected results, such as '' + 1 resulting in '1' or true + false resulting in 1.
    • == vs. ===: The loose equality operator == performs type coercion, which can lead to unexpected results, whereas === does not, leading to a general preference for the strict equality operator but also to confusion among new developers.
  4. Classes and super()
    • Syntactic sugar: JavaScript classes are often criticized for being syntactic sugar over the prototype-based inheritance, which can lead to misconceptions about how inheritance works in JavaScript. In reality this is not a problem in itself, except for all the terrible implementation details in classes, this and super, which become a list of gotchas for developers to memorize.
    • Mandatory call: In a derived class, if you define a constructor, you must call super() before you can use this. Forgetting to do so results in a reference error. But worse, this means it is impossible to completely override a constructor in Javascript.
    • Order of initialization: The call to super() must happen before accessing this, which can complicate constructor logic and initialization sequences, or even make one's idea impossible without a redesign.
    • Classes in JS are so bad that most JS developers prefer to ignore them entirely. Instead, they achieve encapsulation by abusing closures, which is in itself another terrible way to write software.
  5. Module systems
    • Due to historic reasons, JavaScript has multiple module systems (CommonJS, AMD, ES6 modules), which can be confusing and lead to compatibility issues.
    • The final system (ES6 modules) has a export default feature which I don't see in any other language, does not add value per se, and probably only exists to emulate the previous 2 module systems.

JavaScript is a language notorious for its inconsistencies and flaws. Despite possessing modern features, it suffers from fundamental issues that remain unresolved. this, function, arrow functions, super, and the, so to speak, excessively dynamic type system... the behavior of these things is riddled with exceptions and unexpected outcomes. Learning JavaScript often feels like memorizing a long list of workarounds.

As a result, JavaScript is a language that makes kittens cry every day. It is legitimately a language to be hated, if we are being reasonable.

JavaScript is a hypocrite, like a person who pays for expensive, albino-white facades on their front teeth, but leave their back teeth to rot full of caries. JavaScript is the guy with a sports car who in truth is hurtful to women.

People who decide to use JavaScript outside of the browser are backwards: the browser should acquire a good language, instead of the worst language contaminating the entirety of computing.

The real reason every other language compiles to JS, and the real reason WASM exists, is not a lack of cool new features in JS. The real reason is that in JS, this is broken, function is broken, arrow functions are broken, super() is broken, the type system is broken... To learn JS is to learn a pointless list of exceptions to expected behavior.

Consequently, many developers choose to use languages that compile to JavaScript or explore alternatives like WebAssembly. This trend highlights a critical issue: JavaScript's fundamental flaws hinder development efficiency and cost lots of time and money.

As an example, here is a lesson for today:

  • Arrow functions cannot be constructors.
  • Arrow functions do not inherit a this binding; if they are part of an object, they cannot talk to it.
  • Arrow functions don't provide arguments; normal functions do.
  • Named functions are hoisted, const is not. Arrow functions were invented to be anonymous and to make small event handlers and callbacks, but people are abusing them and naming them with const.

This is just one confusing instance where JS has 2 ways of doing the same thing, both with advantages and disadvantages depending on what you are doing. How much of this will you remember in 30 days?

Why not pick a good language instead?

In short, what needs to change in JavaScript is its WAT. And while that doesn't happen, hordes of young programmers are learning a horrible programming language first. Getting used to the most inelegant solutions. Honestly, JavaScript has become the most popular programming language, and also the worst popular programming language. The only things that are worse are those that are designed to be worse: esoteric programming languages like INTERCAL and Whitespace.

But the worst part is, they seem to have given up fixing JavaScript. They have concluded it's impossible, due to the requirement of eternal backwards compatibility. That is the wrong conclusion, and it shall be revised real soon now, as web development has clearly become unsustainable.

2. Ignoring those problems like ostriches

Most JavaScript developers are the proverbial boiled frog. They have been studying this cursed language for years and years, why worry now? "I am productive in JavaScript in spite of its shortcomings." Their attitude is that of the ostrich: "learn the good parts", shun the bad parts, and develop code today.

They will add, that all the alternatives to JavaScript are also doomed, for other reasons. Maybe they are harder to debug in the browser. Their performance is necessarily worse than JavaScript, since they compile to JavaScript. And so on.

In short, it's the famous Sunk Cost Fallacy. JavaScript is evidently not beneficial, but one sticks with it due to past investments.

Where Python 3 focused on removing all the warts from Python 2 and succeeded, people imagine this to be impossible in JS, since they believe there is an eternal backwards compatibility requirement. I predict this requirement will drop very soon, as the accumulation of horrible web standards becomes a terrible burden.

Yet, a successful precedent exists: ActionScript 3 introduced class-based inheritance, separate from, and without disrupting, the existing prototype-based system. This demonstrates that it's feasible to evolve a language without breaking existing code.

Again: It is NOT impossible to fix JavaScript; the impossibility is an illusion that makes you accept JS.

The only thing that is even more painful than fixing a floor full of rusty nails pointing up... is to forever tolerate it. But that's exactly what a boiled frog does. "I already know where the rusty nails are, I don't step on them anymore."

This almost amounts to a Human Rights issue.

My advice to you is: are you writing a large web app? Then for the love of humanity, do it in anything but JavaScript.

3. Problems with TypeScript

There is a moderately popular project by Facebook called Flow. It lets you write static type annotations on otherwise JavaScript code, it checks the types as you write, and then it simply removes the type annotations in the end, leaving only your JS code. I consider Flow a good design – if you need to write JS, that is.

Microsoft answered the same question differently.

They hired Anders Hejlsberg, the guy who had created Turbo Pascal and Borland Delphi, to make derived languages for them. First they used him in their attempt to Embrace, Extend and Extinguish Java. Microsoft then lost a tremendous lawsuit to Sun Microsystems for that misstep, so they turned to the next best war strategy: make their own Java while denying all influence. Thus C# and the Dot Net Framework were born, or rather, cloned. To this day these people are affirming that "C# belongs to the C family of languages", while it really is Java with a couple of misfeatures removed. Hejlsberg was and is the main designer of C#.

In 2012 Microsoft announced another Hejlsberg creation: TypeScript, which has become the most popular compiles-to-js language. But instead of just adding types to JS (like Flow does), it is a bastard child of JS and C#. I imagine they gave Hejlsberg these contradictory goals: "We want C# for the web, but it also must be a superset of JavaScript". The superset bit means, if you paste JS into a TS file, it just works – all JS is valid TS. It also means TS has its own separate features, augmenting JS.

The fact is, this one-way compatibility with JS is probably why TS won. But you know what I am going to say, right?

TypeScript again decides not to fix any of the bad parts of JavaScript. TypeScript is a monstrous creation, it adds even more cool features, such as algebraic types, without first fixing the basics. The decision to be a superset of JS sealed TypeScript's fate; after that decision, being a good language was impossible. It presents the best language features and the worst language features in a single thing. TypeScript is the most hypocritic programming language in the world, and as such, it could only have been born at Microsoft. Or Oracle, Apple, Facebook or Google.

Learning TypeScript is learning tens of weird unexpected syntaxes in the type system – things that should be natural and much easier – and then forgetting them while you are coding.

Every developer has noticed that, if TS seems powerful, it is because there's an enormous amount of features for annotating types. It's not simple at all, it amounts to a tremendous cognitive burden. And newer versions never simplify anything, they only add to that burden. The developers of TypeScript take too much freedom to make it impossibly complex. I have found this frustrating, and I am not alone:

Rich Harris: "We also eliminate an entire class of annoying papercuts that will be familiar to anyone who has worked with the uneven landscape of TypeScript tooling."


Here is a video detailing the latest TS release. And here are some YouTube comments sharing my sentiment:

@tacochub4353: These updates are neat... sure, but I don't really see how these methods solve the plethora of issues with using TypeScript. All they seem to do is add unnecessary complexity to an already perplexing ecosystem filled with syntactical nuances.

@JamesDSchw: My beef with many TS releases over the years surround the cognitive load they incur - more syntax and language semantics to be able to model types in existing libraries in the ecosystem.

@universe_decoded797: Typescript solving things that are not problems to create more problems is problematic. ‘Simple things are hard to create’ is a true statement.


In short, you wanted to fix JavaScript and suddenly you saw TypeScript. It overloaded your senses with so much information and impression of power, that it seemed to be the right solution. The only thing everyone forgot was the actual problem: we need to fix JS.

To choose TypeScript, one must overlook two facts:

  1. There is tremendous value in keeping language scope down to a minimum. Until Python 3.4 more or less, Python was a small language, any programmer could pick it up in a week by reading a 100-page description of the language. And then they could learn crucial parts of the standard library in a couple of months. One would become productive very quickly. Unfortunately, Python has entered a new phase, in which they forget the value of staying small and keep adding syntax. Becoming Scala, a language that one never finishes learning. If you are a Scala programmer and you start reading another developer's code, chances are, you have to stop and look up this syntax that is new to you. That is a horrible mistake. Back to TypeScript, it starts by accepting JavaScript, but then paradoxically it again becomes Scala by relentlessly adding features.
  2. We need a language that is a solid base to build upon; the perplexing crumminess of JavaScript is automatically unacceptable if mental health is a value.

4. Problems with functional languages

It is currently my opinion that an object-oriented programming language is perfect for creating user interfaces, even a pure OO language such as Smalltalk.

But here, let us ponder that an object-oriented approach greatly benefits from adopting a few lessons from functional languages. Functional programming is not the opposite of object-oriented programming; to a certain extent these can be combined. Also, object orientation today accepts that composition is better than inheritance most of the time. I favor a pragmatic approach that uses notions from both these worlds. Immutability only on certain kinds of information, and a conscious effort to create pure functions and unit tests for these – these are key to writing good code.

But the current wave of functional programming languages is another thing that a healthy reader should doubt. In about 15 years of people trying functional languages and immutability in the browser (either in JS or in functional languages such as Elm, Elixir and ReScript), the functional paradigm and the insistence on immutability have failed to deliver the cleanliness and developer productivity that were promised.

Here are some arguments so we can establish that functional languages and techniques are not the panacea:

  1. Complexity in state management
    • State overhead: Functional programming emphasizes immutability, leading to frequent state copies. This can increase memory usage and overhead, unless the collections in the language are carefully made to avoid this problem (such as in Clojure).
    • Verbose code: Functional paradigms often require more boilerplate code to manage state changes in an immutable manner compared to traditional imperative approaches, unless this is addressed in the language design (such as in Clojure).
    • Business Logic Complexity: For complex business logic, imperative programming often provides more straightforward solutions, whereas functional programming can lead to overly abstract and convoluted code. Unless the language is data-centric (such as Clojure).
  2. Steep learning curve
    • Conceptual barrier: Functional programming concepts like higher-order functions, monads, and pure functions can be difficult for developers to grasp, purity being the easiest. Mathematical concepts are of course beautiful in computing, but they simply are not the way most people communicate – and the web should be for everyone.
    • Limited adoption: The steep learning curve has hindered widespread adoption, making it harder to find developers skilled in functional programming, which impacts team productivity.
  3. Performance concerns
    • Inefficiency in browsers: Functional programming can introduce performance issues in the browser, such as excessive garbage collection due to frequent object creation from immutable state changes.
    • Lack of optimization: JavaScript engines are primarily optimized for imperative code, potentially leading to less efficient execution of functional code.

While above I have tried my best to talk ill of functional languages… knowing what I know today, to develop user interfaces, I would reach:

  • first for a functional language that is conscious of, and addresses, the pitfalls above (such as Clojure);
  • then for a multi-paradigm expressive language such as Python, Dart or Kotlin;
  • then for a pure OO language such as Smalltalk;
  • then for a hybrid functional language such as ReScript, OCaml or F#;
  • then for an opinionated, pure functional language such as Elm or Haskell;
  • then for anything else in existence;
  • before resigning myself to use TypeScript or JavaScript with their broken basics.

5. Dart as a solution

In 2009, Node.js brought JavaScript to the server, and now boiled frogs write their backend and frontend in the same language: the worst one. Someone help them!

Seeing this, Google unveiled their Dart language in 2011. You can think of it as the last Java clone, this time with better influences. Dart 1.0 came out on November 2013.

The initial plan for Dart was to include it in Chrome as a second native browser language, the good brother of JavaScript. This was criticized for fragmenting the web, so they gave up this idea in 2015 at the release of Dart 1.9. And then Google proceeded to dominate the web anyway – through countless bad standards – such that now it is financially impossible for anyone else to develop a new browser. We might as well have had Dart in Chrome, it would have been a tremendous blessing all these years.

There exists a parallel universe in which the frontend community gladly accepted Dart as their saviour when Google proposed it as a sane, parallel native language in the browser. I wish I lived in that universe. Frontend devs, you have Stockholm Syndrome.

Instead, Dart was sort of forgotten for a couple of years while Flutter was being developed. It was released in 2018.

Here are reasons why Dart is good for developing applications and GUIs:

  • It has none of JavaScript's defects.
  • It is essentially just another boring multi-purpose Java clone with a few saving graces.
  • It has null safety.
  • It has a good, pragmatic type system without any trace of TypeScript complications. Something that just helps programmers instead of stealing their attention.
  • It has garbage collection.
  • Very performant for a garbage-collected language. You can roughly think of Dart as 10 times faster than Python and 10 times slower than C++.
  • It runs on every platform; it can also compile to JS.
  • It is now beginning to compile to WebAssembly and even use its garbage collector – this makes the runtime smaller.
  • It is being developed at a nice pace.
  • It has a moderate, good enough syntax size; it does not seem to want to become Scala.
  • It has features to write constructors without so much boilerplate, making Java look silly. However, Python is still better in this regard.
  • In fact, in some places it has been smarter than Java and C#. For instance, it does not have the private, protected and public keywords; instead, the programmer simply starts a variable name with an underscore (such as _myVariable) and that makes the variable private to the current file. This is great language design, removing lots of noise in a single movement.
  • Developer productivity and comfort are higher in a no-nonsense, immediately familiar language.
  • If you learn Dart, you are learning the language of Flutter. If you write the core of your web app in Dart, you can later reuse some of that core in a mobile app. And Flutter is much better than React Native... because React Native is based on JS/TS, and its misarchitecture consists of letting you use crummy web technologies such as CSS (or rather, just an arbitrary subset of these technologies) which then get translated into native widgets. It is just a fundamental lie, designed to keep web developers in their narrow comfort zone.

6. Problems with Dart

  • Metaprogramming/reflection is currently weak in Dart, but being worked on right now (2024), with macros in the roadmap for the next few releases.
  • Interop with JavaScript is more difficult than expected. Using a JS library in Dart code is fine, but you have to write typing stubs for the library's interface. Consuming Dart code from JS requires you to expose objects and functions with a decorator, and I don't think you currently can expose them in a JS module, so you have to put the API on the window object, which feels outdated.
  • Indentation with only 2 spaces is hard to see.
  • It uses curly braces instead of significant indentation. (Significant whitespace is objectively better because it communicates the same information with less visual noise and occupies fewer lines.)
  • It requires semicolons.

Given the above, I would definitely write web apps in Dart, especially using its numerous frameworks for doing so; I would also write a large app component to be consumed by JS through a relatively small interface; but I would not write a typical JS library in Dart, unfortunately.

7. Conclusion

Going parallel to JS is unavoidable, that is why everyone wants Web Assembly to succeed: it's the only escape.

Dart is not perfect, but programming in it is bliss compared to JavaScript and TypeScript. There are alternatives out there; your responsibility is to choose something better than what everyone else is using, if you are smart.

8. Futurology

The feared web fork is soon going to be required, and for all Web tech, not just JavaScript. Because the powers that be have introduced an enormous number of spectacularly failing standards:

  • JavaScript
  • HTML that is not XML
  • CSS, which again is growing impossibly as a language, is impossibly complex in the interaction of its features, contains an impossible number of footguns, and is already humanly impossible to learn for its target audience of designers and common people
  • Web Components (Custom Elements), which are enormously complex, have a terribly verbose API, yet somehow manage to fail at addressing basic concerns of writing GUIs
  • IndexedDB, the only way for frontend devs to access a SQLite database, has a horrendous API, so nobody uses it
  • ...?

The idea that these bad standards, plagued by complexity and inconsistencies, must remain in the Web forever for backwards compat is absurd and impossible. Of course one day this entire mess will be dropped.

The web platform has become so convoluted that only tech giants can afford to build browsers. This centralization of power threatens the open nature of the web.

When Firefox finally finishes failing, we'll be in the impossible situation of every browser being based on Chromium. This is due to the number of incredibly complex features and standards that a browser must implement. Thus the web no longer belongs to the people, it belongs to tech giants.

I am calling this right now: soon the people will create a "New Simple Web", from scratch, with simpler (but not necessarily more powerful) technologies, languages and protocols, to replace this Impossibly Big Ball of Backwards Compatible Spaghetti. This revolution will be painful in many ways, but it is clearly unavoidable. The most important values for the right technologies, languages and protocols will not be power, but cleanliness, simplicity and developer experience.

I believe the New Simple Web will look more like Flutter than anything else. It will be based on a single good language. No separate language for formatting. It will tend to the pragmatic needs of writing applications. But it will still somehow make contents public, as they are today. Oh, and it will have no DRM.

In order to become popular, the New Simple Web will have to offer something to the users, too. Evidently, that something will be their freedom. By then Google will already be the distopian oppressive OCP they have decided to become, so they will be closing everything on the Web: mandatory ads, mandatory privacy invasion, mandatory taxes, mandatory DRM protecting THEIR content which they actually stole from books, poorly paid videomakers etc... you name it. This is what Chrome will be.

Other tech giants will try to create an Alternative Web in advance, but they will not provide the necessary freedom, and therefore they will fail.

Someone will rise to the challenge, present a clear picture of how the New Simple Web should be built, and do it. People will use Chrome for banking and gradually migrate to the New Simple Web for everything else.

And then the cycle will begin again, inasmuch as humans are bound to forget learned lessons.

You're too quick to dismiss Agile

I see too many programmers today thinking that Agile is nonsense. It has even become an opportunity to sell books on esoteric methodologies.

However, there's widespread confusion:

  • about what Agile actually proposes,
  • about how bad the alternative is,
  • about what our personal experience really is – usually with Scrum.

First of all, let's quickly remember what Agile really is: a reaction to Waterfall.

I have another post that defines Waterfall and begins to explain Agile as a reaction to it. You should start there; maybe that's where the confusion will vanish.

The manifesto

Please refer to the original Agile Manifesto, which is about 5 lines long:

https://agilemanifesto.org/

It simply means that:

  • processes and tools are important, but individuals and interactions are more important.
  • comprehensive documentation is important, but working software is more important.
  • contract negotiation is important, but customer collaboration is more important.
  • following a plan is important, but responding to change is more important.

You see, it's extremely hard to disagree with anything the manifesto actually says.

For example, notice how the manifesto didn't prescribe any meetings. The meetings that developers complain about so much are usually the Scrum meetings. Therefore, they are not a part of Agile itself. One can develop software well while organizing one's meetings in a different way.

But what some programmers really want is to develop software without communicating at all; that's impossible, and therefore, their own mistake.

Scrum

Scrum is a modern development methodology, appropriate for developing products of any kind, not just software. Scrum does not actually say anything specific about software development.

However, it prescribes a set of meetings. If you don't have your meetings that way, then you are not doing Scrum, you are doing something else. We just saw that Agile values individuals and interactions over processes; therefore each team should have sovereignty over their meetings and should only do Scrum meetings if they think that's appropriate for the specific team. Therefore, Scrum is already not following Agile in principle by demanding those meetings – although the ideas in Scrum can be employed in Agile!

The meetings in Scrum do address a tendency that software developers have, to not communicate enough (or sometimes at all) between themselves. If left unchecked, this tendency is enormously dangerous to the health of any project. We'll talk about this again below (XP).

The Scrum Guide (2009-2020) is another document that is very brief (12 pages) and easy to read. Again, you might be surprised at the things it doesn't say. For instance, Kanban and Planning Poker are not necessarily a part of Scrum. Scrum does not prescribe how the product backlog should be organized or how the team actually decides what to include in the next sprint. You might be surprised at how democratic it really is, if you read it.

I have worked in several bad Scrum implementations, each with their own troubles. However, I do know from experience that Scrum can work wonderfully well, because I have been part of a good Scrum implementation. Its democratic nature kept the entire team quite enthusiastic about their work.

Scrum is a humanistic revolution in the workplace. It inverts the hierarchy. If in the 80s you had quite bossy bosses bossing workers around, Scrum says, bosses are out. Scrum teams have no boss; there is only a facilitator, who is supposed to give workers freedom to do the work the way they want to do it. The role of the facilitator is actually to help the workers, for instance by removing obstacles (institutional, physical etc.) that hinder their best work. This creates an engaged team where before you only had begrudging employees. The Scrum team is self-managing.

"But in my experience Scrum is a tool of domination", you say. Well, did you experience actual Scrum, or a bastardized "version" that actually contradicts its principles?

If you are going to criticize Agile or Scrum, first understand what each actually says. Most often, you'll realize your trouble is with the implementations you've had the misfortune of experiencing.

If you pay attention to the history of Scrum, you realize there are at least 2 Scrums:

  • The 1986 one, from the paper "The New New Product Development Game" by Hirotaka Takeuchi and Ikujiro Nonaka;
  • The famous one, from Schwaber and Sutherland in 1995. Both authors are also signataries of the 2001 Manifesto for Agile Software Development. But the Scrum Guide only appeared in 2009.

It is important to notice that the lineage of thought is different for Scrum – it originated in Toyota, not in software development. Quoting the above Wikipedia article about the Japanese original Scrum:

Based on case studies from manufacturing firms in the automotive, photocopier, and printer industries, the authors outlined a new approach to product development for increased speed and flexibility. They called this the rugby approach, as the process involves a single cross-functional team operating across multiple overlapping phases, in which the team "tries to go the distance as a unit, passing the ball back and forth". The authors later developed scrum in their book, The Knowledge Creating Company.

What I can see Scrum has in common with Agile is the humanistic aspect:

  • individuals and interactions over processes and tools
  • collaboration over negotiation – this time within the team.

Extreme Programming (XP)

XP is the actual first Agile methodology for software development specifically. This is the one that was made by programmers, for programmers. It was developed by Kent Beck and his team from 1996 to 1999, when he wrote Extreme Programming Explained. That team included these guys who also signed the Agile Manifesto:

Most of the ideas in the Agile Manifesto are already found in XP.

XP described most of the software development practices that won and are in use today:

  • writing automated tests and using them to get the courage to refactor existing code freely, without worrying about breaking everything
  • refactoring before implementing a new feature, so it becomes easier to implement
  • delaying decisions when possible
  • pair programming to improve team communication, disseminate knowledge amongst team members, and to severely improve code quality, killing bugs immediately
  • writing only documentation that you actually need and can keep up-to-date

XP was revolutionary, especially when compared to Almighty Thud methodologies which emphasized writing lots of documentation, which were the norm in the Waterfall era. (The Almighty Thud is the name for the noise made by the volume of paper documentation hitting one's desk.)

In fact, XP is still revolutionary, inasmuch as you haven't yet personally practiced its propositions.

Software is a tamagotchi

The main conflict I see in software development is this: Agile promises continuous delivery of value (something like delivering features all the time), but software development simply isn't like that.

Expecting a development team to deliver only features all the time is as realistic as expecting a human being to be of service to their significant other all the time. The reality is, the human and the team need some time to themselves.

Business people start with this idea that software is a project with a beginning and an end. "I will develop an app, then sit back and profit." Nothing could be further…

Reality is like Chacon said:

Software is a tamagotchi. It has its own needs, that must be tended to.

The problem is, business people cannot see the virtual pet or its demands, if they cannot program. A programmer can try to explain it to them, but they get bored quickly.

This tamagotchi is a mythical creature. Only little children can see E. T., grownups cannot. And only developers can see the needs of the software; they are invisible to the marketing team.

This past week I upgraded packages in our Linux servers because of the recently discovered openssh vulnerability. If you have servers, you have to be on top of security, there is no alternative.

— Yeah, but as a business person, I absolutely CAN see the value and importance in that work, since not having our users' passwords stolen is a major component of their satisfaction.

Okay, then I suppose sometimes you can see the tamagotchi demanding we do things that our users are completely unaware of.

Let me try another example then. We really have to do some work on the way we use our asynchronous queue system. You see, things like sending emails, talking to external APIs, anything that isn't instantaneous... these things are done in separate processes, in a queue. That queue is known as FIFO, which means First In, First Out, which means first come, first served. The queue is a buffer for tasks that the app needs to do. But the queue has certain features that we need to start using in order not to have problems in it, which would be a terrible situation.

— That's too technical for me, you seem to be saying words. If I were to prioritize that work, I think I would actually never prioritize it, I think, because I have features that our users actually want, and those I do understand.

…and this is an example of the virtual pet dying of starvation, because the parents didn't understand its importance.

Technical debt

It is a terrible thing, when instead of the whole team choosing what needs to be done in the next sprint, it gets dictated by a non-technical Product Owner who leaves technical debt on the wall forever gathering spiders' webs, until it falls on the ground and gets swept away by someone who doesn't think they are important.

A good rule for solving technical debt had already been proposed in XP: refactor before you implement a new feature. This means, remove the technical debt that affects the feature you are about to implement. It also means, leave alone the technical debt that does not affect the code you need to change. Some technical debt exists in code that never gets changed, and that is okay if the code is working fine.

By the way, bugs are not technical debt, bugs are bugs. Bugs annoy users, technical debt "only" annoys developers. Generally, solving bugs is the most important priority, because if you leave bugs alone, they start compounding. Then when you finally decide to kill them, you can't tell anymore where one starts and ends, because they have become this multi-headed monster. Nobody can understand the behavior of a buggy system; a sane mind can only understand sane behavior.

However, annoying developers is a terrible thing too, and that is what business people don't understand.

Clean code

There's a second document about Agile, also very brief, which tries to clarify the Agile Manifesto. It's the 12 Principles behind the Agile Manifesto. Again I invite you to read them.

Here's a bit I would like to emphasize:

Agile processes promote sustainable development. The sponsors, developers, and users should be able to maintain a constant pace indefinitely. Continuous attention to technical excellence and good design enhances agility.

This means, agile is not supposed to be a tool against developers. This means the maintainability of the code is valuable, and important to agility.

Any psychologist will tell you, before you can love other people, you need to actually love yourself.

As a developer, each day you must do something to improve your own life. Nobody else is going to do that for you. They will even have difficulty understanding that an annoyed programmer is a much slower programmer, naturally and for good reason. It's hard to put something in production when you can't get past development.

Martin Fowler, a famous and respected British author who writes the best descriptions of ideas in software development, while offering the sanest opinions, went through the trouble of cataloguing and describing the various refactorings, in his famous 1999 book Refactoring. He is also one of the first signataries of the Agile Manifesto.

Why would he write Refactoring if technical debt were not important enough to fix???

Oh, and here is his description of technical debt.

Robert C. Martin, a very important author whose name you also find under the Agile Manifesto, is sort of saying the same thing, when he says, the only way to go fast, is to go well.

A large application cannot be built without lots of discipline. A mature programmer knows this and takes pride in the discipline, just like a practitioner of martial arts or a musician.

Robert C. Martin, in fact, goes beyond the XP rule. He notices that people are about to start dying due to badly written software, or maybe already are dying. So he says, when the thing works, do not stop and deliver it. When the thing works, you are only half done. Now you have to clean it up. Remove all the technical debt, make it easy for other programmers to understand. Make it easy even for you yourself to understand it after 2 months! Remove the useless tests, finish writing the good ones. Refactor the spaghetti, rename the badly named functions. Treat your program like a poem.

If the company places excessive pressure on developers, it is an engineer's duty to be firm and say no, especially if people's health is directly or indirectly at stake. This is the ultimate test of a true professional. You do know that "I was just following orders" does not convince. Show some character strength when your turn comes.

If developers do not self-police in this way, people will die due to buggy programs, and then the legislators will legislate software development, and the result will be much worse. This is what Martin says, and it's hard to disagree.

As a developer, do love your users, but love yourself first. You can't be of use to your users, or the company, or your family, if your software becomes unmaintainable.

In other words, no matter how much you love your user, you can't be used by him all day long!

When a musician gets popular, she often needs to put her foot down and say "no, only 2 shows a week maximum and that's final". Otherwise there's no time to hone her craft. These companies always want you for what you already know, but never want you to spend any time learning what you need to learn to stay relevant. It's up to you to draw the line.

According to Woody Zuill, teams and managers should spend the time to make the work easy to do.

Allen Holub has a heuristics page in which he briefly explains agile in his own words. At the time I am writing, number 15 reads: "Quality is not negotiable. (This rule applies to all aspects of quality, not just testing.)"

Conclusion

When bad managers use Scrum against developers and basic development needs, that is in fact against Agile principles.

A solution for our woes will be found in a proper implementation of Agile ideas – not in mistakenly escaping those ideas as if something better existed out there.

Mind the gurus you choose. Digital influencers can be entertaining and arouse emotions, but some of their advice is terribly misguided. To them, all the names in this article are preferable.

A written impression

I'd like to show you a written impression. Here is how the Brazilian elite of São Paulo, that oh so petite burgeoisie, would sum up the first chapter of the book "Pinocchio" by Carlo Collodi:

"Once upon a time dere was... a CEO? A coach? No, justy a loggy of woody. Itchy gotchy foundgy by a puur carpinter. Dgis carpinter hadgy no shoes. He hadgy never wentchy to Miami Orlando. Dgis vacation we wentchy to Miami, we buyedy dis Niky Air. And she buyedy a New Balance and lots of maquiage in Macy's. You can buy a New Balance on de internetty butty de American one is diferaintchy, muchy better. We also bringy de iPhoney for her and de MackyBoocky Air for me oh, and a Reebocky for Allison, and one Androidy tablety for each one. De screens are so brighty our eyes hurty. We watchy Nettiflix and play Farmy and Sugar Crushy. We wenty to Disney and Sea Wordy in Orlando. No, we don'ty liky Epickotty Center. We liky shoppin center. In de Fri Shopi we buyi wiscky andy vodka andy a new Playstation for Allison. You wantchy caipirinha? Is exclusive!"