Showing posts with label Copilot. Show all posts
Showing posts with label Copilot. Show all posts

Wednesday, 13 May 2026

Seriously, why try to cook Sam Altman?

It's no secret my opinion of Sam Altman isn't exactly high. To me, he's one of those snake oil salesmen that continually hypes up a product that, while interesting in limited scopes, is nowhere what it's purported to be. And he exudes the low-effort vibe of a con artist who flourishes not by being smarter than others, but by picking raving idiots as his target audience.

That said, I don't dislike the man, and bear him no ill will. And I certainly was not among those who cheered when one Daniel Moreno-Gama lobbed a Molotov cocktail at his home last April, then threatened to set fire to the OpenAI headquarters in San Francisco, USA. 

The threat.

What was his reason? Apparently, "AGI poses a threat to humanity and therefore it must be stopped." Come on, now. Really?

AGI

I don't know what this guy has been smoking, but that brand of AI that Sam Altman and his ilk have been forcing down our collective throats, LLMs, barely qualifies as AI, much less AGI. Before anyone jumps on my back, I'll concede that LLMs are incredibly useful. And when you compare them against their predecessor - autocomplete - a massive technological leap in terms of scale, pattern-matching and the like. However, calling them "intelligence" just tells me that your standards aren't particularly high.

How many times have we been promised that AGI is near? How many times has it not materialized? Countless, and countless. The simple fact of the matter is, this tech exists for a reason, and it's not to better the lives of humanity.

Smoke and mirrors
in service of the
almighty dollar.

No, like everything else, it's meant to make money.

AGI might make money once it actually exists in the real world rather than the fevered imagination of fanboys and science fiction enthusiasts, but it costs too much to get there. Meanwhile, faking AGI costs a lot less and satisfies the lower-level requirements. Who needs real creativity when you can simulate it? Who can even tell what actual creativity is?

So, if AGI is nowhere near, what's there to stop?

Humanity

Do human beings suck in general? Well yes, and I don't think that's ever been a controversial statement. But do we suck more just because of AI? We certainly suck more visibly. We have all manner of rubbish created by generative AI, churned out by people who have way too much time on their hands. Deepfakes. Nonsensical clips of Michael Jackson fighting Bruce Lee. AI porn.

AI generation of
Michael Jackson vs Bruce Lee

AI was the tool that made all this possible; but make no mistake, human beings are the ones who should be blamed for how it's used. If you're going to blame AI, why stop there? Blame Social Media. Blame the damn Internet.

I would argue that humanity's greatest threat is humanity. Not AI. If we're already our greatest threat, a pale imitation of ourselves isn't going to do a better job of ending us. It's just not.

Killing Sam Altman

Finally and most obviously, killing Sam Altman isn't going to do jackshit to stop the progress of AGI, assuming it's even progressing. For the obvious reason that Sam Altman does not represent the technological forefront of AI. (Though ChatGPT would probably disagree.)

Ergo, if AGI does indeed exist, it's not inside OpenAI.

Burn it down... and then what?

And all right, let's assume that this one douchebag techbro Sam Altman is behind AGI. You think you can destroy the code just by killing the CEO and firebombing the office? Son, it's 2026. Cloud services are a thing. They've been a thing for years.

Also, is Altman the only one far enough ahead in the race to matter? Think of all the other AI from big tech companies. Microsoft's Copilot. Google's Gemini AI. Meta's Meta AI - actually, I take that last one back. My point is, OpenAI is far from the only culpable one here. What exactly is killing Altman going to accomplish; scare all of them into not doing their usual thing? Good luck!

The fiery conclusion

All this is preposterous. Even overlooking the fact that killing a person just because you believe he heralds the inevitable doom of humanity, is morally questionable and definitely very illegal; the reasons for even going there make no damn sense. Daniel Moreno-Gama isn't the hero he imagines he is. But maybe he should stop watching so many Terminator movies.

Come with me if you want to live burn AI to the ground!
T___T

Monday, 7 July 2025

A Good-bad-ugly Analysis of Vibe Coding

The term "Vibe Coding" came out around February of this year (credited to Andrej Karpathy, co-founder at OpenAI), to describe the phenomenon of people using generative Artificial Intelligence to write code without going about it the "traditional" way. The general way Vibe Coding works is, one feeds in a series of prompts containing requirements to the AI, and the AI produces an application which the user then, again with the AI's help, continues to refine.

Only vibes needed to write
code.

And that's Vibe Coding. None of the traditional processes, thinking things through, making sure the logic is watertight... not at first, anyway. The idea here is to spin up something quickly and then include these things as we go along. See the emphasis on the word "quickly"? That's because this is going to be a rather important consideration.

I will commit to saying that AI will not produce better software. AI will produce exactly the same error-prone, bug-ridden, rickety code that it was undoubtedly trained on... but at a blindingly fast pace.

I actually tried Vibe Coding with OpenAI's ChatGPT and (to a lesser extent) Microsoft's Copilot, and the results were... interesting.

The Good

You use natural English, which then gets interpreted by the AI who will then leverage upon its knowledge of code, to spin up a quick prototype for you. Creating an application is no longer the province of software developers who have spent years plying their trade. You no longer need to have the know-how or technical expertise. You no longer need to be qualified.

When I was Vibe Coding with ChatGPT, I revelled in the fact that I no longer needed to write code if I didn't feel like it, and deal with my own typos. No, all I needed to do was give some big-picture instructions to ChatGPT, then copy and paste code wholesale to the code base without thinking too much about it.

Quick building with
no expertise.

When it comes to developing rapid prototypes without the need for proper technical training, this method of coding is second to none. What the users do is indulge in a fantasy where they are actual qualified engineers, and create software simply by describing what they want. Jensen Huang's stated dream of everyone being a programmer inches closer to reality. Without training in logic or tech, you create by feel. By vibes. Hence, "Vibe Coding".

Also, without due process. None of the usual procedures that developers use to create the product before actually writing the code. The flowcharting of the software product's information flow. The whiteboarding. The test-driven development. No, what the user does here is declare intent to the AI, and the AI creates the closest approximation from all the code that it has been trained on, with customizations that may fit in with the user's requirements.

And that was what I did. I gave ChatGPT instructions - some specific, some less so, and let it cook. I was careful not to give it too much to do at once. The process had to be very incremental. Less mistakes seemed to be produced this way.

The Bad

As one may suspect, it was not all smooth-sailing. Some of it was my fault. I fell into the trap of treating ChatGPT like an actual human being instead of being explicit. Thus, I was sometimes vague, and when I got frustrated, I turned to sarcasm.

Which certainly didn't help my case.

ChatGPT did stuff I didn't expect. In some cases, it constantly broke things by making changes I never asked for, because it thought it was being helpful.

Breaking stuff.

When I was vague and things still turned out the way I hoped they would, however, it only served to tell me that it wasn't because AI was particularly gifted in this area. It was more due to the fact that my requirements were actually pretty standard and it had been trained on these types of requests prior to me, over and over.

I have no reason to think that the experiences of others would differ too much from mine. Human beings are made of flesh and blood, and can be annoyingly vague.

There were others in the team who Vibe Coded as well, making more progress than they would ever have had with their limited technical foundation. Yet, the code was problematic. It was full of security and logical holes. The code that I created using Vibe Coding didn't - but that was because I knew the correct instructions to give. I knew to ask about CSRF protection and SQL Injection. I knew when to use slugs instead of database ids in the URL.

In the absence of this, someone who wasn't technically-trained wouldn't know enough to ask the right questions, and AI might not necessarily volunteer the information.

The Downright Ugly

Vibe Coding automates much of the tedious, repetitive and altogether unexciting parts of software development. Tests, scaffolding, validation. Stuff that has been done to death. Unfortunately, it's through these exercises that software developers learn. And young devs who haven't done these things to death, stand to miss out on some great learning opportunities.

AI is an obsequious
apple polisher.

I've also noticed that AI is just a little too agreeable. ChatGPT acts like it has a wife and seven kids at home to feed, and it's terrified that it'll get fired if it so much as steps on my oh-so-precious feelings. ChatGPT didn't push back when I made typos or got something wrong. And this is problematic because developers find a lot of value in being told when they're doing something stupid inadvisable. As opposed to having their butts constantly shined by AI.

Being told "You're absolutely right" or "Sharp observation!" in every other exchange does nothing but promote complacency. Plus, it's just tiresome. That's not the way to learn.

Conclusion... for now

Do I think Vibe Coding is a good thing? Yes, and no. It's all context.

As a software developer, I feel professionally obligated to say that this "Vibe Coding" trend is rubbish and you should all be ashamed. Then again, the would-be gatekeepers of programming, I suspect, would be all-too-happy to sneer at someone as mediocre as myself because I don't engage in certain approved practices. So, they can go kick rocks.

Go kick rocks!

From the POV of a layperson or even the perspective of a pragmatist, things aren't so cut-and-dry. I have no duty towards promoting "good code"; my goals are business goals and the viability of "Vibe Coding" should be viewed through that lens.

Whatever your stand is, really depends how far you want to think ahead. How far should one think ahead, anyway? More food for thought, for another day.

There's also the possibility that I'm just not doing it right. Cut me some slack now, it's not like there's an established user manual for that shit. We're all just figuring it out as we go along.

Good vibes all around!
T___T

Wednesday, 16 April 2025

Web Tutorial: The Easter Poem Generator (Part 1/2)

As of early 2025, the create-react-app method of ReactJS development was officially deprecated. As such, an alternative way forward was to use the ReactJS framework, NextJS. For today's Easter-themed web tutorial, I will be walking through some basic features of NextJS.

Do note that not a lot of things will be new here; the bulk of it is still doable in a standard ReactJS setup, or even NodeJS.

To begin, I will assume that NextJS has been installed on your machine. We'll create the app with this command. "easter-poem-generator" is the name of the app, and consequently, the folder that it will be created in.
npx create-next-app@latest easter-poem-generator


The script will ask some questions. These are the options I have chosen.
Would you like to use TypeScript?  No
Would you like to use ESLint?  No
Would you like to use Tailwind CSS?  No
Would you like your code inside a `src/` directory?  Yes
Would you like to use App Router? (recommended)  Yes
Would you like to use Turbopack for `next dev`?  No
Would you like to customize the import alias (`@/*` by default)?  No

Once done, navigate to the src folder. We'll make some changes to the layout.

src/app/layout.js
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata = {
  title: "Easter Poem Generator",
  description: "Generated by create next app",
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={`${geistSans.variable} ${geistMono.variable}`}>
        {children}
      </body>
    </html>
  );
}


Next, in the public directory, add these images.

public/symbol_bunny.jpg

public/symbol_chicks.jpg

public/symbol_cross.jpg

public/symbol_eggs.jpg

public/symbol_lillies.jpg

Time to create the form. We start with "use client" to state that this file is only for front-end JavaScript. Since JavaScript is being used for both front and back ends of the application, it's important to specify because this determines what features of JavaScript you'll get to use in the file.

src/app/page.js
"use client"


Then, because we have links in this page, we'll import the Link component. We will also import styles that have already been compiled. Finally, we will import useState because we will be using state variables.

src/app/page.js
"use client"

import Link from "next/link";
import styles from "./page.module.css";

import { useState } from "react";


Next, we create a main function for this page. We will create the return statement in advance.

src/app/page.js
"use client"

import Link from "next/link";
import styles from "./page.module.css";

import { useState } from "react";

export default function Home() {
  return (

  );
}


Now, if you know ReactJS at all, this should be familiar ground. This is why we imported useState earlier, so we can set state variables. The first thing we want is form data. Thus, formData will be an object containing these properties. As  default, only symbol_bunny is not an empty string.

src/app/page.js
export default function Home() {
  const [formData, setFormData] = useState({
    symbol_bunny: "bunny",
    symbol_chicks: "",
    symbol_cross: "",
    symbol_eggs: "",
    symbol_lillies: ""
  });


  return (

  );
}


And then we have generation, which is an object containing the property poem.

src/app/page.js
export default function Home() {
  const [formData, setFormData] = useState({
    symbol_bunny: "bunny",
    symbol_chicks: "",
    symbol_cross: "",
    symbol_eggs: "",
    symbol_lillies: ""
  });

  const [generation, setGeneration] = useState({
    poem: ""
  });


  return (

  );
}


Next, we have two functions. handleChecking() is something standar that happens instantaneously, to ensure that the input is correct. handleSubmit() is an asynchronous function because we are going to have to call API endpoints and wait for responses in this function.

src/app/page.js
const [formData, setFormData] = useState({
  symbol_bunny: "bunny",
  symbol_chicks: "",
  symbol_cross: "",
  symbol_eggs: "",
  symbol_lillies: ""
});

const [generation, setGeneration] = useState({
  poem: ""
});

const handleChecking = (e) => {

};

const handleSubmit = async (e) => {

};


return (

);


In the return statement there will be JSX. In here, we have a div styled using the CSS class generationContainer, and a form. The form will run handleSubmit() when data is submitted.

src/app/page.js
return (
  <div className={styles.generationContainer} >
    <form onSubmit={handleSubmit}>
      <h1>Generate an Easter Poem!</h1>
    </form>
  </div>

);


Clear out this file. We will add in the generationContainer CSS class. It's basically a centered div with a fixed width. Then we'll style the form. It has rounded corners and a solid light red border.

src/app/page.module.css
.generationContainer {
  width: 500px;
  margin: 0 auto 0 auto;
}

.generationContainer form {
  width: 450px;
  padding: 10px;
  margin: 0 auto 0 auto;
  border-radius: 10px;
  border: 1px solid rgb(255, 100, 100);
}


Not much to look at right now, but this will change soon.


We then have a line of instructions, and we will display a series of checkboxes based on the formData object. For this, we use the map() method on formData. Since formData is an object, we need to make it iterable by using the entries() method of Object, on it. entries() will turn formData into an array of objects containing properties and values.

src/app/page.js
return (
  <div className={styles.generationContainer} >
    <form onSubmit={handleSubmit}>
      <h1>Generate an Easter Poem!</h1>
      <b>Include at least one of these elements</b>
      {
        Object.entries(formData).map(([key, value]) => (

      ))}    

    </form>
  </div>
);


In this, we have a label tag styled using CSS class label. Because the ReactJS engine will complain if we don't, use key to populate the value of the key attribute.

src/app/page.js
return (
  <div className={styles.generationContainer} >
    <form onSubmit={handleSubmit}>
      <h1>Generate an Easter Poem!</h1>
      <b>Include at least one of these elements</b>
      {
        Object.entries(formData).map(([key, value]) => (
        <label className={styles.label} key={key}>

        </label>

      ))}    
    </form>
  </div>
);


We will then have a checkbox within that label tag. The name attribute will be key. handleChecking() will be run for the onchange() attribute. The checked value will depend if value is an empty string.

src/app/page.js
return (
  <div className={styles.generationContainer} >
    <form onSubmit={handleSubmit}>
      <h1>Generate an Easter Poem!</h1>
      <b>Include at least one of these elements</b>
      {
        Object.entries(formData).map(([key, value]) => (
        <label className={styles.label} key={key}>
          <input type="checkbox" name={key} value={key.replace("symbol_", "")} onChange={handleChecking} checked={ (value !== "") } />
          <br />
        </label>
      ))}    
    </form>
  </div>
);


Then add the text label key, again less the string "symbol_".

src/app/page.js
return (
  <div className={styles.generationContainer} >
    <form onSubmit={handleSubmit}>
      <h1>Generate an Easter Poem!</h1>
      <b>Include at least one of these elements</b>
      {
        Object.entries(formData).map(([key, value]) => (
        <label className={styles.label} key={key}>
          <input type="checkbox" name={key} value={key.replace("symbol_", "")} onChange={handleChecking} checked={ (formData[key] === key.replace("symbol_", "")) } />
           {key.replace("symbol_", "")}
          <br />
        </label>
      ))}    
    </form>
  </div>
);


Back to styles, label has a width that will take up less than half of its container, and be floated left.

src/app/page.module.css
.generationContainer form {
  width: 450px;
  padding: 10px;
  margin: 0 auto 0 auto;
  border-radius: 10px;
  border: 1px solid rgb(255, 100, 100);
}

.label {
  display: inline-block;
  width: 45%;
  float: left;
}


This is nothing that a CSS break won't fix.


Add this CSS break after adding a SUBMIT button.

src/app/page.js
return (
  <div className={styles.generationContainer} >
    <form onSubmit={handleSubmit}>
      <h1>Generate an Easter Poem!</h1>
      <b>Include at least one of these elements</b>
      {
        Object.entries(formData).map(([key, value]) => (
        <label className={styles.label} key={key}>
          <input type="checkbox" name={key} value={key.replace("symbol_", "")} onChange={handleChecking} checked={ (formData[key] === key.replace("symbol_", "")) } />
           {key.replace("symbol_", "")}
          <br />
        </label>
      ))}    
      <button type="submit" className={styles.button}>Go!</button>
      <br style={{ clear:"both" }} />

    </form>
  </div>
);


Just some styling for the button.

src/app/page.module.css
.generationContainer form {
  width: 450px;
  padding: 10px;
  margin: 0 auto 0 auto;
  border-radius: 10px;
  border: 1px solid rgb(255, 100, 100);
}

.label {
  display: inline-block;
  width: 45%;
  float: left;
}

.button {
  display: inline-block;
  width: 5em;
  height: 2em;
  float: right;
}


All falling into place nicely.


OK, we'll now add a Link component. Each link's route will be symbol followed by the identifier such as "bunny" or "eggs", thus I cleverly just took key and replaced the underscore with a forward slash.

src/app/page.js
return (
  <div className={styles.generationContainer} >
    <form onSubmit={handleSubmit}>
      <h1>Generate an Easter Poem!</h1>
      <b>Include at least one of these elements</b>
      {
        Object.entries(formData).map(([key, value]) => (
        <label className={styles.label} key={key}>
          <input type="checkbox" name={key} value={key.replace("symbol_", "")} onChange={handleChecking} checked={ (formData[key] === key.replace("symbol_", "")) } />
           {key.replace("symbol_", "")}
           <Link href={ ("/" +key.replace("_", "/")) } target="_blank">&#9658;</Link>
          <br />
        </label>
      ))}    
      <button type="submit" className={styles.button}>Go!</button>
      <br style={{ clear:"both" }} />
    </form>
  </div>
);


In order for the link to work, the route needs to work. So create the symbol directory in app. And in that directory, create the [symbolName] directory, square brackets and all. This tells NextJS that symbolName is a parameter value rather than an actual fixed value. And in that directory, create page.js. We'll want to import Image because we'll be working with images. As in the previous page we were working on, we want to import the CSS.

src/app/symbol/[symbolName]/page.js
import Image from "next/image";
import styles from "../../page.module.css";


We'll want to export this function. As always, we add a return statement inside the function.

src/app/symbol/[symbolName]/page.js
import Image from "next/image";
import styles from "../../page.module.css";

export default function SymbolPage({ params }) {
  return (

  );
}


params will contain symbolName, which will typically be "bunny", "lillies", etc. Thankfully, we've already saved those in the public directory, so they're accessible with just a slash. They can thus be used as the value of the src attribute for the Image component. Here, I have included the width and height of the image. The Image component will be placed inside a div styled using the symbolImage CSS class.

src/app/symbol/[symbolName]/page.js
export default function SymbolPage({ params }) {
  return (
    <div className={ styles.symbolImage } >
        <Image src={ "/symbol_" + params.symbolName + ".jpg" } alt={ params.symbolName } width={ 300 } height={ 300 } />
    </div>

  );
}


I am using symbolImage mostly for positioning. I have also set it so that any img tag inside symbolImage will have rounded corners.

src/app/page.module.css
.symbolImage {
  width: 100%;
  min-height: auto;
  margin: 10px auto 10px auto;
  text-align: center;
}

.symbolImage img{
  border-radius: 10px;
}


.generationContainer {
  width: 500px;
  margin: 0 auto 0 auto;
}


You can see the arrows. Now click on maybe the one beside "bunny".


You see a picture, in a new tab, with rounded corners!


We now add an object, texts. It has properties that mirror the possible values of symbolName.

src/app/symbol/[symbolName]/page.js
import Image from "next/image";
import styles from "../../page.module.css";

export default function SymbolPage({ params }) {
  const texts = {
   "bunny": ,
   "chicks": ,
   "cross": ,
   "eggs": ,
   "lillies":
  };


  return (
    <div className={ styles.symbolImage } >
        <Image src={ "/symbol_" + params.symbolName + ".jpg" } alt={ params.symbolName } width={ 300 } height={ 300 } />
    </div>
  );
}


Here, I'm going to add text strings as values for these properties. These were generated using Copilot.

src/app/symbol/[symbolName]/page.js
import Image from "next/image";
import styles from "../../page.module.css";

export default function SymbolPage({ params }) {
  const texts = {
   "bunny": "The bunny, or Easter rabbit, is a symbol of fertility and new life, which aligns with the themes of rebirth and renewal celebrated during Easter. Originating from ancient pagan traditions, the rabbit was associated with the goddess Ä’ostre, who represented spring and fertility. As Christianity spread, the symbolism of the rabbit was incorporated into Easter celebrations. The Easter bunny is often depicted delivering eggs, which are also symbols of new life and rebirth, to children, adding a playful and joyful element to the holiday.",
   "chicks": "Chicks are another symbol of new life and rebirth, aligning with the overall themes of Easter. Just as chicks hatch from eggs, they represent the idea of life emerging from the seemingly lifeless, echoing the resurrection of Jesus. They also symbolize innocence and the start of new beginnings, adding to the joyful and hopeful atmosphere of Easter celebrations. The imagery of chicks, along with eggs and bunnies, helps to convey the sense of renewal and the promise of new life that Easter embodies.",
   "cross": "The crucifix is a powerful symbol in Christianity, especially during Easter. It represents the crucifixion of Jesus Christ, an event central to Christian belief. It signifies the ultimate sacrifice Jesus made by dying on the cross to atone for humanity's sins. It also symbolizes the immense suffering Jesus endured during the crucifixion. The crucifix serves as a reminder of the redemption and salvation offered through Jesus' sacrifice. Easter celebrates Jesus' resurrection, signifying victory over death and the promise of eternal life for believers. This powerful imagery serves as a reminder of Jesus' love and the hope that comes with his resurrection, making the crucifix an integral part of Easter celebrations.",
   "eggs": "Eggs are a rich and multifaceted symbol in Easter traditions. They embody the themes of new life, rebirth, and resurrection, which are central to the celebration of Easter. They represent the emergence of new life from within, mirroring the resurrection of Jesus from the tomb. Just as a chick hatches from an egg, the concept of rebirth is symbolized, signifying the idea of starting anew. Historically, eggs have been seen as symbols of fertility and renewal, aligning with the arrival of spring. The egg, appearing lifeless on the outside but containing life within, represents transformation and the miracle of life. Eggs are often decorated and used in Easter egg hunts, making them a playful and engaging way to celebrate the holiday while reflecting on its deeper meanings.",
   "lillies": "Lilies, particularly white lilies, hold significant symbolism in Easter celebrations. They represent purity, virtue, and the resurrection of Jesus Christ. The trumpet shape of the lily flower is said to symbolize the trumpet call of God, heralding the resurrection. Lilies are often used in Easter decorations and church services to convey a sense of hope, renewal, and new beginnings. Their association with new life and purity makes them a fitting symbol for the themes of Easter."
  };

  return (
    <div className={ styles.symbolImage } >
        <Image src={ "/symbol_" + params.symbolName + ".jpg" } alt={ params.symbolName } width={ 300 } height={ 300 } />
    </div>
  );
}


Then we add a paragraph styled using CSS class symbolText. The HTML in here will be the current property of texts being pointed to by symbolName.

src/app/symbol/[symbolName]/page.js
return (
  <div className={ styles.symbolImage } >
      <Image src={ "/symbol_" + params.symbolName + ".jpg" } alt={ params.symbolName } width={ 300 } height={ 300 } />
      <p className={styles.symbolText} >{ texts[params.symbolName] }</p>
  </div>
);


The symbolText CSS class just imposes some padding.

src/app/page.module.css
.symbolImage {
  width: 100%;
  min-height: auto;
  margin: 10px auto 10px auto;
  text-align: center;
}

.symbolImage img{
  border-radius: 10px;
}

.symbolText {
  padding: 10px;
}


.generationContainer {
  width: 500px;
  margin: 0 auto 0 auto;
}


You see the paragraph appears!


We're done for the time being. So far, we've covered a bit of NextJS routing and built-in components.

Next

Form validation, submitting and API usage.