<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Nando Florestan's blog (Posts about programming)</title><link>https://read.nando.audio/</link><description></description><atom:link href="https://read.nando.audio/categories/cat_programming.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2026 &lt;a href="mailto:nandoflorestan+read@gmail.com"&gt;Nando Florestan&lt;/a&gt; </copyright><lastBuildDate>Sat, 07 Mar 2026 00:41:39 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Revising the output of a coding assistant</title><link>https://read.nando.audio/posts/revising-the-output-of-a-coding-assistant.html</link><dc:creator>Nando Florestan</dc:creator><description>&lt;p&gt;Although I am sure using coding assistants today is bad for you, I have been trying them out.
I think it's because even our hero Kent Beck is trying them out, so I have to be open to a change of opinion.&lt;/p&gt;
&lt;p&gt;Here's something that happened, and is typical.&lt;/p&gt;
&lt;p&gt;I told it to create a command to create a user. I told it the command must be idempotent.&lt;/p&gt;
&lt;p&gt;It output this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# This command is idempotent in the sense that,&lt;/span&gt;
&lt;span class="c1"&gt;# if the user exists, it will fail gracefully:&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Add user &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;commands&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;register_cmd&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; || echo 'User might already exist or command failed'"&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above uses &lt;a href="https://pyinfra.com/"&gt;pyinfra&lt;/a&gt;, an awesome Python library that obsoletes infrastructure-as-code solutions such as Ansible.&lt;/p&gt;
&lt;p&gt;Margaret Boden divides creativity in 3 general types: combinatorial, exploratory and transformative.
I notice that the output here shows combinatorial creativity coming from the AI.
It combined its repertoire of shell usage with some Python in an attempt to satisfy my idempotency requirement.
The solution is wrong, but I think it is mildly creative.&lt;/p&gt;
&lt;p&gt;Notice the comment: "it will fail gracefully". That is only a half-truth.
The whole truth is, the &lt;em&gt;or&lt;/em&gt; converts every kind of failure into a success:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The user already exists?  'User might already exist or command failed'&lt;/li&gt;
&lt;li&gt;The command is not present in the target machine? 'User might already exist or command failed'&lt;/li&gt;
&lt;li&gt;Could not connect to the database? 'User might already exist or command failed'&lt;/li&gt;
&lt;li&gt;Out of memory? 'User might already exist or command failed'&lt;/li&gt;
&lt;li&gt;(...)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I used a model that doesn't search the web, and the training data probably didn't have much about pyinfra.
Certainly unaware of how the command works, it tried to ensure idempotency through a trick.&lt;/p&gt;
&lt;p&gt;So I had to look up the documentation and commit a correction:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;    &lt;span class="n"&gt;commands&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;register_cmd&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; --exists-ok"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above adds an argument that the command already has, that makes it idempotent.&lt;/p&gt;
&lt;p&gt;So what a human really wants from a pair programming partner here is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;for the driver to ask the helper (me), "can you please look up the arguments to this function?"&lt;/li&gt;
&lt;li&gt;instead of vomiting an inadequate solution and not even warning me.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All current LLMs (2026-03) have this bad behavior – they try to finish the project right now instead of interviewing me – even if I prompt them to not allow any assumptions to go unchecked.&lt;/p&gt;
&lt;p&gt;There's a second problem: pyinfra will, by default, not show either the output of the command or the &lt;code&gt;echo&lt;/code&gt; message, it will hide them.
The LLM here really knows nothing about pyinfra.
For brevity, I omit the solution to this.&lt;/p&gt;
&lt;p&gt;Now examine all my steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create my augmented code setup,&lt;/li&gt;
&lt;li&gt;Write a prompt,&lt;/li&gt;
&lt;li&gt;Pay for an LLM that pollutes and is currently subsidized and will soon get 10-15x more expensive,&lt;/li&gt;
&lt;li&gt;Review the code, find and understand the problem,&lt;/li&gt;
&lt;li&gt;Look up the documentation,&lt;/li&gt;
&lt;li&gt;Write code,&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Commit it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Steps 0, 1 and 2 are the ones necessary to use an LLM.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Steps 4, 5 and 6 are the steps it should have done for me.&lt;/li&gt;
&lt;li&gt;Step 3 would be unnecessary in an ideal world, but we'll probably never get there. Someone has to be responsible and sign off on the code, because LLMs cannot be trusted with any decisions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If I had simply done steps 4, 5 and 6, in this case,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I would have finished much sooner.&lt;/li&gt;
&lt;li&gt;I would have skipped 2 bugs in 6 lines of code or less.&lt;/li&gt;
&lt;li&gt;I would have read a bit of the documentation, improving my memory of it and my ability to find it in the future.&lt;/li&gt;
&lt;li&gt;I would have exercised my coding chops, which is as essential to building up my architecture ability and my software engineering ability as practicing the piano is to improving my musical skills and interpretation skills.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Writing code is a creative and pleasant activity that teaches you, makes you grow.
Reviewing code is a tiresome, difficult, arid activity that teaches you nothing, but also depends on you having written a lot of code in the past.
Nobody can be taught to review code, they can only be taught how to code.&lt;/p&gt;
&lt;p&gt;If I stop writing code and become only a reviewer, this will certainly hurt my skills.
But that is exactly what working with a coding assistant is.&lt;/p&gt;
&lt;p&gt;Code reviews also do not work, beyond a very low quantity of lines of code.
I have explained this in the past.&lt;/p&gt;
&lt;p&gt;I am seeing a lot of programmers say that working in this way is exhausting.
I think my example shows how.&lt;/p&gt;
&lt;p&gt;Now, a critic might point out that I didn't use one of the most expensive models, the ones that can search the web.
They might have answered correctly.
But if you are being honest, you know that is not the point here.
This small example is good enough as a placeholder for the kinds of mistakes that LLMs commit, such as working around problems in the wrong layer of abstraction (as it kinda did here).&lt;/p&gt;
&lt;p&gt;In the awesome lecture &lt;a href="https://www.youtube.com/watch?v=DZpR0GojoWQ"&gt;"The dangers of probably-working software"&lt;/a&gt;, the main point is "if you don't know how it works, you don't know it works".
Had I been lazy and not paid attention to the output, the problem would still be there.&lt;/p&gt;
&lt;p&gt;That is a Github employee – you know, the guys selling you CoPilot – brilliantly explaining that, if you don't review everything CoPilot writes for you – if you don't understand the code in your project to the point that it is yours – you cannot trust that code.&lt;/p&gt;
&lt;p&gt;An organization does not need code written, it needs code understood.&lt;/p&gt;
&lt;p&gt;Much beyond what is demonstrated in this example, LLMs make implicit design decisions in their code, which are usually bad, and never discussed or made explicit to you in any way.&lt;/p&gt;
&lt;p&gt;So using a coding assistant becomes a futile exercise in trying to control (specify in the prompt) every single design decision, or sometimes just running the prompt again until something good comes out.
In any case, you become a control freak.&lt;/p&gt;
&lt;p&gt;But senior programmers have an intuition about code, they get the design right sooner.
This intuition is more than a little different from a conscious enumeration of all the design decisions involved.&lt;/p&gt;
&lt;p&gt;Even if you see the AI's implicit design decisions hidden in the code, they are a great opportunity for laziness to make our lives more difficult.
In this specific project, the AI came up with a directory structure for the deployment, and I said "fine".
I only realized how horrible it was, and how difficult to navigate and understand it was, in the middle of the project, when a refactoring became necessary to fix the issue.
This refactoring involved a lot of files, it was unpleasant and a bit risky.
I really wish I had spent some time designing the directory structure myself.&lt;/p&gt;
&lt;p&gt;Laziness is a very difficult thing for humans to suppress, and no matter how disciplined I am as a programmer, I know my laziness will eventually hurt things again.&lt;/p&gt;
&lt;p&gt;In short, the more you give the reigns to the AI, the worse for your project.&lt;/p&gt;
&lt;p&gt;Ah! One more thing. If you are pairing with a robot, you are probably not pairing with a human.&lt;/p&gt;
&lt;p&gt;In conclusion, both from a philosophical/educational stance and from practical usage, I continue to believe &lt;strong&gt;using LLMs to produce code is hurtful to your project, to your real speed, to your wallet, to your organization, to our energy consumption, to the environment, to the economy, to your skills, to your memory, to your patience, to your team and social skills, to your loneliness and sense of alienation, and to software engineering as a whole.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This technology enables developers to, irresponsibly, quietly quit, producing tons of instantaneous legacy code that is impossible to maintain, while clueless managers push for more and more of the same, thinking it's the New True Way.&lt;/p&gt;
&lt;p&gt;It remains theoretically possible to code with an assistant in such a way that you gain more than you lose, but in practice, it's so hard to see how, and I think it requires such a senior and disciplined programmer to figure that out, that it's clearly not worth it.&lt;/p&gt;
&lt;p&gt;But I am just an average schmuck.
I invite you to hear a successful programmer/entrepreneur/philosopher small genius saying similar things: &lt;a href="https://www.youtube.com/watch?v=dHBEQ-Ryo24"&gt;The dangerous illusion of AI coding&lt;/a&gt;.&lt;/p&gt;</description><category>computing</category><category>programming</category><guid>https://read.nando.audio/posts/revising-the-output-of-a-coding-assistant.html</guid><pubDate>Fri, 06 Mar 2026 22:08:49 GMT</pubDate></item><item><title>Risks of adopting Flutter</title><link>https://read.nando.audio/posts/adopting-flutter.html</link><dc:creator>Nando Florestan</dc:creator><description>&lt;p&gt;&lt;a href="https://read.nando.audio/posts/crummy-web-tech.html"&gt;My previous post&lt;/a&gt; ended by recommending "something like Flutter" against the crumminess of web tech. But it is not that simple.&lt;/p&gt;
&lt;p&gt;First of all, Flutter's performance on the web is much worse than on the other platforms it supports. And this year (2024) this is not going to change because the Flutter developers said they are not working on it right now.&lt;/p&gt;
&lt;p&gt;That is enough to rule out Flutter on the web, I think. But suppose that weren't the case. Here are more thoughts about it.&lt;/p&gt;
&lt;h3&gt;The argument against Flutter&lt;/h3&gt;
&lt;p&gt;Google kills its projects without mercy. The &lt;a href="https://gcemetery.co/"&gt;Google Cemetery website&lt;/a&gt; lists tens of such projects.&lt;/p&gt;
&lt;p&gt;It is about this risk that David Heinemeier Hansson wrote &lt;a href="https://x.com/dhh/status/1790501976733807078"&gt;something I have to quote in its entirety&lt;/a&gt;:&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;The saying "nobody ever got fired for buying IBM" is at its essence about risk management. The traditional wisdom goes that if you buy from a big company, you're going to be safe. It may be more expensive, but big companies project an image of stability and reliability, so buying their wares is seen as the prudent choice. Except, it isn't. Certainly not any more. Meta killing Workplace is merely exhibit #49667.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Any company that hitched their wagon to Workplace just got served with an eviction notice. In a about a year, the data will go read-only, and shortly after that, it's game over. Now companies from Spotify to McDonalds, along with millions of others, have to scramble to find an alternative. Simply because Meta can't be bothered to maintain a platform that's merely used by millions when their consumer business is used by billions.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This, right here, is the risk of buying anything from big tech like Meta and Google. Their main ad-based cash cows are so fantastically profitable that whether it's the millions of paying accounts on Workplace or the millions of live websites once hosted by Google Domains, it all just pales in comparison, and is thus one strategy rotation away from being labeled "non-core" and killed off.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Buying from big isn't the sure bet they want you to believe. Buy from someone who actually needs your business to make the wheels go round.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;How can you be sure Flutter is going to stay around?  If Google dropped it, I doubt the open source community would be able to maintain it, just because it is a project that targets many platforms and requires many different kinds of expertises. It definitely would require professional organization similar to the Linux kernel or things like Gnome and KDE.&lt;/p&gt;
&lt;h3&gt;Arguments in favor of Flutter&lt;/h3&gt;
&lt;p&gt;If you follow DHH's advice and choose something from smaller companies, guess what, many of these aim to be bought, and then the rug gets pulled from under you anyway. If Microsoft buys the product, it starts to get worse with each update. But normally the product is bought to be killed. So the risk must be managed taking much more into account than just company sizes.&lt;/p&gt;
&lt;p&gt;The price of Flutter is right for everyone. (Zero.) Xamarin used to offer a comparable product for cross-platform development which cost a thousand dollars per developer per year. And then &lt;a href="https://www.bairesdev.com/blog/what-is-xamarin/"&gt;Xamarin was bought by Microsoft and the product was included into Microsoft's own&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cross-platform development solutions being offered by smaller organizations (that I know of), such as Qt and &lt;a href="https://kivy.org/"&gt;kivy&lt;/a&gt;, &lt;a href="https://www.reddit.com/r/kivy/comments/hmfj7l/deploy_kivy_app_as_a_web_app_possible_how/"&gt;do not seem to be equal in scope&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I should also clarify that Flutter is NOT a toy. The most recent figure is that one million applications have been built with it. That is a very significant number in the mobile space. No other cross-platform toolkit has that number.&lt;/p&gt;
&lt;p&gt;Incredibly relevant to the question of "what tech to use" is the advice given in the famous article &lt;a href="https://paulgraham.com/avg.html"&gt;"Beating the Averages", by Paul Graham&lt;/a&gt;, which you absolutely should read in its entirety.  Nevertheless, I will quote:&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;We knew that everyone else was writing their software in C++ or Perl. But we also knew that that didn't mean anything. If you chose technology that way, you'd be running Windows. When you choose technology, you have to ignore what other people are doing, and consider only what will work the best.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(...)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;When I was about nine I happened to get hold of a copy of "The Day of the Jackal", by Frederick Forsyth. The main character is an assassin who is hired to kill the president of France. The assassin has to get past the police to get up to an apartment that overlooks the president's route. He walks right by them, dressed up as an old man on crutches, and they never suspect him.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Our secret weapon was similar. We wrote our software in a weird AI language, with a bizarre syntax full of parentheses. For years it had annoyed me to hear Lisp described that way. But now it worked to our advantage. In business, there is nothing more valuable than a technical advantage your competitors don't understand. In business, as in war, surprise is worth as much as force.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Graham's weapon, the Lisp language, was not and still is not normally used in businesses. It is mostly used by academics. Nubank using Clojure (a lisp language) is a notable exception. (And Nubank's app is made with Flutter – they must be following Graham's advice.) But the main point is, don't do what everyone else is doing – do something better, which I think Flutter is, except for the Google risk.&lt;/p&gt;
&lt;p&gt;Perusing discussions about the future of Flutter, I came across &lt;a href="https://www.reddit.com/r/FlutterDev/comments/14pr5mu/comment/jqljlgq/"&gt;this comment&lt;/a&gt; from July 2023 that made a lot of sense to me:&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Connecting the dots of what Google has been doing over the past 13+ years:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Launched a system programming language called GO&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Forked little kernel to make Zircon&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Started the Fuchsia project on top of Zircon built with Go.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Launched Flutter for cross platform&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Community engagement for spreading the usage of Flutter&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Build all tool kits for complete cross platform support&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Build a large swarm of one million apps running in Flutter on play store by community&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;So I believe Google is trying to hit the IOT market as the existing operating systems are very heavy to be interfaced with smaller devices in which Zircon based hardware is a lighter option with a lot of perks. To make that hardware accessible to masses we need an operating system which is the Fuchsia. But if an operating system is introduced to the world no one is going to use it as for the adoption we require APPS. To make those apps they selected Flutter and Dart as their native language to write apps for Fuschia. Now, they've started community engagement to make flutter a widespread tool and used community to make a unified codebase for a million apps which can be made available in both the play store and the upcoming Fuschia store. This will solve the problem of NO apps in the market for newly launching OS. (The Windows Phone team thought people would make apps instead of community engagement through the years that's why they failed miserably.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Now when the new OS is launched it'll have a lot of apps which can simply be ported to support Fuchsia with minimal efforts and opens a whole new world of Zircon based hardware hitting the market interfacing with the new OS ushering a new era of IOT apps through Fuchsia.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;So Flutter is just a part of a BIG PLAN for years and not a thing made to Die by Google.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;That's all I have for you. I think Flutter is the way forward for me, but unfortunately I don't have a crystal ball to divine the future.&lt;/p&gt;</description><category>computing</category><category>flutter</category><category>programming</category><guid>https://read.nando.audio/posts/adopting-flutter.html</guid><pubDate>Thu, 23 May 2024 09:51:00 GMT</pubDate></item><item><title>The crumminess of web tech</title><link>https://read.nando.audio/posts/crummy-web-tech.html</link><dc:creator>Nando Florestan</dc:creator><description>&lt;p&gt;We make things for the web because the web is free. We want our stuff to be accessible to everyone. We don't want, for instance, the Apple police dictating whether we can update our app or not, or when, or how, or taking an enormous cut of our income.&lt;/p&gt;
&lt;p&gt;But the default web tech has always been very bad for making web applications. It was originally invented for hypertext, not apps. It has been a long "evolution", but until yesterday, it didn't even offer native popovers, so everyone had to create their own. It is safe to say that a popover component should be part of every basic app toolkit.&lt;/p&gt;
&lt;p&gt;Here are a few ways in which web tech is bad:&lt;/p&gt;
&lt;h3&gt;1. JavaScript&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;JavaScript&lt;/strong&gt; is a language that makes kittens cry every day.
It was created in a week and now we have to tolerate it forever!?
&lt;a href="https://www.destroyallsoftware.com/talks/wat"&gt;WAT&lt;/a&gt;.
The best book about it is called "JavaScript - the good parts"...
It is the only language I know with so many evil parts, other than &lt;a href="https://en.wikipedia.org/wiki/INTERCAL"&gt;INTERCAL&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;2. Standards schmandards&lt;/h3&gt;
&lt;p&gt;Web browsers implement standards differently, and devs suffer with browser support.
This will never improve: the new Popover API, which everyone wants to use, already has been implemented differently in each browser.
In 2024! My God, the story never changes!!!&lt;/p&gt;
&lt;p&gt;Therefore your &lt;strong&gt;layout breaks&lt;/strong&gt; through no fault of your own. It may work today and break tomorrow – not in theory, but in practice.&lt;/p&gt;
&lt;p&gt;Further, when your web app runs out there in weird browsers on weird phones, or just in Safari (which is always lagging like an Internet Explorer in adoption of web standards), you keep seeing very &lt;strong&gt;weird error messages&lt;/strong&gt; in your Sentry.
Hard to believe they are real.&lt;/p&gt;
&lt;h3&gt;3. CSS&lt;/h3&gt;
&lt;p&gt;CSS is always in flux. At first, one had to learn how to write semantic CSS.
Then CSS frameworks appeared, solving new problems and creating new ones.
Now everyone uses Tailwind, which is again better, but again poses the old problem of how to use CSS well.
In fact, Tailwind requires the development of very good taste about "where to put this code", because there are 4 different layers of abstraction, all of them valuable:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;global CSS (such as theme variables),&lt;/li&gt;
&lt;li&gt;components (where Tailwind defers to Bootstrap style),&lt;/li&gt;
&lt;li&gt;usage of actual Tailwind classes (with the danger of too much repetition), and&lt;/li&gt;
&lt;li&gt;inline styles, which should be very rare, but still do happen.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;4. Build pipeline hell&lt;/h3&gt;
&lt;p&gt;Typescript and &lt;a href="https://flow.org/"&gt;Flow&lt;/a&gt; are better than JS, but using them requires compilation.
Tailwind does, too.
&lt;strong&gt;Build tools&lt;/strong&gt; such as vite are hard to understand and configure, but occasionally that responsibility falls on you.
At that moment, you wish you had chosen straight JS, no build pipeline.&lt;/p&gt;
&lt;p&gt;For instance, &lt;a href="https://dev.to/tylerlwsmith/build-a-vite-5-backend-integration-with-flask-jch"&gt;this article&lt;/a&gt; teaches you how to have hot reload if you use Vite in the frontend and Flask in the backend.
It doesn't mention that you can do the opposite: Vite has a reverse proxy.
Maybe the article was written before Vite added the reverse proxy.
Anyway, the section named "A word of caution" states:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;In my 7 years of building for the web, I've used Grunt, Gulp, Webpack, esbuild, and Parcel.
Snowpack and Rome came-and-went before I ever had a chance to try them.
Bun is vying for the spot of The New Hotness in bundling, Rome has been forked into Biome, and Vercel is building a Rust-based Webpack alternative.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;5. Overactive ecosystem&lt;/h3&gt;
&lt;p&gt;The above paragraph is just one instance of a tremendous problem:&lt;/p&gt;
&lt;p&gt;The JavaScript ecosystem is overactive, oriented to excitement, with lots of packages being created all the time, and then dying in less than 5 years.
In fact, you will have a library die before you have a chance to use it.
Happened to him, happened to me.
A normal developer needs something durable, stable.
But we are unable to tell which tools are going to be responsible and stay maintained.
And the considerable force of the &lt;em title="fear of missing out"&gt;FOMO&lt;/em&gt; makes us try many alternatives.&lt;/p&gt;
&lt;h3&gt;6. Unruly npm dependencies&lt;/h3&gt;
&lt;p&gt;Controlling the dependencies of your project can be pretty impossible.
Every medium project out there depends on an unreasonable number of &lt;strong&gt;npm packages&lt;/strong&gt;, and you as app developer have a very faint idea of what most of them do.
This is dangerous. But it is also a consequence of the overactive ecosystem.&lt;/p&gt;
&lt;h3&gt;7. Legacy code&lt;/h3&gt;
&lt;p&gt;Because &lt;strong&gt;libraries and frameworks are so short-lived&lt;/strong&gt;, they put a ceiling on how much devs can accomplish before they have to reimplement their own "legacy code".
Witness Angular 2.0, which infamously gave devs no upgrade path from AngularJS 1, leaving thousands of projects orphaned.&lt;/p&gt;
&lt;h3&gt;8. Boiled frogs&lt;/h3&gt;
&lt;p&gt;Because the web is necessary, programmers learn JavaScript first and specialize in it too early.
These inexperienced developers easily become &lt;strong&gt;the proverbial boiled frog&lt;/strong&gt; – they have no idea of what a sane environment actually feels like, let alone a good programming language.
They think that world is normal.&lt;/p&gt;
&lt;p&gt;Boiled frogs will disagree with what I am saying.
Perhaps even jump to the cheap accusation of a "skill issue".&lt;/p&gt;
&lt;p&gt;A subset of the boiled frogs shrug and declare "I did my job".
They are happy to learn something new, jump ship, and leave the hand that fed them with legacy code that is only 4 years old.
That is an irresponsible and immoral thing to do.
Those people have no right to complain about planned obsolescence, or they would be hypocrites.&lt;/p&gt;
&lt;p&gt;On the other hand, developers who have a clue may dismay in the face of adversity, sometimes optimizing for ease of implementation rather than awesomeness of UI design.
Today many a developer says they prefer the backend to the frontend.&lt;/p&gt;
&lt;p&gt;If HTML, CSS and JS weren't so awful, then we wouldn't be seeing every other language compile to JS or WebAssembly or both.
&lt;strong&gt;The impetus of WebAssembly is proof&lt;/strong&gt; that many, many people agree with what I am saying here.&lt;/p&gt;
&lt;h3&gt;9. Too much learning&lt;/h3&gt;
&lt;p&gt;And now the worst part: &lt;strong&gt;the amount of learning&lt;/strong&gt; that a programmer has to constantly go through.
This is something that the boiled frogs don't see anymore, but they have been wasting their lives and brains on HTML, CSS and JS, not to mention JS frameworks in general, especially React, Vue etc. which are always imposing new concepts and new ways.&lt;/p&gt;
&lt;p&gt;FOMO makes you try new frameworks.
For instance, SolidJS suddenly offers much higher performance through a smarter observable.
But only when you use it, do you realize limitations such as...
SolidJS only likes arrays, you can't use Maps or Sets, which by the way are collections in JS that should be much more popular.&lt;/p&gt;
&lt;p&gt;99% of JS frameworks are full of leaky abstractions like that.
They seem to solve a problem but create many others by hurting all the other dreams you had for your code.&lt;/p&gt;
&lt;h3 id="history"&gt;Tiny history of the crumminess&lt;/h3&gt;

&lt;p&gt;In 1995, Netscape told Brendan Eich to quickly create a little language they wanted to add to their browser. So &lt;a href="https://thenewstack.io/brendan-eich-on-creating-javascript-in-10-days-and-what-hed-do-differently-today/"&gt;JavaScript was created in 10 days&lt;/a&gt;. Nobody expected it to become the most used language...&lt;/p&gt;
&lt;p&gt;Through the decades, &lt;a href="https://keyua.org/blog/top-alternatives-to-javascript-for-web-development/"&gt;many, many alternatives&lt;/a&gt; were created, so developers wouldn't have to suffer the crummy JavaScript. One of the most important ones was CoffeeScript (2009). Microsoft hired the designer of Delphi to create their own in 2012: TypeScript, or "C# in the browser". TypeScript basically has won. However, all these languages introduce a compilation step, because only JavaScript ran in the browser. Now developers have to wait before seeing changes on the page, which is crummy.&lt;/p&gt;
&lt;p&gt;The formatting language, CSS, was considered crummy, so they did the same thing: they invented CSS improvements which needed a compilation step down to CSS, making the total compilation time even longer and crummier.&lt;/p&gt;
&lt;p&gt;With compilation, debugging suddenly became crummy, because when an error occurred, the browser reported the error was in line 934 of a JavaScript program that you hadn't written and looked hideous. So Chrome invented source maps, solving that problem: Now the browser would map lines of code and report the error on your CoffeScript source, not the translated JavaScript source. But source maps are a heavy download and they take even more time to compile, making them crummy. For being heavy, they are never used in production.&lt;/p&gt;
&lt;p&gt;Trying to control the problem of web apps being heavier and heavier downloads in production, they added "tree shaking", which means, the compiler is smart enough to omit functions that were written but aren't actually currently used in the app. Feeling smart, they forget this is one more complicated thing that every web developer needs to know exists, and takes more compilation time, being, therefore, crummy.&lt;/p&gt;
&lt;p&gt;To give back to developers the immediacy of saving code and seeing the changes in the browser without having to wait, sophisticated build tools such as gulp, webpack, vite etc. make complex decisions about which of those things to do during development and which to do in a production build. That's not all they do, it's more complex. Anyway, they have become yet another essential tool in the toolkit, they last even shorter than web frameworks, they are hard to understand, they have hundreds of configuration options... but they solve the immediacy problem – yet again, in a crummy way.&lt;/p&gt;
&lt;p&gt;And in this manner, web development is ever more complex, and the crazy mob continues to think themselves smart after patching fundamental wounds with more and more tools.&lt;/p&gt;
&lt;p&gt;The real solution always was something like Dart (2011) or WebAssembly (2017): a hard break with crummy web tech, as long as the replacement tech were as open as the web, and designed for applications from the start. So what did the boiled frogs do? They basically ignored these. The initial plan for Dart was to include it in Chrome as the good brother of JavaScript. This was criticized for fragmenting the web, so &lt;a href="https://news.dartlang.org/2015/03/dart-for-entire-web.html"&gt;they gave up this idea in 2015&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Instead, Node.js (2009) brought JavaScript to the server, and now boiled frogs write their backend and frontend in the same language: the worst one.  Someone help them!&lt;/p&gt;
&lt;h3&gt;Searching for a solution&lt;/h3&gt;
&lt;p&gt;You thought you would develop your product, be done, sit back, let the profits come in and never work again. Then you learned Chacon's lesson: &lt;strong&gt;software is a tamagotchi.&lt;/strong&gt; Like a virtual pet, software has its own needs that must be tended to, over time, constantly. That's normal in software. What is abnormal is the furious intensity of the tamagotchiness if you use web tech: if you don't update it, in only 4 years it is legacy code that nobody wants to maintain.&lt;/p&gt;
&lt;p&gt;In short, you had a problem, so you decided to write a web app. Now you have 9 problems, with more to be expected in the future.&lt;/p&gt;
&lt;p&gt;We want to make web apps, yes. But with decent tools!&lt;/p&gt;
&lt;p&gt;Through the years I have tried many alternatives to JS, especially those that promised I could write my web apps in Python, the most legible language. But I never felt they were mature enough to actually use. They always came with serious drawbacks, such as more difficulty debugging, due to translation to JS.&lt;/p&gt;
&lt;h3&gt;Still within web tech: Mithril&lt;/h3&gt;
&lt;p&gt;The best I could do was use basic JavaScript as much as possible, avoiding frameworks that interfere in my data.
Something like &lt;a href="https://mithril.js.org/"&gt;Mithril.js&lt;/a&gt;, a reactive library with limited scope, is the best you can choose.
When I use Mithril, my state management library is {}.
Do not let a framework dictate how your data should be organized!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You must isolate your business logic from JS frameworks.&lt;/strong&gt; Write the core of your system with one principle: importing the JS framework is not allowed!
Keep the code that uses the framework very thin.
This is the only way some of your code can survive these frameworks, which usually last only 4 years.&lt;/p&gt;
&lt;p&gt;Avoiding the situation in which your entire frontend is suddenly a pile of legacy code is so important that it trumps other considerations, such as the availability of ready-made widgets for your framework.
There are only &lt;a href="https://vrimar.github.io/construct-ui/"&gt;one&lt;/a&gt; or &lt;a href="https://github.com/ArthurClemens/polythene"&gt;two&lt;/a&gt; widget &lt;a href="https://github.com/orbitbot/awesome-mithril?tab=readme-ov-file#libraries-components--plugins"&gt;libraries for Mithril&lt;/a&gt; out there.
To avoid reinventing the wheel we switch to web components (custom elements) for very complex things such as editable sortable filterable data grids.&lt;/p&gt;
&lt;h3&gt;Beyond web tech: Flutter&lt;/h3&gt;
&lt;p&gt;The crumminess of web tech is a good reason to adopt something like &lt;a href="https://en.wikipedia.org/wiki/Flutter_(software)"&gt;Flutter&lt;/a&gt;.
Since 2021, it can render on the web using Canvas.
Like a game engine, it paints the screen before it hands the pixels over to some dumb surface or canvas of the platform it is currently sitting on.
Therefore, &lt;strong&gt;my layout will never break&lt;/strong&gt;.
I will no longer care whether browsers agree on most things.
I won't have to use HTML or CSS or web frameworks.
The Dart language has been getting great features, such as null safety (2021).
Much better than JS and very similar to TypeScript, so learning Dart is easy for most.
My Sentry will certainly contain fewer weird errors from weird browsers.
And no need to ever configure a bundler.&lt;/p&gt;
&lt;p&gt;CSS? Hahahahahaah... CSS... Good one!&lt;/p&gt;
&lt;p&gt;Flutter is an open source cross-platform application development kit created by Google.
From one codebase it generates the same application for Android, iOS, web, Windows, OS X and Linux.
One million applications have been created with it.&lt;/p&gt;
&lt;p&gt;Flutter has an initial learning curve, for sure.
But in the long run, that is much less effort than keeping up with crummy web tech!&lt;/p&gt;
&lt;p&gt;What about beginning developers?
What do you think is easier, to learn HTML, then CSS, then Javascript, then Typescript, then Vue, then vite (and alternatives)... or to learn Dart and then Flutter?&lt;/p&gt;
&lt;p&gt;But one must know when to use this kind of thing on the web.
Flutter is for applications, not for content websites.
A Flutter app running on the web is a heavier and slower download, does not expose its content to search engines, and does not easily integrate with the accessibility features of the web platform.
Keep your blog in HTML, because HTML was created for hypertext.
But it wasn't created for web apps!
We have been forcing web apps onto it for years, defacing it, turning it into a monster.&lt;/p&gt;
&lt;p&gt;And the only problem is, Flutter's performance is great on every platform, except the web, and Google is not doing anything about that – not in 2024, at least.
The web seems to be a second-class platform for them.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Although I am only getting started with Flutter, it is already easy to see how developer productivity should be higher by using it instead of HTML, CSS and TypeScript.&lt;/p&gt;
&lt;p&gt;My interest is not necessarily to make iOS or Android apps, no. Just make my life easier.
Make a bloody app that will even run on the bloody web, without requiring that I use crummy web tech.&lt;/p&gt;
&lt;h3&gt;Further thoughts by other people&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=5ChkQKUzDCs"&gt;Big projects are ditching TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=e3xl5kLiyJM"&gt;Christin Gorman: Being a full stack dev is impossible&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=xh-iMBOXl6M"&gt;Radical simplicity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=aWfYxg-Ypm4"&gt;Interview with Senior JS Developer 2024&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><category>computing</category><category>css</category><category>flutter</category><category>html</category><category>javascript</category><category>programming</category><guid>https://read.nando.audio/posts/crummy-web-tech.html</guid><pubDate>Mon, 20 May 2024 10:59:03 GMT</pubDate></item></channel></rss>