Notes

    Note #17

    +---+---+---+---+---+---+---+---+---+---+
    | |
    +---+ + +---+---+ + +---+---+ +
    | | | | | |
    +---+ +---+---+ + +---+ + + +
    | | | | | | |
    + + +---+ +---+ + +---+---+ +
    | | | | | | |
    +---+---+---+ +---+---+---+---+---+ +
    | | |
    + +---+ +---+ +---+ +---+---+ +
    | | | | | |
    +---+ + + +---+---+ + + + +
    | | | | | | | |
    +---+ +---+ +---+ + + + + +
    | | | | | | | |
    + + + + +---+ +---+ +---+ +
    | | | | | | | |
    +---+ + +---+---+ + +---+ + +
    | | | | | | |
    +---+---+---+---+---+---+---+---+---+---+
    RNG Seed: 1060052695

    Note #16

    A nice article on game loop design for a turn based game. A Turn-Based Game Loop

    Note #15

    Bisecting as a general purpose program (instead of Git/source control specific) and my suggestions for how this should work from the usage point of view.

    The following excerpts from Git - git-bisect Documentation:

    Basic bisect commands: start, bad, good

    As an example, suppose you are trying to find the commit that broke a feature that was known to work in version v2.6.13-rc2 of your project. You start a bisect session as follows:

    Once you have specified at least one bad and one good commit, git bisect selects a commit in the middle of that range of history, checks it out, and outputs something similar to the following:

    Terminal window
    $ git bisect start
    $ git bisect bad # Current version is bad
    $ git bisect good v2.6.13-rc2 # v2.6.13-rc2 is known to be good
    $ git bisect
    Bisecting: 675 revisions left to test after this (roughly 10 steps)
    $ git bisect bad
    Bisecting: 337 revisions left to test after this (roughly 9 steps)
    $ git bisect good

    The previous usage demonstrates the basics a Git bisect. Additionally, it can be automated too.

    Note that the script (my_script in the above example) should exit with code 0 if the current source code is good/old, and exit with a code between 1 and 127 (inclusive), except 125, if the current source code is bad/new.

    Terminal window
    $ git bisect run my_script arguments

    Git bisect is very cool. I had the idea of a more general purpose approach that isn’t necessarily tied to source control. There are some considerations that need satisfactory solutions though. When using Git bisect we are working within the context of a stream of commits that are selected as part of a binary search. That means the bisect input is well defined.

    With a general purpose bisect, what do those inputs look like? These are some possible usage patterns.

    • Invoke two programs sequentially and compare the outputs
      • Is the output different/longer/greater than/less than a value?
      • Does one program have a non-zero exit code, or do both programs have different exit codes?

    But this still does not explain what the input should look like. What would the bisect program pass as arguments to both processes?

    This is something I need to think about. WIP.

    Note #14

    Some articles and resources I’m collecting on Nix/NixOS. I’m pretty excited to learn about this and use it myself. A fully declarative, reproducible, and consistent system configuration is very appealing.

    Note #13

    I am tired of NPM

    The Node ecosystem is a complete mess, which is hardly new news I suppose. Today while updating some dependencies used to build my site I ran into the absurd situation where upgrading multiple dependencies NPM actually downgraded some of them - to versions nine months old.

    Terminal window
    $ npm audit fix
    npm WARN audit Updating astro to 2.10.15, which is a SemVer major change.

    I confirmed that NPM really did just do that. It had.

    package.json
    "astro": "^3.3.2",
    "astro": "^2.0.2",

    I wish I could say I’m surprised. This is my experience with NPM and the “JavaScript cinematic universe”, time and time again. Why did it decided to downgrade?

    Your guess is as good as mine, but one thing I remembered is that, unlike NPM, at least PNPM actually fucking works. I actually don’t even want to know why this happened, I simply no longer have any patience for the vast amounts of bullshit and suffering the “JavaScript cinematic universe” throws at people just trying to write code.

    So I migrated to PNPM. I barely had to change anything:

    • Prefix script entries in package.json with pnpm instead of npm
    • Convert package_lock.json via pnpm import and then delete it
    • Update the CI/CD pipeline to use pnpm and it’s cache instead of npm

    Now I enjoy fast installs, more reliable upgrades, and some peace of mind.

    Note #12

    I spent Friday evening and some of Saturday trying to understand why my site’s CI/CD build pipeline was failing. I introduced a new component for displaying Venn diagrams. This can be used anywhere, including MDX files I use for articles. Everything worked locally but failed on GitHub Actions, Netlify, and Cloudflare pages.

    I tried everything I could think of, eventually going as far as creating a new component with a new name in a new directory under the suspicion Git was somehow to blame. It worked.

    Even more perplexed by this, I wrapped my component in a try/catch in case the usage of happy-dom was causing a rendering failure in Astro that was somehow being interpreted as the file not existing. I use happy-dom to emulate the DOM for the sake of Venn.js - a solution I’m not happy with generally and want to replace with a more elegant and robust solution.

    It was then I realised the problem! Changes I made in the Venn diagram component were not even being tracked!

    One deep breath later I checked my .gitignore, and sure enough, any directory called astro was being ignored. The component was at /src/components/experiments/astro/VennDiagram.astro. The reason this was in my .gitignore was because in February, for some reason, I added two entries instead of one:

    coverage
    astro

    Problem solved! 😐 Here is an example Venn diagram.

    <VennDiagram
    size="medium"
    sets={[
    { sets: ['A'], size: 20 },
    { sets: ['B'], size: 10 },
    { sets: ['C'], size: 5 },
    { sets: ['A', 'B'], size: 2 },
    { sets: ['A', 'C'], size: 2 },
    { sets: ['B', 'C'], size: 4 },
    ]} />
    ABC

    Note #11

    Trying out maths rendering via markdown.

    This is an inline equation: , followed by a display style equation after lots more lines of paragraph to test vertical alignment of inline expressions as well as the standalone expressions. Here is also some styled text.

    This is another inline expression followed by a normal expression, which align to the middle of the content:

    Area of a triangle:

    This is the configuration I have to enable this:

    astro.config.ts
    import { defineConfig } from 'astro';
    import remarkMath from 'remark-math';
    import rehypeMathJax from 'rehype-mathjax';
    export default defineConfig({
    site: 'https://www.lloydatkinson.net/',
    markdown: {
    remarkPlugins: [remarkMath],
    },
    integrations: {
    mdx({
    rehypePlugins: [
    [rehypeMathJax],
    ],
    }),
    },
    });

    Note #10

    Some topics I’d like to write about. In no particular order.

    • Code Metrics and Analytics: Write about using code metrics and analytics tools to gain insights into your codebase’s quality, complexity, and maintainability.
    • DevOps Culture: Write about the importance of a DevOps culture and how it promotes collaboration between development and operations teams.
    • Managing Tech Burnout: Share strategies for preventing and managing burnout in the tech industry, balancing work, personal time, and skill development.
    • Unit Testing Legacy Code: Explore the challenges and approaches to adding unit tests to existing legacy code, including when there’s minimal test coverage.
    • Using Design Systems: Detail how you use design systems to create consistent user interfaces and user experiences across different projects.
    • Developing Design Systems in React: Detail how a design system is designed and implemented with React.
    • Dependency Injection in Practice: Discuss real-world scenarios where you’ve applied dependency injection to improve code maintainability and testability.
    • Automating Infrastructure as Code: Detail your approach to automating infrastructure provisioning and management using tools like Terraform or CloudFormation.
    • Event-Driven Architecture: Explore the concepts of event-driven architecture and how you use events to coordinate and communicate between components.

    I have another list too but these are possibly some of my more immediate topics.

    Note #9

    Hacker News Big Brain Takes Hacker News Big Brain Takes

    At this point it’s not even worth explaining for the 100th time why this is a stupid question. I’m just going to post this meme and move on. Taken from this post Ryujinx: Experimental Nintendo Switch Emulator written in C#.

    Note #8

    I’ve stopped using Vue. In fact, I just deleted twenty eight repositories and archived the remaining twelve (there’s a bunch of private repos I didn’t count in this).

    In fact, I have not used Vue since early 2022 and don’t intend to use it again. I became deeply frustrated with the tooling, direction, community, and leadership. I am completely done with fighting against the current of passive ineptitude.


    Any time I see the latest Vue thing, whether that’s a tweet demonstrating a ridiculous new “feature” that is actually a workaround for Vue’s historically poor TypeScript support, an old GitHub issue I was involved in finally getting a comment months or years later, or yet another pattern that copies developments in other frameworks without considering the ergonomics of doing so - it’s all the same: problems that shouldn’t have existed in the first place.

    I used Vue from 2016 to the end of 2021. I was an active member of it’s online developer community, mainly focussed around their Discord server, before that succumbed to incompetent moderation.

    I also noticed a strong bias among developers using Vue across the board:

    • Often brand new to development or a junior developer. There is a distinct lack of experienced or knowledgable developers in the Vue community. This is a vicious cycle as more and more content and information is created by these same developers and then taken at face value by newer developers.
    • I consider myself one of the more experienced developers in the Vue community and indeed I had their Discord “MVP” role for a few years. Outside of that circle, there is not much.
    • It’s very hard to find highly technical or informative discussions about Vue. On the other hand, I could spend five minutes and probably find a dozen articles, videos, and tweets about a particular React feature.
    • A strong unwillingness to learn new patterns or explore new ideas. Still to this day I see people attaching useless shit to the Vue global prototype and then littering this kind of code throughout all their components.

    The Vue tooling situation is fragmented and full of needlessly deprecated tools:

    • Vue CLI was deprecated in favour of Vite but with none of the configuration people interested in high quality code had come to rely on (unit testing, linting, formatting)
    • I tried to address this specific concern in a GitHub issue but as usual with the Vue core team: silence.
    • A new major version of Vuex was due and instead of making it a new major version they opted to release a totally new library called Pinia further fragmenting the user base
    • The VS Code extension is now on it’s second iteration - and it seems like the second iteration now needs two different extensions installing

    Of course, when asked why they do this they say something like “that’s how I’ve always done it”. When pressed further, they won’t understand that this makes reasoning about the code harder because of the implicit shared global state (one of the points of a framework is to make shared state easier to maintain and mutate not harder!).

    Without fail, the developers writing this sort of code do not write unit tests and might even be completely unfamiliar with the term. Bonus points if they also do not use async/await.

    loadCustomers () {
    Vue.$api.getCustomers().then((response) => this.customers = response);
    }

    This is but one problem of an entire catalogue of poor practices and mistakes I see consistently in Vue projects. I find it frustrating that these same problems like this particular one are still so prevalent meanwhile the more competent side of frontend developments has made huge progress in this space. You only have to spend five minutes looking into TanStack Query to see how asynchronous API calls are made in modern React projects.

    Moving onto the topic of DX and developer tooling, so many of Vue’s developer tooling problems stem from the decision to invent a file format for Vue components instead of using widely accepted standards like JSX and TSX. Of course, both of these can be used but does anyone? Hardly. You won’t find them mentioned in the docs without specifically searching for it.

    Earlier when I referred to new “features” that are workarounds due to poor TypeScript support, the following screenshot of the docs is an example of exactly what I meant.

    Vue is a meme

    Seriously, it does not supported imported types? That is a completely normal thing to do with any framework that supports JSX/TSX such as React. Or, to phrase it more generally importing things is a normal thing to do in any language but Vue’s tooling once again breaks default semantics. This is something I could imagine being the case for an experimental beta feature. This warning has been there for at least a year and a half.

    Although I could write an entire article diving deeply into more of these problems, I’ll finish off with one final point. The quality of most Vue codebase’s is firmly on the lower end. It’s so bad in fact that I suggest to you try and see for yourself. Find a library that solves a common problem, and then look for the React and Vue version of it. Assuming a Vue version exists, compare the code quality of the React and Vue versions.

    • You’ll be lucky to find maintainable code in the Vue version
    • You probably won’t see any unit tests and the code will be written in such a poor manner that retrospectively adding tests would be difficult
    • If you tried to raise any of these concerns or create a PR to fix these issues it would probably be ignored indefinitely

    I often opted to write my own version of a Vue library to ensure the code is not a complete shitshow and has tests. The downside of this is it’s more code to maintain, but at least I know it can be maintained, unlike whatever amateur hour code was in the original library.

    I’ve been using React for a while now and I am much happier:

    • React and TypeScript work so well together, I’ve never had a problem or had to make an issue on GitHub to fix something like the time I did for TSX support in Vue.
    • The community is more vibrant, engaged, and welcoming. Welcoming is certainly not a word I would use to describe the Vue community.
    • Hooks feel like a much more natural approach to declarative state compared to Vue’s copy and paste version of Hooks.

    Note #7

    I’ve been looking at Rust recently and I wrote a small Rust program that uses traits, a concept very similar to interfaces in other languages. There’s a lot to learn but this seems reasonable.

    struct Message {
    id: i32,
    text: String,
    }
    trait Printer {
    fn print(&self, value: &str);
    }
    struct ConsolePrinter {}
    impl Printer for ConsolePrinter {
    fn print(&self, value: &str) {
    println!("{}", value);
    }
    }
    fn main() {
    let messages = vec![
    Message {
    id: 1,
    text: String::from("Hello world"),
    },
    Message {
    id: 2,
    text: String::from("How are you?"),
    },
    Message {
    id: 3,
    text: String::from("Goodbye"),
    },
    ];
    let printer = ConsolePrinter {};
    for message in &messages {
    printer.print(&message.text)
    }
    }

    Note #6

    I saw some interesting statistics published by Vaihe regarding Astro and the usage of various tools and frameworks with it.

    As I’ve been working on data visualisation components recently, and given my site is also written in Astro (with some Preact/React in places), I thought it would be fun to visualise some of these statistics about Astro using Astro. One of the components I’ve been working on is a stacked value chart, which I’m using here.

    <ProseIsland>
    <ActivityChart
    options={{
    format: 'percent',
    size: 'medium'
    }}
    data={[
    { label: 'With React', value: 0.258, color: '#009d88' },
    { label: 'Without React', value: 0.742, color: '#00bf63' },
    ]} />
    </ProseIsland>

    How many Astro sites use React

    Without React: 74.2% With React: 25.8%
    1. Without React 74.2%
    2. With React 25.8%

    The popularity of Tailwind among Astro sites

    No Tailwind: 55% Use Tailwind: 45%
    1. No Tailwind 55%
    2. Use Tailwind 45%

    Estimating how many Astro sites use SSR vs. SSG

    SSG: 79% SSR: 21%
    1. SSG 79%
    2. SSR 21%
    Node: 39.3% Vercel: 23.8% Cloudflare: 18.6% Netlify: 15.2% Deno: 3.1%
    1. Node 39.3%
    2. Vercel 23.8%
    3. Cloudflare 18.6%
    4. Netlify 15.2%
    5. Deno 3.1%

    How many Astro sites use a JavaScript framework

    JavaScript framework: 64.1% No JavaScript framework: 35.6%
    1. JavaScript framework 64.1%
    2. No JavaScript framework 35.6%
    React: 40.4% Svelte: 17.6% Vue: 17.4% Preact: 12.2% Solid: 6.4% Lit: 3.4% Alpine: 1.7%
    1. React 40.4%
    2. Svelte 17.6%
    3. Vue 17.4%
    4. Preact 12.2%
    5. Solid 6.4%
    6. Lit 3.4%
    7. Alpine 1.7%

    Note #5

    There is often a strong disconnect between what management believes their developers are working on and reality. Doubly so in “agile with a capital A” type environments. Leadership is often ignorant (sometimes deliberately) about developers’ genuine concerns and frustrations with the type of work environment they have to work in.

    The contrast became hard to ignore when I calculated the time and effort spent in my current job on everything but designing software the customers wanted.

    Entire teams of developers are being prevented from doing what they were hired to do: solve problems with software engineering. Instead, incredible amounts of money is spent on what can only be described as “Agile Theatre” as it has come to be known.

    Based on my experiences, observations, and notes, a somewhat disturbing story is told.

    There’s just so much bullshit.

    Fixing technical debt: 20% Bad internal tooling: 20% Bad DevOps process: 20% Meetings to discuss meetings: 20% Refactoring poor/fake tests: 10% Vague/contradictory requirements: 10% Debugging other team's code: 5% Writing new features: 5%
    1. Fixing technical debt 20%
    2. Bad internal tooling 20%
    3. Bad DevOps process 20%
    4. Meetings to discuss meetings 20%
    5. Refactoring poor/fake tests 10%
    6. Vague/contradictory requirements 10%
    7. Debugging other team's code 5%
    8. Writing new features 5%

    Note #4

    Using Jira does not make you agile

    Note #3

    I see a lot of bad text trimming code around. It usually cuts off a word mid-way through, which just looks bad. This code aligns the ellipses with the start and end of words. It returns a tuple. This approach can obviously be used in any language.

    const trimText = (input: string, length: number = 80): [text: string, trimmed: boolean] => {
    const trimmed = input.length >= length;
    const text = trimmed ? `${input.slice(0, input.lastIndexOf(' ', length))}...` : input;
    return [text, trimmed];
    };
    trimText('This is some trimmed text that will not cut off half way through a word.', 35)
    // => ['This is some trimmed text that will...', true]

    Note #2

    I couldn’t tell whether this would be considered coercion or transformation, so I’ll just go with “asserting on a type and return the required one”.

    export const foo = (date?: string | Date): string | undefined => {}

    Imagine the scenario in a JavaScript/TypeScript project where a date can be supplied as either a string or a real date object but the required end result is a string in ISO 8601 format. This code is copy pasted as-is from a project.

    const publishedDate = dates && dates.published
    ? typeof dates.published === 'object'
    ? dates.published.toISOString()
    : new Date(dates.published).toISOString()
    : undefined;
    const updatedDate = dates && dates.updated
    ? typeof dates.updated === 'object'
    ? dates.updated.toISOString()
    : new Date(dates.updated).toISOString()
    : undefined;

    Note #1

    I made this note page to contain ideas, small streams of thought, reminders, future project and article ideas.

    The first note is dedicated to my fiancée!

    Happy Valentines Day! 💕

© Lloyd Atkinson 2024 ✌

I'm available for work 💡