Creating My Own PaaS: Azure and AWS at Home (P2)

The 7 Recreations Of My PaaS

About 3 months before the creation of this post, I created a blog post reflecting on my time coding my own PaaS ( I highly recommend reading that blog post if you haven't already ). At the time I only finished about half of my PaaS - the backend, I still had to do the UI and add a few other bits and pieces. However, after completing the blog post, I wasn't all too happy with the state of the PaaS, so I decided to restart from scratch. Little did I know that this restart would not be the last.

Since then I've restarted, not once, not twice, not thrice but 7 different times. You may be wondering why, I wonder that too.. during the 7th restart, I decided that I wouldn't restart again. I knew if I kept restarting then I would take this project to the grave. Luckily the 7th version wasn't all that bad I'm quite happy with the state of my PaaS right now. So I finally decided to provide an update!

Why the 7th throw stuck?

Many hands make light work

The key difference between the 7th PaaS version and all the others is that the 7th version uses Nixpacks. For those who may not know, Nixpacks is an image builder made by Railway, it takes a project's source code and automatically builds an image for it that you can then deploy.

This "image building" part is an essential part of any PaaS because it makes or breaks the deployment process. Before I started using Nixpacks I was just throwing my own Dockerfile in a project which assumes the project is a NodeJS project, and for any other type of project, I'd have to manually make a new Dockerfile. This overcomplicated things by a lot, since I use Nixpacks now - I not only have automatic image building but my code is a lot more manageable.

Less is more, keeping things simple

Another big issue with the previous version is my tendency to overcomplicate. What I usually did was implement some sort of middleware between my app and the database that automatically caches data, and while it worked very well to make my app a lot faster, it also added a lot of unneeded complexity. In the 7th version, I tried focusing more on simplicity.

This made my code a lot less difficult to navigate and maintain, which made me enjoy working on it a lot more than I did before.

Polishing the Gem

Lastly, I feel telling myself that I won't make more versions really forced me to go back and refactor code to ensure longevity and robustness. I definitely still need to go back and refactor some more but I think it's totally manageable for now.

Cutting the Dead Weight

In the previous versions, I was using Cloudflare, not only for security and performance but also for SSL/TLS. However, I later found out that my app was extremely slow for no reason, a blank HTML page took 500ms to load - from a computer 5 feet away from the server the page was loading from. I immediately thought it was Cloudflare and tried disabling CF proxy, but it didn't help my cause, after 3 days of debugging and trying to find the cause, a friend asked me to disable Cloudflare entirely. After doing that my website was blazingly fast.

What happened was Cloudflare was routing my app's requests extremely poorly, requests for my website were coming from London. I reached out to Cloudflare and they said it was my ISP's fault, but I had friends from other continents test too and they had the same issues with it being unreasonably slow. I decided I'd just drop Cloudflare, the security benefits did not outweigh the slow speed of my site. After I dropped Cloudflare, my site's response times went from 500ms to 5ms.

New features

The new version also has a lot of new features, the biggest of which is a CD. A CD ( Continuous Deployment ) is a service that allows you to easily deploy completed code automatically. This was very needed in my case since it makes updating my PaaS a lot smoother and easier to do, which makes it easier for me to work on.

Another feature is statistics with Grafana, I can now monitor everything about my app using Grafana, which I initially only deployed to help me find the issue with load times I spoke of before, but it ended up being very insightful and I love just staring at my statistics!

Future Goals for the PaaS?

I have a few awesome plans for this PaaS, firstly - I want to add a db feature in the PaaS that allows me to easily deploy a database inside of my PaaS from a predefined image. Although I'm also content with using third-party database providers since they often offer extremely generous free tiers and also make migrating my project around a lot easier since I don't have to worry about migrating my databases, so I'm not in any rush to add this.

Another thing I want to add is a docs page, currently, nothing is documented, so it'd be a good idea to document a few things before I forget them, although if I do forget them then I can always just peak at the code, so this is also not on top of my priority list.

I think for now I can finally start migrating my projects onto my PaaS. It's been a blast working on this PaaS, I've learned so much while doing it, and I highly recommend it!


Read More

Code Craftsmanship: Never Nesting

Reviewing the practice: Never Nesting

This blog post will review a video about how to write cleaner code using a practice where you try to not nest your code. I will then give my thoughts on the video and comment on whether I think this is a good practice or not based on my personal opinions.

What is Nesting

In the video he talks about nesting your code, nesting refers to the practice of adding more code blocks within an existing code block, here's an example of a nester for loop in javascript:

for (let i = 1; i <= 3; i++) {
  for (let j = 1; j <= 3; j++) {
    console.log(`Outer loop: ${i}, Inner loop: ${j}`);
  }
}

We call this a nested for loop because there's a for-loop code block inside an existing for-loop code block. He mentions in the video that he'll refer to each indentation/nest in the code as depth, for each indentation the depth increases, one indentation is one deep, two indentations are two deep, and so on. I'll be referring to indentations similarly here.

How Never Nesting works

In the video he explains you can achieve never nesting using two methods, extraction and inversion. Here's an example to showcase both:

function example(param1, param2) {
  if (param1) {
    if (param2) {
      const convertedParam2 = (param1 + param2).toString(36)  
                    + "-" + Math.round(Math.random() * 9)

      for (let i = 0; i < convertedParam2.length; i++) {
        const letter = convertedParam[i]
        if (letter == "b") {
          return true
        }
      }

      return false
    } else {
       console.warn("Please Provide a param2")
    }
  } else {
    console.warn("Please provide a param1")
  }
}

To denest this function we can make use of the two methods mentioned earlier, first extraction, we'll take the for loop out of the function and put it into its own function.

// extracted function
function convertNumber(n) {
  const r = Math.round(Math.random() * 9)
  return param2.toString(36) + "-" + r
}

// extracted function
function containsLetter(word, letter) {
  for (let i = 0; i < convertedParam2.length; i++) {
    const letter = convertedParam[i]
    if (letter == "b") {
      return true
    }
  }

  return false
}

function example(param1, param2) {
  if (param1) {
    if (param2) {
      // extracted functions used to be here
      const convertedParam2 = convertNumber(param1 + param2)
      return containsLetter(convertedParam2, "b")
    } else {
       console.warn("Please Provide a param2")
    }
  } else {
    console.warn("Please provide a param1")
  }
}

Now we can make use of inversion, this is where we take conditions and invert them so that the rest of the code becomes the condition, removing the nesting required for the condition.

function convertNumber(n) {
  const r = Math.round(Math.random() * 9)
  return param2.toString(36) + "-" + r
}

function containsLetter(word, letter) {
  for (let i = 0; i < convertedParam2.length; i++) {
    const letter = convertedParam[i]
    if (letter == "b") return true // less nesting
  }

  return false
}

function example(param1, param2) {
  if (!param1) { // inversed condition
    console.warn("Please provide a param1")
    return
  }

  if (!param2) { // inversed condition
    console.warn("Please provide a param2")
    return
  }

   // there used to be a big nest of conditions here
   const convertedParam2 = convertNumber(param1 + param2)
   return containsLetter(convertedParam2, "b")
}

Mental Storage

He mentions that when over-nesting, he finds that he has to keep all these conditions in mind when going through the code, which becomes very hard to do the more you're nesting your code. When you denest your code, you can discard the conditions that were checked earlier in the code and you only have to focus on the core code. It makes less difficult to go through old code and understand it.

Conclusion

I completely agree with this coding methodology, and I took a lot away from this video, never nesting makes your code easier to understand and makes it more readable and promotes self-documentation by forcing you to split big functions into smaller functions. Since watching that video, I've adopted the "never-nesting" approach in my own programming, and it has significantly improved the way I write and understand code. It's a game-changer for sure!


Read More

Who is Alfred?

Alfred backstory

I mentioned in my previous blog that I wanted to start blogging to track my progress with Alfred, and since then I've had many questions about who or what "Alfred" is, in short Alfred is my life goal.

About 3 years ago, I watched a series about a millionaire with a very smart AI butler. The AI butler was capable of human speech and honestly seemed to be extremely useful. I then decided that I would make my own, and so the development of Alfred started.

Originally I wanted Alfred to be a butler who emphasized being interconnected with my devices. An example of how I would use this is say I'm at university and forgot some of my project files at home, all I need to do is pop out my smartwatch, say:

"Alfred, grab the files I worked on last night and send them to my laptop."

Alfred would then go find the files I worked on last night on my main computer, and send them to my laptop. This idea has expanded over time, Alfred is now going to be the main control of my future house.

Alfred0: Beginnings

Alfred0 is the first iteration of Alfred, and every time I completely remake Alfred from scratch I increase the version. Alfred0 development started in early 2021 and was written using the Lua programming language. I made Alfred0 run on Discord but at the time I hadn't really made Discord bots before, so Alfred0 served mostly as experimentation.

My current goal was just to pump as many features into Alfred as possible. I realized that if I kept adding more and more features, at some point Alfred would be able to do just about anything. However I quickly realized that due to my lack of experience, Alfred had many fatal flaws, and remaking him would be for the better.

Alfred1: Infinite Flexibility

Alfred1 was a breakthrough, I think that was the first time I really understood how to make discord bots. Alfred1 was also written in Lua but Alfred1 featured the ability of being infinitely flexible. I did this by making Alfred's entire codebase self-updatable, you could give Alfred some code and he'd be able to update himself with that code from anywhere, every single piece of code, every single file, every single folder in Alfred was completely customizable at any time of day. Alfred could also synchronize its codebase between devices using my own version of a git version control like github.

I realized I wouldn't ever have every possible feature I could need, so I decided to make it so I could easily just add features when I needed them. Although this ended up causing more harm than good. Since I never had to open a code editor to work on Alfred and could change Alfred's code from anywhere, I often just updated Alfred right from Discord chat. Obviously writing code in Discord chat will not result in the best code ever and over time Alfred's code became extremely unreadable. After this, I kinda stopped using Alfred and quit working on him altogether.

Alfred2: The start of something BIG

It turns out that over the development of Alfred, I've gathered a small set of friends who were big fans of Alfred, and they convinced me to start working on Alfred again. This was right around the time when ChatGPT came out and I realized that ChatGPT could improve Alfred by a ton. I decided to implement ChatGPT as the main way to communicate with Alfred. This irretation of Alfred was written in javascript.

As I kept using Alfred a friend of mine asked if he could use Alfred as well, at that time Alfred was only made with one user in mind, so I rigged the code a little to allow that friend to use Alfred independently from me, but since Alfred was not made with the intent of having multiple users, Alfred would still call that friend of mine by my name and such. That friend did give me money for using Alfred since using OpenAI's ( the company behind ChatGPT ) API cost me money. Since I rigged Alfred to work with multiple users even though that was not its intended use, the code was pretty bad, so I decided to remake Alfred but with multiple users in mind.

Alfred3: a big change in pace

Alfred3, also written in javascript, was the fourth iteration of Alfred and was made with multiple users in mind. I made a Patreon so people could pay me and then automatically get access to Alfred. This was not meant to be a way of making money, but really only a way to programmatically let people use Alfred. Over time Alfred gained some users which motivated me to become more innovative. I decided to make Alfred's AI have the ability to run predefined functions by itself. However, by the time I finished this, OpenAI already made that a dedicated feature in their AI.

Since I was using Javascript and Alfred was growing in size it became harder and harder to maintain, and there were a ton of issues in Alfred3 that were hard to fix due to how the code was poorly documented. I then decided to remake Alfred once again, but this time - changed things up.

Alfred4: The current version

Alfred4 is made in typescript, allowing me to expand Alfred without worrying too much about documentation since typescript is self-documented with, well, types. Alfred4 is a change in the right direction for Alfred, I put emphasis on making Alfred just as good as the premium ChatGPT but for cheaper.

I added features such as:

  • Google Search: Alfred realizes he doesn't know something and searches the internet to find answers.
  • Code runner: Alfred can create and run its own javascript code.
  • Inline commands: most of Alfred's commands are made inside of the AI, so you don't have to remember any syntax to run a command, you just ask Alfred what you want to do.
  • Self-info DB: a database of information about himself, allowing him to answer more questions regarding how to use Alfred.

Alfred4 is the current version of Alfred and is the fifth iteration. Alfred4 does have some problems however, it's hard to expand into other mediums, Alfred4 was not made with the intent of serving multiple types of functions, and Alfred4 was made to be a discord bot but it should not be a discord bot forever. This is going to be fixed in the next version of Alfred.

Alfred5: The Future of Alfred

Alfred5 is going to be the sixth iteration of Alfred, Alfred5 will focus on expandability, and Alfred5 should lay the groundwork for future ambitions such as a web app, desktop app, mobile app, and so on. I've already made a mobile app for Alfred3 a while ago that behaved the same as Google Assistant but just for Alfred, but that was mostly for experimentation and was completely separate from the actual Alfred codebase. Alfred5 will allow me to connect Alfred from multiple different devices and servers together into one main codebase.

This blog was made to track my progress with Alfred5, if you want more information on Alfred you can go to Alfred's website Stay tuned for updates!


Read More

0

/

2