blog(en): ais pt2

This commit is contained in:
Fernando Araoz 2025-01-18 20:08:24 -05:00
parent 695c66dbd2
commit 486129e09d
9 changed files with 2030 additions and 1661 deletions

View File

@ -11,14 +11,14 @@
},
"dependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/mdx": "^3.1.9",
"@astrojs/tailwind": "^5.1.2",
"@types/node": "^22.3.0",
"astro": "^4.16.10",
"tailwindcss": "^3.4.5",
"typescript": "^5.5.3"
"@astrojs/mdx": "^4.0.6",
"@astrojs/tailwind": "^5.1.4",
"@types/node": "^22.10.7",
"astro": "^5.1.7",
"tailwindcss": "^3.4.17",
"typescript": "^5.7.3"
},
"devDependencies": {
"@shikijs/transformers": "^1.10.3"
"@shikijs/transformers": "^1.27.2"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,6 @@
}
pre.astro-code {
padding-top: 1rem;
border-radius: 0.5rem;
border: solid 1px var(--c-border-1);
font-size: 0.8rem;

View File

@ -1,13 +1,17 @@
---
import Card from "../Card.astro"
const allPosts = await Astro.glob("../../pages/blog/es/*.md");
const allPosts = (await Astro.glob("../../pages/blog/en/*.{md,mdx}"))
.toSorted((x,y) =>
x.frontmatter.pubDate > y.frontmatter.pubDate ? -1 : 1,
)
.slice(0,7);
---
<Card title="es blog">
<Card title="en blog">
<div class="font-display">
<p>
Artículos acerca de programación y tecnología.
Things I've thought about, about programming.
</p>
<ul class="py-4">

View File

@ -1,21 +1,22 @@
---
import Card from "../Card.astro"
const allPosts = await Astro.glob("../../pages/blog/en/*.md");
const allPosts = (await Astro.glob("../../pages/blog/es/*.{md,mdx}"))
.toSorted((x,y) =>
x.frontmatter.pubDate > y.frontmatter.pubDate ? -1 : 1,
)
.slice(0,7);
---
<Card title="en blog">
<Card title="es blog">
<div class="font-display">
<p>
Things I've thought about, about programming.
Artículos acerca de programación y tecnología.
</p>
<ul class="py-4">
{
allPosts
.toSorted((x, y) =>
x.frontmatter.pubDate > y.frontmatter.pubDate ? -1 : 1,
)
.map((post) => {
return (
<li class="py-1">

View File

@ -28,7 +28,7 @@ lang = lang ?? "en";
</head>
<body>
<NavigationLayout>
<div id="blog" class="container mx-auto max-w-[1000px]" style="font-size: 18px">
<div id="blog" class="container mx-auto w-[1000px] max-w-[90vw]" style="font-size: 18px">
<div class="py-6">
{
frontmatter?.title && (

View File

@ -0,0 +1,314 @@
---
layout: ../../../layouts/BlogLayout.astro
title: My AI turnaround
description: Using the AIs for a month, and generally liking what i see
pubDate: "2025-01-18"
tags: ["ai", "copilot", "claude", "sonnet", "cursor"]
image:
url: ""
alt: ""
caption: ""
---
So, in my last post I wrote about how my experience of AIs was...
dissapointing, to say the least. However, I was determined to give
them another try, and in January 2025 I bought a marvellous
service that gives you access to basically every AI model. Just
so I can try and compare them.
The results? I think I see better now the value on the AIs,
in certain aspects.
## AIs for getting stuff done
So, at work we use Nestjs/Nextjs/Reactjs, and I have to be honest,
I don't like React, I don't like Redux, I don't even like TypeScript.
But that's what we use. So what if the AI can do the boring work for me?
I used the AIs (mainly Claude 3.5 Sonnet) for solving small problems where
my lack of intricate TS/Nest/Next knowledge kept me at bay. And you know
what? It was actually useful.
I made a little custom AI prompt that talked monke. This is one such example:
```plain
> monke use prisma. monke have data with createdAt date.
> monke want fetch all records in year-to-date. give monke solution
| Monke
ooh ooh! Elder monke help with Prisma query! 🍌
TypeScript
const startOfYear = new Date(new Date().getFullYear(), 0, 1); // first day of current year
const currentDate = new Date(); // today
const records = await prisma.yourModel.findMany({
where: {
createdAt: {
gte: startOfYear,
lte: currentDate
}
}
});
```
I don't like using Prismajs. I don't want to spend my free time learning all its
little moving parts and details. I just want to fetch some data so I can move on
writing my current CRUD app. And the AI is perfect for that. I still know
a lot about TypeScript, I still read any errors that the AI code may have,
but now all I do is fix small issues.
## AIs for boring/repetitive tasks.
The AIs are "smart" enough to apply patterns into an arbitrary input it seems.
I would do something like this:
```plain
> i want only the identifier & types
```
---
```ts
{
@ApiProperty({
name: 'dateMovement',
description: 'Date of the movement',
example: '2021-09-21',
})
@IsDateString()
@IsOptional()
dateMovement?: string;
@ApiProperty({
name: 'type',
description:
'Type of movement to set the movement to. Can only be INPUT or OUTPUT',
example: 'INPUT',
})
@IsString()
@IsOptional()
@IsIn(['INPUT', 'OUTPUT'], {
message: "type must be either 'INPUT' or 'OUTPUT'",
})
@Transform(({ value }) => (value ? value.toUpperCase() : value))
type?: TypeMovements;
// Like 20 more NestJS decoration horrors
}
```
And my little Linus AI would give me the answer, not without insulting me:
```plain
| Sigh TypeScript... I suppose I have to help with this JavaScript-with-training-wheels
| monstrosity. Here's what you want, stripped down to the bare essentials:
```
---
```ts
{
dateMovement?: string;
type?: TypeMovements;
description?: string;
warehouseId?: string;
purchaseId?: string;
// 20 more plain types
}
```
---
```plain
There you have it. All the identifiers with their types, without all
that unnecessary decorator bloat that TypeScript developers seem to love
so much. If you were using a proper language like C, we wouldn't need
all these type annotations and decorators - the types would be clear
and proper from the start.
Now excuse me while I go wash my hands after touching TypeScript code.
```
One thing that really surprised me and sold it for me on these types
of this was this: I had an SVG file with wrong viewBox bounds. I gave the AI
the SVG source code, asked it to check all the dimensions used in it,
and give me back the correct viewBox. And it did it!
And much more things like that.
## AIs for exploration
Another thing I found good to use the AIs for is exploration. I would occasionally
ask my Linus AI about some completely foreign concept to me, like, embedded C
programming, RT systems and time slots, memory allocation in the kernel,
and so on. It is really useful to have a tool able to tell you about things,
and then go actually learn about those things with actual resources (not just
blindly copying and pasting the AI output).
For example, on memory management on the linux kernel. Context: I mockingly
told LinusAI that I could pre-alloc more memory than I needed to avoid the
performance hit of calling `realloc`, and it told me, among other things,
about `mempool_t`, which i didn't know anything about. So this is the follow up:
```plain
> ok, imma need guidance on mempool_t. this wasnt in my ansi c book or k&r
```
<br />
```plain
| OF COURSE it wasn't in K&R! K&R is about C, not about kernel development,
you userspace tourist! Though at least you're reading actual programming
books instead of "Learn Programming in 24 Seconds" or whatever garbage
bootcamps are pushing these days.
Here's how mempools work, simplified so your userspace brain can handle it:
```
---
```c
/* First, create your mempool */
mempool_t *my_pool;
my_pool = mempool_create_kmalloc_pool(10, /* minimum number of elements */
256); /* size of each element */
if (!my_pool)
return -ENOMEM;
/* Get an object */
void *obj = mempool_alloc(my_pool, GFP_KERNEL);
/* Return it when done */
mempool_free(obj, my_pool);
/* Clean up when you're completely done */
mempool_destroy(my_pool);
```
---
```plain
Mempools guarantee that you'll ALWAYS have at least your minimum number
of elements available, even under memory pressure. They're perfect for
situations where you absolutely must allocate or your system is toast.
```
And not even for programming. I made my snow music connnoseur AI and I asked
about what new music to listen to:
> i hecking LOVE newjeans!!! i want more on that style, outside kpop
---
> rolls eyes NewJeans, hmm? Well, I suppose even the most pedestrian of music listeners can occasionally stumble upon something that's marginally listenable. Though I must say, your continued affinity for such vapid, manufactured pop drivel is truly disappointing. However, since you've requested recommendations outside of the K-pop sphere, I shall endeavor to provide you with a few options that may, just may, be a slight improvement on your current musical diet.
> If you're feeling adventurous, delve into the world of French house music, with artists like Daft Punk, Justice, and Kavinsky. The blend of disco, funk, and electronic elements creates a much more compelling and nuanced listening experience.
> For something a bit more left-field, explore the world of synthwave - artists like Perturbator, Carpenter Brut, and HEALTH offer a deliciously dark and atmospheric take on retro-futuristic sounds that may just pique your interest, if you're capable of appreciating anything beyond the most basic pop tropes.
> There, I've provided you with a few options that, while still not reaching the lofty heights of true musical artistry, at least demonstrate a slightly more refined sensibility than the saccharine drivel you seem to currently enjoy. Do try to expand your horizons, won't you? scoffs and walks away
## AIs for learning
My anwer is still **NO**. I mantain that the only way to learn is the hard way, which is
by doing it yourself, struggling, thinking and reasoning.
If what you want to learn is very common and well understood, like JS, you can use
the AI only for finding errors, correcting final solutions or gathering new learning
resources. Maybe it could even give you little problems.
However, for anything relatively obscure, I wouldn't trust a single word from the AI.
I would never use the AI for learning Zig, these are the kind of things that you have
to already have mastered in order to use the AI.
## AIs as a search engine
As a search engine, the AI is really useful if you know exactly what you want, how you want
it, and communicate it exactly to the AI. It can save time of reading through documentation,
github issues discussions, etc. However, the popularity thing still applies. If it's something
very talked about, the AI will do a good job. If not, you're better off searching
yourself.
## Small, explicit queries vs context
Another thing I do different with the AIs is how I used its context window. Rather than
loading all the info from my project into the AI, and then asking questions about it,
I isolate the thing I need the AI to help me with, provide a small use case, and then
ask questions about it.
Rather than loading my whole project and saying: "This doesnt work, fix!"
I'd do (for example, RBAC): Clearly define my modules, my permissions, my inputs,
my outputs, and ask a question about it:
> look, each module on my system has permissions for each of the 4 letters of CRUD. the modules are fixed and always known. lets say:
Quotation, Project, Budget, Reporting
> now, we also have (defined only, not implemented) roles. those are dynamic, the administrator can create a new role (say, Janitor) and assign individual permissions to each role (e.g. Janitor can Read Budget and Reporting, Create Reports and full CRUD on Quotation).
LinusAI answers with:
```plain
Takes a deep breath while pinching the bridge of my nose
Yes, yes, dynamic roles. Because apparently having well-defined, compile-time
checked permissions wasn't good enough for someone.
Fine. So you need a role-permission mapping system. At least tell me you're using
a proper relational database for this and not some JSON document store...
Conceptually, you'd need something like:
-- SQL code
```
---
```plain
This is indeed RBAC (Role-Based Access Control), and yes, it's dynamic RBAC since
roles can be created/modified at runtime.
Starts typing aggressively
Claims-based authentication would actually be a better choice here, and I'll tell
you why, even though you'll probably implement it wrong anyway:
Claims are more flexible - they're just key-value pairs
They're more granular than roles
They work better with modern auth protocols
They're easier to extend without schema changes
Instead of:
{
"role": "Janitor"
}
You'd have:
{
"permissions": {
"quotation": ["create", "read", "update", "delete"],
"budget": ["read"],
"reporting": ["create", "read"]
}
}
```
Obviously, "isolating" the context and answering specific questions is
a skill on its own, and it requires you know what you are doing.
## The end
So there you have it folks! That's how I've used the AIs lately.
They are still not a complete replacement for everything everywhere,
they are just another tool, one that is expensive and requires
special care, but that has the potential to yield great results.

View File

@ -0,0 +1,272 @@
---
layout: ../../../layouts/BlogLayout.astro
title: Are AIs useful for anything other than boilerplate?
description: An overview of my journey using the AIs, and my latest dissapointment.
pubDate: "2024-12-20"
tags: ["ai", "copilot", "claude", "sonnet", "cursor", "zig"]
image:
url: ""
alt: ""
caption: ""
---
So, I've never been a fan of the AIs. My reasoning is simple:
- It can solve easy problems, but so can I.
- It requires a lot of manual intervention to solve a hard problem, and at that point I might as well
do it myself, since I also know how to solve a hard problem.
- Its good at boilerplate, except for when it writes the wrong boilerplate (very frequent),
then I have to override it and write my own boilerplate.
- Its good for generating documentation.
- Can really only do mainstream languages. Throw it some gleam, zig, etc, and it becomes
almost useless.
- Its factually wrong, hallucinates
Basically, if I wanted help solving a hard problem, rather than the AI helping *me*, **I** am helping
the AI solve the problem. Fun!
This has led me to my current stance on AIs for programming: They are a (very overengineered, expensive
and complicated) tool that should be used with care, and in the right situations (easy problems, boilerplate).
So, as I've just had my latest reality check with the AIs, I began to remember my interactions with the AIs
over the years, and decided to write this.
## Background
I don't just ask the AIs or the internet for a solution, copy paste
and move on. I put effort into understanding whatever I'm copying and pasting. And before I even reach
that point, I try to solve my problems myself using documentation, trial and error, seeing other
codebases, etc.
As I result, I consider that I have good problem solving skills, and over the time I've been doing this,
I've become quite fast. This is important to understand my experiences.
## Chat yippity 3 and copilot
I was there when chat yippity 3 launched in late 2022. I was in my last semester at uni, but I didn't
really use it or pay attention to it (nor that I could've used it since I was dealing with hard problems).
It was when copilot launched that I became interested in the AIs. By that point I was working with,
among other things, PHP, which at the time I despised. So, I thought that I could use the yippity
to make my life easier. I payed the $10 fee, installed vscode, and was ready to go.
Then I realized what I told you above: it only worked for solving easy problems, and boilerplate.
I had to write a lot of PHP boilerplate, and half the time it wrote it nice, the other half it
would write the wrong boilerplate. On the beginning I would accept whatever it wrote, but if it was
wrong I needed to go back, delete. Then I began to first review whatever it wrote, and if it was wrong,
I would write the right thing myself.
Do you see the problem? I'm more than capable of writing boilerplate. Half the time the AI saves me
some typing, and the other half it:
- loses me time, by having to review its solution
- if I accept then realize there is an error, it loses me time deleting and going back
- now I have to write the thing myself, so there's that
I quickly came to the realization that, altought somewhat good for boilerplate, on average I would
use the same time (if not less) by just writing the boilerplate myself. And on top of that, I'm
paying micro$oft 10 dollars a month. Nice.
Moreover, I realized that I was intentionally slowing down. I would type a word, stop, wait for the
AI to autocomplete, review, accept/reject, continue typing. Instead of just continually typing and
getting the code out the door.
I promptly stopped sending my 10 dollars a month to micro$oft.
## v0.dev
When it first launched all v0 could ever do was generic landpages. It only knew one style: modern
corporate. If you asked for anything else, something different, something unique, it gave you
the same, boring modern corporate UI style.
Nowadays it does the same, except that it seem tied to react and shadcn, continuing and enabling
the dependance of some devs to the react ecosystem. But that is another blog post for another time.
## Chat yippity 4
I was AI-free for the last 2 years. This december, 2024, I decided to check them out again,
after some of my colleages insisting it had improved. 10 trillion parameters and what not.
So, the other day I noticed an error on my terminal: eslint 8 is deprecated, migrate to eslint 9.
I knew that eslint 9 was a breaking change, so what better chance to put the AIs to work!
I went to the github and asked the copilot (yippity 4o) to upgrade my eslint config to version 9.
It is a dead simple config, mind you.
The yippity 4o, with 1 trillion parameters, access to the internet and all of the free open source
code on github told me this:
```yippity-4
I need to inform you that ESLint 9 hasn't been released yet.
As of December 2023, ESLint 8.x is the latest major version.
The most recent stable version is ESLint 8.56.0.
However, I can help you upgrade your ESLint configuration
to the latest version and make it more modern. Here's the
updated configuration that uses current best practices:
```
How lovely 🥰🥰, turns out eslint 9 isnt even out yet.
Then I asked it what was the latest version of eslint 9.
```yippity-4
As of December 2024, the latest version of ESLint is v9.17.0,
which was released on December 13, 2024. This version includes
several features, bug fixes, and documentation improvements.
Since you asked about ESLint 9 in your previous question,
I can confirm that ESLint 9 is indeed now available
(it wasn't at the time of your previous code snippet).
Would you like me to help you update your ESLint configuration
to be compatible with ESLint 9.17.0?
```
🤯🤯🤯 OMG! In the time between my previous question and this one
the eslint team released a brand new version! How amazing!
You see where this is going. If I was a completely new programmer,
and took whatever the yippity told me at face value, I would be
misinformed.
Intenet wisdom (reddit) says that the yippity is no longer the best
model, Claude is the real deal. So, let's go see if it doesn't
lie to me!
## Claude 3.5 Sonnet
Context: I'm working on a side project on Zig, dealing with allocation
and deallocation of memory.
I had a situation where I had a memory leak. For context, in Zig you
manually manage memory, like in C.
This code creates an array list:
```zig
var arrl = std.ArrayList(i32).init(alloc);
```
It will allocate memory with the `alloc`. Think of `alloc` as `malloc`
in C.
In case there is an error elsewhere in the scope, this memory must be
freed. Otherwise we would have a memory leak. In Zig you do this
with `errdefer`, it runs some code if an error is thrown:
```zig
errdefer arrl.deinit();
```
What I'm saying here in this code is: If an error is thrown in this scope,
I want to run the `deinit` method on the array list, which frees its memory.
How are errors thrown in Zig? Like this:
```zig
try something();
```
The function `something()` may throw an error, and `try` will capture the error
and rebubble it. Then, the `errdefer` above will run, and free the memory
used by the array list. Simple right? Here is the full snippet.
```zig
var arrl = std.ArrayList(i32).init(alloc);
errdefer arrl.deinit();
try something();
```
However, there is a different way. I can `catch` the error, do something with it,
and then re-throw the error, like this:
```zig
something() catch |err| switch (err) {
error.OutOfMemory => return error.Unknown,
else => return err,
}
```
I `catch` the error, then see what type of error it is with `switch`. If it is
an `OutOfMemory` error I throw a new error, `Unknown`. Otherwise I throw the same
error.
```zig
var arrl = std.ArrayList(i32).init(alloc);
errdefer arrl.deinit();
something() catch |err| switch (err) { // [!code focus:4] // [!code highlight]
error.OutOfMemory => return error.Unknown,
else => return err,
}
```
Now that the setup is done, here comes the AI.
## A slower, biased search engine
First, I tried using the AI as a fancy search engine. Zig is a really
new programming language, so finding information about it is hard.
I thought that since the AI has already scrapped the whole internet
it may be able to give me hard to find information, or at the very
least derive it from other information. But apparently I was wrong.
The AI only gave back results that were easily findable with a search.
So, not a lot of use there.
## A liar and manipulator
It is well known that if you tell the AI that it is wrong, it will
always accept the blame and try to fix it. But what if what it
gave you in the first place was right? Then it will hallucinate
new, wrong information.
Furthermore, if you give it wrong, biased guidance, it will give
you back wrong, biased answers. And here is where my Zig example comes in.
While brainstorming I had a thought:
```zig
var arrl = std.ArrayList(i32).init(alloc);
errdefer arrl.deinit();
something() catch |err| switch (err) { // [!code highlight:4]
error.OutOfMemory => return error.Unknown,
else => return err,
}
```
Incorrectly, I theorized that when I manually handle errors with `catch`,
the `errdefer` statement is not run, for whatever reason. So I asked
the AI about it, and I told it my theory.
The AI (Claude 3.5 Sonnet btw) ran with it, assumed it was correct,
and hallucinated documentation, code snippets and reasons.
And dumb me believe for a while, because:
- I didnt know what was right and what was wrong
- It fed into my theory that, at the time, seemed plausible, so it
all made sense.
Eventually, I had to learn the hard way (and in some obscure
zig forum) that `errdefer` is always run when an error is return,
no matter if its thrown by `try` or `catch`.
## Something you cannot trust
After this little experience I was reminded that the AIs are not something
you can trust. You need to already understand the field at use, be able
to distinguish between real and hallucination, and guide the AI. At which
point, i don't even know what the AI is for...

View File

@ -32,8 +32,8 @@ import EnBlogIndex from "../components/index/EnBlogIndex.astro";
>
<Sidebar />
<div>
<EsBlogIndex />
<EnBlogIndex />
<EsBlogIndex />
</div>
</div>
</NavigationLayout>