Bash Arrays: From First Steps to Real-World Mastery
Bash arrays aren't just containers, they're a way to control how data flows through the shell. This guide builds from zero to production-grade patterns, using real examples like file processing and reverse lookups. 1. The Basics (Quick but Solid) Creating arrays Copy arr=(apple banana "cherry pie") Access Copy echo "${arr[0]}" echo "${arr[@]}" echo "${#arr[@]}" 👉 Always use "${arr[@]}" — this preserves elements. 2. The Rule That Changes Everything "${arr[@]}" vs ${arr[@]} Copy arr=("a b" "c d") for x in ${arr[@]}; do echo "$x"; done # broken a b c d for x in "${arr[@]}"; do echo "$x"; done # correct a b c d Without quotes, Bash: splits on spaces expands wildcards 3. Real Data: Reading Files Safely Let's start doing something real. ** Wrong way** Copy arr=($(ls)) Breaks on:…
system-designDebugging a “Slow VPS” That Wasn’t Slow
My VPS suddenly felt extremely slow: pages taking 3–5 seconds TLS handshake hanging random spikes in latency First instinct: server issue. Reality: network path instability. This is how I debugged it step by step. 1. Measure Real User Experience with curl Instead of guessing, start with actual HTTP timing. Copy curl -o /dev/null -s -w "\ DNS: %{time_namelookup}s\n\ Connect: %{time_connect}s\n\ TLS: %{time_appconnect}s\n\ TTFB: %{time_starttransfer}s\n\ Total: %{time_total}s\n" \ https://your-domain.com What each metric means DNS ( time_namelookup) → time to resolve domain → IP Connect ( time_connect) → TCP handshake (network latency baseline) TLS ( time_appconnect) → SSL/TLS negotiation (very sensitive to packet loss) TTFB ( time_starttransfer) → time until first byte from server Total ( time_total) → full request time Example (bad case) Copy DNS: 0.05s Connect: 0.30s TLS: 2.29s TTFB:…
system-designStatix: A Static Engine That Behaves Like a Dependency Graph
Most static site generators rebuild everything. Statix doesn’t. It rebuilds exactly what changed — nothing more, nothing less. This article is a deep dive into how Statix actually works internally: Symlink-based runtime theming (no rebuilds) Localized builds driven by implicit dependency graphs The admin pipeline that orchestrates rebuilds The CLI and system integration philosophy 1. Symlinks as Runtime State (Themes & Fonts) Statix treats themes and fonts as runtime configuration, not build-time artifacts. 1.1 Filesystem as Source of Truth Themes are discovered dynamically: Copy func (s *Server) listThemes() ([]string, error) { base := "/var/www/go_blog/assets/css/themes" entries, err := os.ReadDir(base) if err != nil { return nil, err } var themes []string for _, e := range entries { if !e.IsDir() && strings.HasSuffix(e.Name(), ".css") { name := strings.TrimSuffix(e.Name(), ".css") themes = append(themes,…
system-designGo Joining Errors - Learn with Examples
In Go (since Go 1.20), errors.Join lets you combine multiple errors into a single error while still preserving each individual error inside it. This is especially useful when: multiple operations can fail independently you want to return all errors, not just the first one Basic idea Copy err := errors.Join(err1, err2, err3) Returns nil if all inputs are nil Automatically ignores nil errors The resulting error wraps all the non-nil ones Simple example Copy package main import ( "errors" "fmt" ) func main() { err1 := errors.New("file not found") err2 := errors.New("permission denied") joined := errors.Join(err1, err2) fmt.Println(joined) } Output: Copy file not found permission denied Checking errors with errors.Is This is where errors.Join becomes powerful: Copy package main import ( "errors" "fmt" ) var ErrNotFound = errors.New("not found") func…
system-designStatix - I Built My Own Blog Engine (Because I Refuse to Negotiate with Markdown Toolchains).
Let me clarify something immediately. First the repo is here lol: Statix, and second This is not a “framework”. This is not a “platform”. This is not “the future of publishing”. It’s just called blog. And it does one thing extremely well: it lets me create, edit, update, and delete articles directly in the browser without negotiating with a build pipeline, a folder structure, or a philosophical manifesto. The Problem With Static Generators (Yes, All of Them) Static site generators are brilliant. Until you actually want to change something. Want to fix a typo? Open your editor → find the file → edit Markdown → rebuild → deploy → commit → push. Want to delete an article? Remove the file → rebuild → redeploy → invalidate cache → hope you…
system-designStreaming a MariaDB Dump from Go: Pipes, Syscalls, Backpressure and the Runtime
We start from a very simple handler: spawn mysqldump, capture its stdout, and stream it directly to the browser. No intermediate file. No full buffering in memory. Copy func (s *Server) handleDumpDb(w http.ResponseWriter, r *http.Request) { cmd := exec.Command("mysqldump", "-u", "root", "go_blog") stdout, err := cmd.StdoutPipe() if err != nil { http.Error(w, "pipe error", 500) return } if err := cmd.Start(); err != nil { http.Error(w, "start error", 500) return } w.Header().Set("Content-Type", "application/sql") w.Header().Set("Content-Disposition", `attachment; filename="dump.sql"`) io.Copy(w, stdout) cmd.Wait() } What looks like “just stream stdout” is in fact a multi-layered systems pipeline involving: Kernel pipes File descriptors Syscalls Scheduler decisions TCP flow control Go runtime goroutine scheduling Let’s dissect this deeply. 1. What StdoutPipe() Actually Does (Kernel-Level) When you call: Copy stdout, _ := cmd.StdoutPipe() Go performs something conceptually…
system-designDispatch Responsibility: C++ Compile-Time Power vs Go Runtime Reflection
When comparing C++ and Go, one of the most interesting differences is not syntax, not performance, and not even generics — it is where the responsibility for dispatch logic lives. In C++, behavior is encoded into the type system itself. In Go, behavior is often encoded into consumers of metadata. Both approaches are powerful. They simply operate on different axes. 1. Compile-Time Dispatch in C++ In modern C++, dispatch logic is typically resolved at compile time. You use templates, if constexpr, traits, concepts, or std::variant with std::visit. The compiler generates the final branching code. There is no runtime inspection. Example: Compile-Time Branching Here, the compiler selects the branch at compile time based on T. Only the valid branch is instantiated. Copy #include <type_traits> #include <iostream> template <typename T> void process(const…
system-designBuilding InFoEnd: An End-to-End Encrypted Chatroom in Go
InFoEnd is my first experiment with building a secure chatroom application in Go. The goal: create a real-time messaging system where messages are encrypted end-to-end, such that even the server cannot read them. To make it feel like a proper client, not just a toy, I added a terminal UI using the tview library and relied on the WebSocket protocol for message transport. The result is a multi-room chat platform that demonstrates encryption, networking, and terminal UI in one place. Architecture Overview The system consists of two roles: Admin (server) and Clients. Illustration images Server (Admin) Responsible for creating chatrooms. For each room, generates a unique 32-byte AES key. Distributes this AES key securely to clients via their RSA public keys. Once all clients of the chatroom have handshaked with…
system-designBuilding an HTTP Server in Rust Without a Framework
All code excerpts below are highlights of the full implementation. See the complete source on GitHub: julienlargetpiet/HTTP_Server. Why write your own server? When you think of writing an HTTP server in Rust, the obvious choices are production-grade stacks like Hyper, Actix-Web, or Warp. They’re excellent—and in production you should likely use them. But building a server from first principles forces you to understand what actually happens: accepting sockets, parsing a protocol, and coordinating concurrency safely. Beginner-friendly intro: HTTP and Rust in 5 minutes What an HTTP server really does Listen on a TCP port for incoming connections. Parse each incoming byte stream into a structured HTTP request (method, path, version, headers, body). Respond with a valid HTTP response (status line, headers, body). Why Rust helps Ownership & borrowing ensure memory…
system-designBuilding an Encrypted Terminal Chatroom in C - A Personal Engineering Story
I built a tiny chatroom that runs entirely in the terminal, written in C, with all messages encrypted. This article is my engineering story: why I did it, how the design evolved, what broke (and why), and the practical lessons I’m taking to my next low-level project. The code lives here: github.com/julienlargetpiet/Chat. It’s a simple, scrappy program that uses sockets, pthread, ncurses for the TUI, SDL for a small “poke” sound, and OpenSSL’s EVP API for AES encryption. Why a chatroom in C, and why the terminal? I like C for the same reason some people like rebuilding engines: it’s brutally honest. If I forget to check a return code, leak a buffer, or mix up a length, I pay the price immediately. A chatroom touches a lot of systems…
system-designSimple Compression Algorithm
I've just finished implementing a simple text compression algorithm in C++, i will talk about its implementation in this article. The programm is available here repo Or on this website as a zip zip Compression overview A function will read the file to compress and will create a std::string of its content. After, it will look for recurrent patterns. Recurrent patterns A recurrent pattern as its name suggests is a sequence of character s that is present multiple times in the scaned std::string of the input file. We can choose the length of the pattern to find. For example a pattern of length 2 is more commun than a pattern of length 3. In a sentence, we more often see "ou" than "oup". Compression level Of course, the patterns frequence…