[{"content":" FreeBSD I have known about BSD ever since I got into GNU/Linux. I remember going and trying BSD and different Linux Distros and even SUN systems. Just looking at how things worked. This was about a decade ago\u0026hellip;\nI think there is a revival of more niche OS\u0026rsquo;s since GNU/Linux is splintered in more than 1 way. But the largest debate by far is systemd. There are two camps. Those that enjoy systemd (or don\u0026rsquo;t care) and those that don\u0026rsquo;t like systemd. I don\u0026rsquo;t really care, but I do enjoy simplicity and systemd is anything but. I did look at VOID Linux. Which does get rid of systemd, but then I thought, why not try a *BSD?\nSo I did. And here we are. Turns out installing it was pretty easy on a Thinkpad X230. I\u0026rsquo;m using it as my daily driver now for my netbook that I toss around, not my main laptop.\nWhy it\u0026rsquo;s awesome First, Why FreeBSD and not OpenBSD. Well my first exposure to a desktop OS running BSD when starting this project, was actually NomadBSD a great way to try it out. I tried it, runs XFCE which is great and figured I might as well try the other ones.\nBesides the cool logo of FreeBSD, it has a built in feature that I really enjoy and need. JAILS.\nThat\u0026rsquo;s right, how cool is it that I can keep daemons in Jails? Also it has Linuxulator. Which allowed me to set up this netbook as a daily driver.\nThe biggest issue I have with BSD systems is that I\u0026rsquo;m deep into GNU/Linux and protonmail. Protonmail has a bridge which allows communication between their servers and a desktop email client that is encrypted and secure. However, protonmail does not have a BSD installer. Only GNU/Linux. This is where Linuxulator comes in.\nSo, I needed GNU/Linux on BSD, so I went ahead and setup a Ubuntu Jail at /compat/ubuntu, thinking that would be enough and quick. It wasn\u0026rsquo;t. The default FreeBSD linux jail, is a lightweight. Turns out that protonmail bridge is bloat (LOL). I did pull the deb file into the jail and it failed to install with a bunch of missing libraries. After a quick search, turns out that I could just add more items to the sources.list to get the full Ubuntu experience (so I did, even though I\u0026rsquo;m sure there is a better way to do this). I went ahead and added the full archives (Universe, Multiverse, and Restricted) just to get the deb file to compile and install.\nchroot /compat/ubuntu /bin/bash # drops you into the jail instance root@x230:/# cat /etc/apt/sources.list deb http://archive.ubuntu.com/ubuntu jammy main deb http://archive.ubuntu.com/ubuntu jammy main universe multiverse restricted deb http://archive.ubuntu.com/ubuntu jammy-updates main universe multiverse restricted deb http://archive.ubuntu.com/ubuntu jammy-security main universe multiverse restricted I spent the next few hours trying to figure out why proton bridge cli would quit when I threw it on a script to auto-start on boot. Turns out that protonmail bridge cli, is waiting on a terminal session to be opened. So having it through a script it would always crash. I even tried having a TMUX instance auto start, but I still had to open the terminal and switch over to the jail and continue before I could get my emails flowing into Thunderbird/Betterbird.\nSo why did I need bridge? Why not use Hydroxide like everyone else in *BSD, well because I have split emails through proton: @fonzi.xyz @bison.software @protonmail. I need these to be compartmentalized. I then can decide which domain to listen and get notifications for, I can pick one domain and just mute the rest. Hydroxide does not offer domain splitting, plus if I\u0026rsquo;ve learned anything the most likely hacks done in third parties apps, that use an upstream service and leaks happen. So I had to find a real solution.\nFinally, after hours of pulling my hair, and staying up until 4:00AM. I found a small reddit thread. by the user u/Salonique. The function he found is amazing. Turns out that there is a tool called unbuffer which is part of the expect package. apt install expect. Finally I got the bridge to listen to a pseudo terminal that would auto start and not crash. I did strip the passphrase of the GPG key so that the bridge can self start. It\u0026rsquo;s on local and not a server so i\u0026rsquo;m not too worried about not having a passphrase there. I ended up writing a quick script and added it to the rc.conf and it auto boots now quietly.\nNow, I\u0026rsquo;m 100% automated. But the irony isn\u0026rsquo;t lost on me: I moved to FreeBSD to not use linux, only to spend hours to put linux in a Jail and an app running inside that cage. But now I have an inbox that I can use and mute on any of the domains. And it\u0026rsquo;s all running on a 12 year old Thinkpad. That should say how awesome the virtualization of a jail is and how much more superior it is than docker for this use case.\nScripting the magic In the example below you can spot the unbuffer command working it\u0026rsquo;s magic. And to get this script working, all that is needed is to add the following line in rc.conf.\n# Protonmail Bridge protonbridge_enable=\u0026#34;YES\u0026#34; fonzi@x230:~ $ cat /usr/local/etc/rc.d/protonbridge #!/bin/sh # PROVIDE: protonbridge # REQUIRE: LOGIN DAEMON NETWORKING linux # KEYWORD: shutdown . /etc/rc.subr name=\u0026#34;protonbridge\u0026#34; rcvar=\u0026#34;protonbridge_enable\u0026#34; load_rc_config $name : ${protonbridge_enable:=\u0026#34;NO\u0026#34;} # --- Configuration --- # Trying \u0026#39;proton-bridge\u0026#39; which is often the main engine binary REAL_BINARY=\u0026#34;/usr/lib/protonmail/bridge/proton-bridge\u0026#34; JAIL_PATH=\u0026#34;/compat/ubuntu\u0026#34; pidfile=\u0026#34;/var/run/${name}.pid\u0026#34; logfile=\u0026#34;/var/log/protonbridge.log\u0026#34; bridge_start() { echo \u0026#34;Starting Protonmail Bridge engine...\u0026#34; # -o captures the output to our log file /usr/sbin/daemon -f -p ${pidfile} -o ${logfile} \\ /usr/sbin/chroot ${JAIL_PATH} \\ /usr/bin/env HOME=/root TERM=xterm \\ /usr/bin/unbuffer ${REAL_BINARY} --cli --no-window } bridge_stop() { echo \u0026#34;Stopping Proton Mail Bridge...\u0026#34; pkill -f \u0026#34;proton-bridge\u0026#34; [ -f ${pidfile} ] \u0026amp;\u0026amp; rm ${pidfile} } start_cmd=\u0026#34;bridge_start\u0026#34; stop_cmd=\u0026#34;bridge_stop\u0026#34; run_rc_command \u0026#34;$1\u0026#34; *BSD Apps Another great thing about FreeBSD is that there is software ports. Basically, a bunch of GNU/Linux apps have been ported over to BSD, and they work mostly out of the box. There are some that fail, such as vscode. Which I had to manually compile on the thinkpad. Only took about 24 hours. Due to electron, but got it working. Now this blog entry was written in FreeBSD and VSCode.\nFreeBSD Documentation By far, the best part of FreeBSD, it has to be stated, the best kept-secret. DOCUMENTATION, glorious documentation. I read through the docs, felt like I was an expert, clearly not. But take into account what I accomplished in the first 8 hours of FreeBSD (and of course having linux knowledge helped a lot). Installed the OS, setup XFCE, setup most packages I need, setup the proton bridge fiasco from above, and started to compile VSCode and installed hugo ahead of time to generate the HTML for this site itself. That was all thanks to the documentation. What other OS can you hop on and learn about how it all works from top to bottom in a single documentation source? That\u0026rsquo;s the real power behind a single dev team behind a full OS not just a kernel. And the package manager? pkg install {insert name} this looks for ports too if you set that up.\nThe not so awesome. Well, like everything it has pros and cons, what don\u0026rsquo;t i like about FreeBSD, well to be honest. It\u0026rsquo;s an OS that is a lot smaller, so many hardware limitation still exists, it\u0026rsquo;s not like linux where any machine will just work out of the box. Sure you can get it working, but if you\u0026rsquo;re not into tech and tinkering or running a server, then yeah that is a downside.\nAnother thing. Once you get used to sudo in linux it\u0026rsquo;s a bit jarring to have to hop into the root account with su - every time to do anything, although I think there is a way to do sudo, I have just not set it up, but i\u0026rsquo;m trying to do it the *BSD way.\nI do know that there is a doas option, however, it\u0026rsquo;s not configured by default? At least not on my install, maybe I missed something.\nThe Logo. Yep, I like their logo so much, I figured it required it required own small section. How cool is it to see a fun little devil that does the work behind the OS. And his name is Beastie how cool is that lore behind daemons in computing. If you know you know.\n, , /( )` \\ \\___ / | /- _ `-/ \u0026#39; (/\\/ \\ \\ /\\ / / | ` \\ O O ) / | `-^--\u0026#39;`\u0026lt; \u0026#39; (_.) _ ) / `.___/` / `-----\u0026#39; / \u0026lt;----. __ / __ \\ \u0026lt;----|====O)))==) \\) /==== \u0026lt;----\u0026#39; `--\u0026#39; `.__,\u0026#39; \\ | | \\ / ______( (_ / \\______ (FL) ,\u0026#39; ,-----\u0026#39; | \\ `--{__________) \\/ \u0026#34;Berkeley Unix Daemon\u0026#34; Will I switch to *BSD? I\u0026rsquo;m not sure yet. But everything is pointing to a yes. I have been curious about other OS\u0026rsquo;s other than just GNU/Linux. However I still very much enjoy GNU/LINUX. I will more than likely continue testing the OS and see if I run into any other bottle necks. There is something magical about getting an OS and figuring out how things work and doing it yourself. Such as the protonmail bridge stuff above. It reminds me of 2008/2009 when I got my first Ubuntu CD in the mail from the UK directly from Canonical. Not everything was fully figured out and doing it yourself keeps the spirit of learning and tinkering alive and well after all these years.\nPerformance It\u0026rsquo;s worth considering how well *BSD performs on this thinkpad. I am running apps that require very little resources. VSCode is the heaviest I\u0026rsquo;d say. So here\u0026rsquo;s a btop screenshot at idle. You can see that there\u0026rsquo;s barely any resources getting used. We\u0026rsquo;ll see how it holds as the system grows and then it\u0026rsquo;ll most likley be bad app development instead of the OS\u0026rsquo;s itself.\n","permalink":"https://fonzi.xyz/blog/freebsd/","title":"FreeBSD: A Complete OS?"},{"content":" The Context: CLI Is Not the Enemy I like the CLI. I use the OpenVPN3 CLI regularly, and for servers or automation, it’s the correct interface. But a desktop environment is not a server, and a desktop user is not a shell script.\nIf COSMIC is going to succeed as a serious desktop environment, common workflows need to be discoverable and visible without requiring a terminal session. VPNs are the perfect example of this gap.\nThe Evolution: From Python to Rust This project actually started as a Python/PyQt5 application. It worked well enough as a proof of concept, but it felt like a guest on the system rather than a resident.\nThe initial Python/PyQt5 version. It proved the demand was there, but it didn\u0026rsquo;t feel \u0026lsquo;COSMIC\u0026rsquo;.\nAfter sharing the prototype on r/pop_os, the feedback was clear: if I wanted it to be a true \u0026ldquo;first-class citizen\u0026rdquo; of the COSMIC ecosystem, I needed a more performant foundation. I decided to rewrite the entire thing in Rust using the Iced framework.\nThe Rust rewrite: Faster, lighter, and much closer to the modern Linux desktop aesthetic.\nWhy the GUI Wins: Features You Can\u0026rsquo;t \u0026quot;Tail\u0026quot; A thin wrapper shouldn\u0026rsquo;t just replicate CLI commands; it should surface data that is tedious to track in a terminal.\nLive Traffic Graph: Real-time visualization of throughput (Bytes in/out) and latency monitoring. SSO \u0026amp; 2FA Support: Handles modern authentication flows by automatically handing off to your default browser and reflecting the result in the UI. Wayland Tray Integration: A functional system tray icon that works under Wayland, allowing you to monitor status without keeping the main window open. Recent Configurations: A quick-access dropdown for your most used profiles, so you aren\u0026rsquo;t hunting through directories for .ovpn files. Tech Stack: Rust, Iced, and libcosmic Choosing Rust wasn\u0026rsquo;t about being trendy; it was about stability. The app can sit quietly in the background for days with a negligible memory footprint.\nFollowing some great feedback from the System76 team (thanks mmstick!), the project is moving toward deeper libcosmic integration. This ensures the app respects the system’s theme engine (Light/Dark mode) and handles Wayland windowing exactly how COSMIC expects.\nCurrent Status The project is currently in early alpha but is already \u0026ldquo;daily-driver\u0026rdquo; ready:\nConnect / Disconnect with one click. Real-time network stats \u0026amp; session monitoring. Log Export for when things inevitably go wrong. Auto-reconnect on drop. Known quirks: I\u0026rsquo;m still refining the session persistence when the UI is closed, and the dock icon currently requires manual pinning in the alpha build of COSMIC.\nWhere to Find It The project lives here:\nhttps://github.com/fonzi/openvpn-gui-rust Feedback is welcome the scope is intentionally small to keep the project sustainable, but the goal is to make it the best VPN client for the modern Linux desktop.\n","permalink":"https://fonzi.xyz/blog/openvpn3-rust/","title":"Why I Built a COSMIC-Native OpenVPN3 GUI (Even Though I Like the CLI)"},{"content":" Auth0 The Painful Migration When we migrated our authentication to Auth0, we quickly discovered that Auth0\u0026rsquo;s session model is not designed for parallel browser automation. Running Playwright tests in parallel led to all our workers sharing the same Auth0 session, which caused flaky tests, random logouts, and a world of pain. The root of the problem is that Auth0, like many SSO providers, stores session state in browser cookies. If multiple Playwright workers use the same user, they end up overwriting each other\u0026rsquo;s sessions. This is manageable for manual QA, but a nightmare for automated, parallel E2E testing. One test might log in, another logs out, and suddenly all your tests fail.\nTo solve this, we built a Playwright fixture that dynamically discovers all available test users from environment variables. On startup, the fixture scans your .env for any variable matching patterns like uname, plusname, proname, superuser, and their numbered variants. Each variable represents a unique test user for a specific role or tier. When you run Playwright with multiple workers, each worker is assigned a unique user from the discovered pool in a round-robin fashion. For example, with eight workers and eight users, each worker gets its own user. If you have fewer users than workers, users are reused in order. Scaling up is as simple as adding more user credentials to your .env file and increasing the worker count no code changes required. Tests can still override the assigned user to log in as a different role, but each worker’s session remains isolated.\nThis architecture means you can scale your parallel E2E tests as far as you have users, with no session collisions and minimal config changes. The core logic is straightforward: scan the environment for user variables, assign each worker a user in round-robin fashion, and proceed to login with those credentials. As you add more users to your environment, your parallel test runs scale automatically.\nOne interesting outcome of this journey was how we ended up blending Playwright’s fixture system with the Page Object Model (POM) pattern. Playwright encourages the use of fixtures for dependency injection and test setup, while POM is a classic approach for encapsulating UI logic. In our solution, the auth fixture provides login/logout helpers and user context, while the actual login and logout flows are implemented as page objects. The fixture handles user assignment, session management, and exposes simple auth.login() and auth.logout() methods, while the page objects encapsulate the UI interactions for each flow. This separation keeps tests clean and readable, while making it easy to update UI logic in one place. It also plays nicely with Playwright’s parallelism and fixture injection, giving us the best of both worlds.\nThe Downside of leaving things in serial mode, and the upside of working around limitations The results speak for themselves. Before this architecture, a single deployment with nearly 3,000 tests took over 11 hours to complete due to Auth0 session collisions and forced serial execution. After implementing worker-based user isolation and true parallelization, we not only got back to our original two-hour runtime, but pushed it even further down to about 1.5 hours. This means faster feedback, more reliable releases, and a much happier team. The pain of setup is real, but the payoff is massive.\nOf course, setting this up isn\u0026rsquo;t trivial. You need to maintain a pool of test users, keep passwords and roles in sync, and update your .env and sometimes your test data when adding new users. Debugging user assignment can be tricky. But the payoff is huge: no more flaky parallel tests, true role isolation, and confidence that your auth flows work for every user type.\nIf you’re running Playwright tests against an Auth0-protected app, don’t settle for serial runs or flaky parallelism. Build (or borrow) a worker-isolated auth fixture, keep a pool of test users, and enjoy reliable, scalable E2E tests even if it takes some pain to get there.\nHere’s a diagram of how the architecture fits together:\n┌────────────┐ ┌────────────┐ ┌────────────┐ │ .env file │───▶ │ User Pool │───▶ │ Playwright │ │ (users) │ │ Discovery │ │ Workers │ └────────────┘ └────────────┘ └────────────┘ | | | | uname, plusname | Assign users | Each worker | proname, ... | round-robin | gets unique | | | session For those interested in the full implementation, here is the complete (obfuscated and genericized) Playwright auth fixture class that powers this approach:\nimport { test as base } from \u0026#39;@playwright/test\u0026#39;; // ... import your Login and Logout page objects, and any TOTP helpers as needed export type UserTier = \u0026#39;base\u0026#39; | \u0026#39;plus\u0026#39; | \u0026#39;pro\u0026#39; | \u0026#39;super\u0026#39;; type AuthFx = { user: UserTier; auth: { login: () =\u0026gt; Promise\u0026lt;void\u0026gt;; loginAs: (tier: UserTier) =\u0026gt; Promise\u0026lt;void\u0026gt;; logout: () =\u0026gt; Promise\u0026lt;void\u0026gt;; }; }; function getAvailableUsers(): { [key: string]: string } { const users: { [key: string]: string } = {}; if (process.env.name) users[\u0026#39;base\u0026#39;] = process.env.uname; if (process.env.plusname) users[\u0026#39;plus\u0026#39;] = process.env.plusname; if (process.env.proname) users[\u0026#39;pro\u0026#39;] = process.env.proname; if (process.env.superuser) users[\u0026#39;super\u0026#39;] = process.env.superuser; const envKeys = Object.keys(process.env); envKeys.forEach(key =\u0026gt; { const match = key.match(/^(name|plusname|proname|superuser)(\\d+)$/); if (match \u0026amp;\u0026amp; process.env[key]) { const baseType = match[1] === \u0026#39;uname\u0026#39; ? \u0026#39;base\u0026#39; : match[1] === \u0026#39;superuser\u0026#39; ? \u0026#39;super\u0026#39; : match[1].replace(\u0026#39;name\u0026#39;, \u0026#39;\u0026#39;); const userKey = `${baseType}${match[2]}`; users[userKey] = process.env[key] as string; } }); return users; } function creds(tier: UserTier) { const availableUsers = getAvailableUsers(); const userKey = Object.keys(availableUsers).find(key =\u0026gt; key.startsWith(tier === \u0026#39;base\u0026#39; ? \u0026#39;base\u0026#39; : tier === \u0026#39;super\u0026#39; ? \u0026#39;super\u0026#39; : tier) ); if (!userKey || !availableUsers[userKey]) { throw new Error(`No ${tier} user found in environment variables`); } const email = availableUsers[userKey]; const pass = tier === \u0026#39;super\u0026#39; ? process.env.superpass : process.env.pass; if (!email || !pass) { throw new Error(`Missing credentials for ${tier} user`); } return { email, pass }; } export const test = base.extend\u0026lt;AuthFx\u0026gt;({ user: [\u0026#39;base\u0026#39;, { option: true }], auth: async ({ page, user }, use) =\u0026gt; { const loginPO = new Login(page); const logoutPO = new Logout(page); const doLogin = async (tier?: UserTier) =\u0026gt; { // login flow: navigate, enter credentials, handle MFA, wait for login success // ...actual login logic goes here }; await use({ login: () =\u0026gt; doLogin(), loginAs: (tier) =\u0026gt; doLogin(tier), logout: async () =\u0026gt; { await logoutPO.performLogout(); }, }); }, }); export const expect = test.expect; This class handles user discovery, assignment, login, logout, and role switching, and is designed to be extended and customized for your own Playwright E2E needs.\nHere\u0026rsquo;s a sample test showing how to use this fixture in practice. Note that we\u0026rsquo;ve further obfuscated the environment variable names for demonstration:\nExample .env (obfuscated):\nAPP_BASE_URL=\u0026#39;https://your-app-url.com\u0026#39; USER_A=\u0026#39;user1@example.com\u0026#39; USER_B=\u0026#39;user2@example.com\u0026#39; USER_C=\u0026#39;user3@example.com\u0026#39; ADMIN_USER=\u0026#39;admin@example.com\u0026#39; USER_PASS=\u0026#39;YourPassword123!\u0026#39; ADMIN_PASS=\u0026#39;SuperSecret!\u0026#39; Sample Playwright test:\nimport { test } from \u0026#39;../fixture/auth\u0026#39;; test(\u0026#39;Admin can access dashboard\u0026#39;, async ({ auth }) =\u0026gt; { await auth.loginAs(\u0026#39;admin\u0026#39;); // ...test admin dashboard logic }); test(\u0026#39;Regular user can view profile\u0026#39;, async ({ auth }) =\u0026gt; { await auth.login(); // Uses the worker\u0026#39;s assigned user // ...test profile logic }); This approach keeps your tests clean and role-aware, while the fixture handles all the session and user management under the hood.\nAPI Authentication: The Service Account Pattern Another challenge we faced was authenticating our APIs in a way that worked with Auth0. For this, we had to create a dedicated \u0026ldquo;machine-to-machine\u0026rdquo; (M2M) or service account application in Auth0. This app is not the same as our main user-facing app it exists solely to issue tokens for backend and automated API access.\nThe process works like this: our test code (or backend service) sends a POST request to the Auth0 authentication server not the main app using the Auth0 client ID, client secret, and the correct audience for our API. Auth0 then returns a bearer token, which we can use to authenticate requests to our protected APIs.\nHere\u0026rsquo;s a simplified example of how this works in code:\nconst url = `${process.env.AUTH_SERVER_URL}/oauth/token`; const requestBody = { grant_type: \u0026#34;client_credentials\u0026#34;, client_id: process.env.API_CLIENT_ID, client_secret: process.env.API_CLIENT_SECRET, audience: process.env.API_AUDIENCE }; const response = await fetch(url, { method: \u0026#39;POST\u0026#39;, headers: { \u0026#39;Content-Type\u0026#39;: \u0026#39;application/json\u0026#39; }, body: JSON.stringify(requestBody) }); const data = await response.json(); const token = data.access_token; This token can then be sent as a Bearer token in the Authorization header of any API request. This approach is essential for automated testing and backend integrations, and it keeps your API authentication decoupled from your user-facing login flows.\nIf you need to test user-level flows (with MFA, etc.), you can use a similar approach as shown in the APILogin class, but for most backend and CI/CD scenarios, the service account pattern is the way to go.\nNote: We also ended up injecting MFA (multi-factor authentication) into our flows for certain user-level tests, but that\u0026rsquo;s a topic for another blog post on advanced Auth0 automation.\n","permalink":"https://fonzi.xyz/blog/playwright-auth0-parallel/","title":"Parallel Playwright Auth: Surviving Auth0's Session Pain"},{"content":" Why Canvas Testing Is Hard HTML5 canvas elements are everywhere games, maps, drawing apps, custom visualizations. But testing them has always been a pain. Unlike regular DOM elements, you can\u0026rsquo;t just select, click, or inspect canvas content with standard browser automation tools.\nThe Two Camps of Canvas Testing When it comes to automating canvas testing, there are generally two camps:\nDeserialization and Direct Calls: Some tools try to \u0026ldquo;read\u0026rdquo; the canvas by deserializing its pixel data or using direct API calls. This can work for simple cases, but quickly gets complicated for dynamic or interactive canvases, and often requires deep integration with the app\u0026rsquo;s code.\nML/AI Training: Others use machine learning or AI to visually recognize elements and simulate clicks or drags. This approach is powerful, but requires training data, setup, and can be overkill for simple interactions.\nI wanted something easier to plug in for basic canvas actions like clicking, dragging, or finding tooltips. So I thought: why not just overlay a dynamic grid at test runtime? That way, you can interact with any region of the canvas, without needing to reverse-engineer its internals or train a model.\nMotivation: MapGrab Broke, So I Built This I started working on canvas-grid after my MapGrab integration broke due to some layering confusion. Tooltips and overlays were appearing in the DOM only after canvas interactions, and existing tools couldn\u0026rsquo;t reliably automate or verify these behaviors. I needed a way to:\nClick and drag on specific canvas regions Detect tooltips or overlays that appear in the DOM after canvas events Sample colors and verify rendering Introducing CanvasGrid canvas-grid is a Playwright-first library for testing HTML5 canvas elements using a grid-based approach. It\u0026rsquo;s experimental, but it makes previously impossible tests easy-ish:\nOverlay a grid on any canvas Click, drag, and hover on grid cells Sample pixel colors Find tooltips or DOM elements triggered by canvas events Example Usage import { test, expect } from \u0026#39;@playwright/test\u0026#39;; import { CanvasGrid } from \u0026#39;canvas-grid\u0026#39;; test(\u0026#39;canvas testing example\u0026#39;, async ({ page }) =\u0026gt; { await page.goto(\u0026#39;https://your-canvas-app.com\u0026#39;); const grid = new CanvasGrid(page) .locator(\u0026#39;canvas\u0026#39;) .gridSize(10, 8); // 10 cols, 8 rows await grid.attach(); await grid.clickCell(5, 4); await grid.hoverCell(3, 2); const color = await grid.sampleCell(5, 4); // Now check for tooltips or overlays const tooltip = await page.locator(\u0026#39;.tooltip\u0026#39;).textContent(); expect(tooltip).toContain(\u0026#39;Expected text\u0026#39;); }); CanvasGrid in Action Below there is a GIF showing CanvasGrid running against a test app:\nDragging a Canvas Ball Your browser does not support the video tag. Real-World Benefits With canvas-grid, you can finally automate:\nDrag-and-drop interactions Pixel-perfect UI checks DOM overlays triggered by canvas events Regression tests for games, maps, and more Try It Out The project is still experimental, but you can find it in my repo. If you have feedback or want to contribute, reach out!\nWhere to Find CanvasGrid CanvasGrid lives here for now:\nGitHub: Bison-Software/CanvasGrid npm: @bisonsoftware/canvas-grid-playwright This project is under my new company, Bison Software LLC.\nLearn more at bison.software\n","permalink":"https://fonzi.xyz/blog/testing-canvas-with-canvasgrid/","title":"Testing HTML5 Canvas with CanvasGrid"},{"content":"After years of performing lead/architect-level QA work without concern for titles, but rather for the sake of learning, I started Bison Software. The surprise wasn\u0026rsquo;t the technical work; it was the taxes. There were forms to fill out with a due date of 30 days before penalties and fees ensued. The true bugs were in the paperwork.\nAll good software has some bs. I guess all good systems have some bs as well\u0026hellip;\n","permalink":"https://fonzi.xyz/relay/post6/","title":""},{"content":"There’s a myth you need heavy infrastructure to run real projects online. Kubernetes clusters, managed cloud services, and expensive bills often get presented as the “default” for hosting anything serious.\nThe truth is simpler: I run two websites, analytics, and even a full search engine on a single $5/month Vultr VPS. And it works just fine.\nThe VPS My entire setup lives on a $5/month Vultr instance with:\n1 vCPU 1 GB RAM 25 GB SSD That’s all I need. No autoscaling groups, no sprawling services, just one small virtual machine.\nDomains I split my domains between two registrars:\nEpik for fonzi.xyz Namecheap for bison.software Both point to the same VPS, where Nginx handles SSL with Let’s Encrypt and routes requests to the right service.\nWhat Runs Inside Here’s the breakdown of what actually lives on this box:\nStatic websites\nfonzi.xyz: generated with Hugo. bison.software: plain HTML, with a static contact form that posts to staticforms.xyz. Analytics\nGoatCounter, running in Docker. A lightweight, privacy-friendly alternative to Google Analytics. Search engine\nSearXNG, also in Docker. This isn’t just a search box — it’s a full metasearch engine that queries dozens of sources. Served at searx.fonzi.xyz. At idle, the whole system sits around ~500 MB RAM. That leaves breathing room even on this tiny instance.\nArchitecture Here’s how everything connects:\nMonitoring Without Bloat Monitoring is simple:\nhtop for live CPU/memory/disk checks. sysstat (sar) for historical CPU and memory logs. No dashboards, no bloated agents, no extra services consuming resources. Just the basics.\nWhy Minimal Works This approach works because it focuses on what matters:\nCost all of this runs for less than $6/month. Control Vultr doesn’t decide what’s acceptable content; they only enforce legality. Simplicity static sites and Dockerized apps mean fewer moving parts. Rebuildability I can redeploy from scratch in under an hour if needed. Minimal doesn’t mean fragile. It means focused, efficient, and easy to maintain.\nClosing You don’t need a complex cluster or a big monthly cloud bill to put real projects online. With a small VPS, some static sites, and a couple of containers, you can host everything you need and keep full control of it.\nThis setup runs two domains, analytics, and a search engine — all on a $5 Vultr server. Nothing more required.\n","permalink":"https://fonzi.xyz/blog/stack/","title":"Running Two Sites, Analytics, and a Search Engine on a $5 VPS"},{"content":" Testing Interactive Maps with Playwright and MapGrab Maps are some of the trickiest UI components to test. They’re dynamic, data-driven, and highly interactive. Unlike static DOM elements, a map tile or layer isn’t just a you can click(). You need to assert visibility on a canvas, zoom to a region, and sometimes even intercept the map’s internal events.\nI recently built an automated test suite for map views using Playwright together with the MapGrab\n1. Merging Test Contexts The first hurdle: getting Playwright and MapGrab expectations (expect) and fixtures (test) to coexist.\nI solved this with a support file:\n// MapSupport.ts import { test as playwrightTest, mergeTests, expect as playwrightExpect, mergeExpects, } from \u0026#34;@playwright/test\u0026#34;; import { test as mapGrabTest, expect as mapGrabExpect } from \u0026#34;@mapgrab/playwright\u0026#34;; export const test = mergeTests(playwrightTest, mapGrabTest); export const expect = mergeExpects(playwrightExpect, mapGrabExpect); This gave me a unified test and expect that support both DOM checks and map-specific checks like toBeVisibleOnMap().\n2. Bootstrapping the Map Each test begins by logging in (via a Page Object) and asserting that the base “earth” layer is visible:\nconst mapHelper = new MapHelper(page); await mapHelper.assertEarthVisible(); This ensures the map actually rendered before deeper validation.\n3. Custom Map Helper Class To keep tests clean, I wrapped common interactions in a MapHelper class:\npublic async fitTileToMap(code: string, browserName: string) { const tile = this.getTileLocator(code); await expect(tile).toBeVisibleOnMap(); await tile.fitMap({ padding: this.getPadding(browserName) }); } This method zooms/pans the map so the requested tile is centered. Padding logic accounts for browser rendering differences.\nClicking and validating tiles required a bit more work:\npublic async clickAndVerifyInfoPanel(code: string, label: string) { const tile = this.getTileLocatorByLayer(code); const box = await tile.boundingBox(); const clickX = box.x + box.width / 2; const clickY = box.y + box.height / 2; await this.page.mouse.click(clickX, clickY); const infoPanel = this.page.locator(\u0026#39;.info-box\u0026#39;); await expect(infoPanel).toBeVisible(); await expect(infoPanel.locator(\u0026#39;.layer-name\u0026#39;)).toContainText(label); } This ensures not just that the tile exists, but that clicking it triggers the correct info panel and button set.\n4. Handling Multiple Layers The app supports multiple tile layers (e.g., layer vs. sublayer). I kept my helper flexible by passing a layer type:\nthis.getTileLocatorByLayer(code, \u0026#39;sublayer\u0026#39;) 5. Injecting MapGrab into the App Injecting MapGrab into the App The scariest part was wiring MapGrab into the app’s map instance. The library expects a map object to hook into, but our app doesn’t export it by default.\nThe fix: install a stub and inject MapGrab on map load.\n// map-interface/index.ts export function installMapGrab(..._args: unknown[]): void { // no-op stub for tests } And in the initializer:\nmap.on(\u0026#39;load\u0026#39;, () =\u0026gt; { installMapGrab(map, \u0026#39;mainMap\u0026#39;); this.mapReadySubject.next(map); }); Now the tests can “see” the map internals without modifying production code.\n6. Example Test Here’s a simplified end-to-end test:\ntest(\u0026#39;Verify map view is loaded\u0026#39;, async ({ page, browserName }) =\u0026gt; { // log in const mapHelper = new MapHelper(page); await mapHelper.assertEarthVisible(); // verify main tile await mapHelper.fitTileToMap(\u0026#34;CODE123\u0026#34;, browserName); await mapHelper.clickAndVerifyInfoPanel(\u0026#34;CODE123\u0026#34;, \u0026#34;Layer: Example\u0026#34;); // verify sub-tile await mapHelper.fitTileToMap(\u0026#34;CODE456\u0026#34;, browserName); await mapHelper.clickAndVerifyInfoPanel(\u0026#34;CODE456\u0026#34;, \u0026#34;Sublayer: Example\u0026#34;, \u0026#34;sublayer\u0026#34;); }); 7. Lessons Learned Maps require spatial awareness. Clicking at x, y is often more reliable than locator.click(). Cross-browser padding is essential. Different engines render map extents slightly differently. Helper classes keep tests readable. Without MapHelper, the tests would be noisy and fragile. Injection was the secret sauce. Without installing MapGrab on map load, expectations like toBeVisibleOnMap() wouldn’t work. Browser limitation: currently this approach only works in Chromium (headless). Firefox and WebKit do not render the map in headless mode, so they can’t be validated with this setup.\nConclusion Testing maps isn’t as straightforward as testing forms or buttons. But with Playwright + MapGrab, plus some thoughtful helper code, you can validate tiles, layers, tooltips, and navigation in a way that’s both stable and maintainable.\nThis setup now runs in CI alongside other UI tests, giving confidence that when we say “the map is ready,” it actually is.\n","permalink":"https://fonzi.xyz/blog/maps/","title":"E2E Tests For Maps"},{"content":"Map Testing? How do you do it? Got a blog coming soon.\n","permalink":"https://fonzi.xyz/relay/post5/","title":""},{"content":"Today felt like I was QA, PM, PO, and janitor—cleaning up a mess I didn’t make, with 7 hours to launch. And getting a non stable testing environment.\n","permalink":"https://fonzi.xyz/relay/post4/","title":""},{"content":"I almost added a like button. Then I remembered my email is at the bottom.\n","permalink":"https://fonzi.xyz/relay/post3/","title":""},{"content":"Debugged the upload, verified S3, wrote the curl — then got asked for my request body.\n","permalink":"https://fonzi.xyz/relay/post1/","title":""},{"content":"I needed a place for stray thoughts, technical friction, and half-built ideas. But not a social media.💀\n","permalink":"https://fonzi.xyz/relay/post2/","title":""},{"content":"Load Testing.\nA somewhat challenging subject for most QAs I’ve worked with. Usually, it’s ignored or done incorrectly due to a misunderstanding of what it actually means.\nFirst, let’s clarify the difference between Load Testing and Performance Testing — they are not the same thing.\nLoad Testing – Literally overload your system to simulate peak and worst-case user influx scenarios. You could say that load testing is a subset of performance testing.\nPerformance Testing – Ensures your platform performs well under certain pre-determined loads. This is a much broader category.\nI like to think of performance as an abstract idea: What is performant for X given Y? And those variables can only be defined by your organization.\nWe recently had an idea: what if we actually started load testing our startup app?\nThanks to K6, we discovered some cool things.\nWe found that we could handle about 3500 VUs over a 30-second timespan, with 50 actual users hitting a specific endpoint.\nWe leveraged K6 (which was super easy to set up) and used an existing Grafana dashboard to monitor P99 latency, request failures, request success rates, etc.\nThis small exercise gave us surprising insights:\nWe\u0026rsquo;re likely over-provisioned. Since we don’t actually hit 3500 users at peak, we might be able to scale down and save some money (awww yeah 💸). We uncovered that we might not be using the most optimal Garbage Collection tool in Java. The fact that all this was exposed by a simple Node app (~300 LOC) is wild. The value we got in return was way more than expected.\nWhile I get that load testing can feel daunting, it\u0026rsquo;s 100% worth doing from time to time. We\u0026rsquo;re now better positioned for the future because we understand our limits and tip-over points.\nThis was a small project that I pushed for at our company, and it taught me a few key lessons:\nNever underestimate what a simple test can expose. Setting up Grafana and K6 with a remote write endpoint was easier than expected. Here’s what we added to our prometheus.yml to make it work:\nremote_write: - url: \u0026#34;http://localhost:9090/api/v1/write\u0026#34; queue_config: capacity: 5000 max_shards: 10 min_shards: 1 max_samples_per_send: 1000 write_relabel_configs: - source_labels: [__name__] regex: \u0026#34;.*\u0026#34; action: keep And we ran k6 scripts with:\nK6_PROMETHEUS_RW_SERVER_URL=http://localhost:9090/api/v1/write \\ K6_PROMETHEUS_RW_USERNAME=USERNAME \\ K6_PROMETHEUS_RW_PASSWORD=PASSWORD \\ k6 run -o experimental-prometheus-rw script.js 2025-03-27T21:08:22-43-04:00\n","permalink":"https://fonzi.xyz/blog/k6/","title":"K6"},{"content":"Sometimes, there\u0026rsquo;s a need for QA to monitor data. This has been an interesting challenge in recent years, where entire ETL pipeline monitoring tools have emerged. We recently had an incident at work where some of our users were dropping properties (most likely due to human error). We still wanted to catch and alert on significant deviations.\nThe Problem: No way to monitor significant deviations.\nInitially, I figured it\u0026rsquo;d be cool to read directly from our data source. In this case, MongoDB. We had a simple limitation: not being in the enterprise Grafana tier nor MongoDB Enterprise, which meant we did not have a direct connection to MongoDB as a data source.\nThe first obstacle was figuring out how to read directly from the database in hopes of identifying some cool historical trends. No biggie. I was sure someone had already solved this issue, and I was mostly right. Someone had created a plugin that was easy to install: MongoDB Datasource Plugin. Coincidentally, there was a bug fix our team needed, and the author of the plugin was already working on it. You can see me testing this here: Issue #15. Pretty sweet to be able to collaborate with Open Source for a day job, all because of a quick need.\nAt first, this solution seemed like all we needed. However, I quickly realized we were missing something critical: historical data. To detect deviations, we needed a historical record of the user\u0026rsquo;s data before any changes occurred. Since this was not implemented in MongoDB, I had to find another way.\nYou can see that I had a cool Login Failure Rate. Since that does have historical data in its collection. However, I still needed properties.\nThe middleware I created was a quick tool that scraped the MongoDB collection, pushed the data to Pushgateway and Prometheus, and then allowed Prometheus/InfluxDB to retain the historical data. We run this tool every two hours, which gives us solid historical insights.\nThis is pretty cool, actually. We already had a case where we needed some data to be stored, and the way it works is as follows:\nScript Runs in Bibtucket ----\u0026gt; Bitucket Restuls get pushed to PushGateway ----\u0026gt; PushGateway is scraped by Prometheus ----\u0026gt; Prometheus stores in InfluxDB\nThis is the general pipeline of data flow. From MongoDB with no historical data to keeping historical data on a pinch. The ideal solution would be to update the MongoDB collection to keep the data as well.\nOnce we had this setup, we could calculate deviations by percentage. Now, we get Slack alerts if a user experiences a significant drop in properties. This allows us to monitor all our users simultaneously without fear of missing critical changes.\nWe use this type of monitor now, with an environment variable for each of our users, to avoid being overwhelmed with lines and to narrow down to the problem user.\nSome of the math involved behind the scenes includes:\nsum by (email) (user_hotel_info{environment=\u0026quot;prod\u0026quot;} offset 15m) (historical data)\nsum by (email) (user_hotel_info{environment=\u0026quot;prod\u0026quot;}) (current data now)\nThen, in the match function and a reduce function, we use the following: (($A - $B) / ($A + 1e-10)) * ($A \u0026gt; $B) This checks for sudden drops in properties.\nFinally, we set this as an alert: abs(($A - $B) / ($A + 1e-10)) \u0026gt; 0.1 Here, 0.1 represents 10%, but it can be adjusted as needed.\nEven QA has a use for Grafana, and more QA engineers should explore the DevOps world to solve internal issues like this one, beyond just UI/API automation. I\u0026rsquo;ve noticed a trend where QA engineers thrive as solution engineers, with QA being their primary role.\n2024-12-30T10:22:41-06:00\n","permalink":"https://fonzi.xyz/blog/grafana/","title":"Grafana"},{"content":"Starlink. I\u0026rsquo;ve been keeping my eye on it since I first heard about it. Finally, in 2024, I had the chance to buy a unit and install it. In the middle of nowhere, for that matter.\nI own some land in Mexico 🇲🇽, so I\u0026rsquo;ve been building a small office as a stepping stone to the full house. Since I need to visit every once in a while to make sure everything is progressing.\nTop speed was 132 Mbps, averaging around 50-60 Mbps on clear days. Even through a heavy storm, the internet kept running fine. Needless to say, I\u0026rsquo;ve been super impressed.\nThis is just a simple setup that is not fully permanent, and it’ll be a bit longer before I install it permanently elsewhere. In the meantime, I tied it down with some wire so it doesn’t get tilted during heavy winds. Since it’s a bit hard to source items in this location, you need to think outside the box.\nI traveled from Mexico City to a smaller city about 1.5 hours south, then continued another 2.5 hours south to finally install it.\nDescansa en paz, Padre. Te veo pronto.\nSeguiré tu visión de acabar la propiedad. Primero mi abuelo, después tú, ahora yo.\nRaúl Vázquez Sánchez\nJunio 26 de 1956 - Junio 4 de 2023\n","permalink":"https://fonzi.xyz/blog/starlink/","title":"Starlink... In the Middle of Nowhere"},{"content":" Parallel Testing in Playwright Software testing is a critical aspect of the development process, ensuring that applications function as expected and meet the required quality standards. However, as projects grow in complexity, the test suite can become time-consuming to execute, leading to longer feedback loops and delayed releases. To overcome this challenge, developers turn to parallel testing, a technique that distributes test execution across multiple machines or processes simultaneously. In this blog, we explore how Playwright, a powerful end-to-end testing framework, enables developers to implement and monitor parallel testing for faster, more efficient testing workflows.\n// test.spec.ts import { test, expect } from \u0026#39;@playwright/test\u0026#39;; test(\u0026#39;Login Test\u0026#39;, async () =\u0026gt; { // Your login test implementation here // ... }); test(\u0026#39;Signup Test\u0026#39;, async () =\u0026gt; { // Your signup test implementation here // ... }); test(\u0026#39;Search Test\u0026#39;, async () =\u0026gt; { // Your search test implementation here // ... }); test(\u0026#39;Checkout Test\u0026#39;, async () =\u0026gt; { // Your checkout test implementation here // ... }); Implementing Parallel Testing in Playwright: Parallel testing in Playwright is straightforward and can be achieved with just a few lines of code. By organizing tests using Playwright\u0026rsquo;s built-in test runner, developers can execute tests concurrently, saving precious time during the test cycle. For instance, let\u0026rsquo;s consider a test suite with login, signup, search, and checkout tests.\n// playwright.config.json { \u0026#34;workers\u0026#34;: 4 } Distributed Parallelism using Playwright Test Runner: For large-scale projects, Playwright offers distributed parallelism by leveraging cloud-based infrastructure to run tests across multiple machines. This method is highly efficient and further shortens test execution time.\n# Run tests in distributed parallel mode npx playwright test --project=my_project --workers=4 Monitoring and Reporting: Monitoring the test execution is essential to track progress and identify any issues. Playwright allows developers to configure multiple reporters to generate various types of test reports, such as dot format, JSON, and JUnit XML, or the best Allure Reporting.\n// playwright.config.ts import { PlaywrightTestConfig } from \u0026#39;@playwright/test\u0026#39;; const config: PlaywrightTestConfig = { reporter: [ [\u0026#39;dot\u0026#39;], [\u0026#39;allure-playwright\u0026#39;]. [\u0026#39;json\u0026#39;, { outputFile: \u0026#39;test-results.json\u0026#39; }], [\u0026#39;junit\u0026#39;, { outputFile: \u0026#39;test-results.xml\u0026#39; }], ], }; export default config; Overall Parallel testing with Playwright is a game-changer for teams seeking faster and more efficient test cycles. By implementing method-level parallelism and distributed parallelism, developers can significantly reduce test execution times and receive quicker feedback on the application\u0026rsquo;s quality. With monitoring and reporting capabilities, teams gain valuable insights into test progress and results. As development projects continue to grow in scale and complexity, adopting parallel testing in Playwright becomes a strategic decision for ensuring top-notch software quality in a time-efficient manner.\nSharding: Sharding involves dividing the test suite into smaller subsets or \u0026ldquo;shards\u0026rdquo; and running each shard on a separate machine or process. This allows multiple machines to execute different parts of the test suite concurrently, significantly reducing the overall test execution time. Sharding is particularly useful for large test suites or distributed environments.\nWorkers: Workers, on the other hand, are individual processes running on the same machine that execute test files in parallel. Each worker can run multiple tests within a single file, making use of multi-core CPUs to speed up the test execution. Workers share the same environment and resources, but they are isolated from each other, ensuring a clean environment for each test execution.\nIn summary, sharding focuses on distributing the test suite across multiple machines, while workers focus on parallelizing test execution within a single machine. Both approaches are valuable techniques for achieving faster and more efficient parallel testing, but they target different aspects of test execution optimization. Choosing between sharding and workers depends on factors such as test suite size, available resources, and the desired level of parallelization.\n+-----------------+ | | | Test Suite | | | +-------+---------+ | v +--------------+ +-----------------+ +-----------------+ | | | | | | | Shard 1 | | Shard 2 | ... | Shard N | | | | | | | +------+-------+ +-----------------+ +-----------------+ | | | v v v +------------+ +------------+ +------------+ | | | | | | | Worker 1 | | Worker 2 | ...... | Worker M | | | | | | | +------------+ +------------+ +------------+ ","permalink":"https://fonzi.xyz/blog/test-parallelization/","title":"Unlocking Efficiency with Parallel Testing in Playwright"},{"content":" The Relationship that needs to happen The relationship between QA and upper management in the software industry is often overlooked, yet it holds significant importance. While QA is typically placed under the umbrella of the engineering department, there is a strong case for QA to have its own VP who can provide dedicated leadership and representation. This separation allows for a more balanced decision-making process that considers both the engineering and QA perspectives.\nOne common challenge QA professionals face is the misconception that they are less technical compared to developers. However, it is important to challenge this stereotype and showcase the technical expertise within the QA team. By actively demonstrating their skills and knowledge, QA professionals can gain credibility and influence within the organization.\nPushing back on developer decisions can be a delicate process. As QA, we are responsible for finding flaws and ensuring quality, but that doesn\u0026rsquo;t mean we should impose our decisions on the development team. Instead, it is crucial to approach these situations with well-informed solutions and opinions. By presenting our insights in a respectful and collaborative manner, we can foster a culture of open dialogue and mutual understanding.\nHow to push forward To advance in the QA field and establish connections with upper management, it is essential to have a deep understanding of the business and industry landscape. QA professionals should stay updated on industry trends, emerging technologies, and customer expectations. By demonstrating a strong grasp of the business\u0026rsquo;s goals and aligning QA efforts with those objectives, QA professionals can position themselves as valuable assets to the organization.\nCrafting a personal brand is another key aspect of building relationships with upper management. Developing a reputation as a skilled and influential QA professional requires consistent effort. Actively participate in industry events, contribute to relevant forums and communities, and share insights through blog posts or speaking engagements. By showcasing your expertise and actively engaging with the larger QA community, you can enhance your professional profile and gain visibility among senior management.\nIn summary, the relationship between QA and upper management is crucial for effective decision-making and achieving quality goals. By challenging misconceptions, pushing back when necessary, staying informed about the industry, and building a strong personal brand, QA professionals can enhance their influence and contribute to the success of their organizations.\n","permalink":"https://fonzi.xyz/blog/ctos-and-qa/","title":"CTOs and QA"},{"content":" Why does modern QA Suck? For nearly a decade, I have been working in Quality Assurance (QA), and I have observed an endemic issue in the QA community: a lack of technical expertise. While there are undoubtedly skilled QA professionals out there, many QA teams struggle with basic technical concepts and practices. In this blog post, we\u0026rsquo;ll explore the common technical skill gaps in QA, why these gaps exist, and how we can start addressing them to elevate the QA industry as a whole.\nTechnical skill gaps in QA:\nGit Knowledge Object-Oriented Programming (OOP) Basics Google-Fu / GPT-Fu skills Basic Database functionality (Relational and Non-Relational) Basic Network Understanding General Security Report Analytics CI/CD Why do these gaps exist? The lack of technical expertise in QA can be attributed to several factors. One possible reason is the lower pay and expectations in the QA industry compared to development roles. There is also a noticeable absence of a robust QA community, with limited local meetups and events compared to those for developers. This lack of community may contribute to the diminished motivation and drive for QA professionals to continuously improve their skills.\nHow can we address these gaps? Raise industry standards: By increasing the pay for QA roles and setting higher expectations for technical skills, companies can attract more skilled professionals and motivate existing QA teams to upskill.\nFoster a strong QA community: Encouraging local QA meetups, conferences, and events can help establish a supportive environment where QA professionals can network, share knowledge, and grow together.\nComprehensive training: Encourage training that covers the entire SDLC and necessary technical skills, rather than just focusing on specific tools like Selenium.\nPromote a culture of continuous learning: Encourage QA professionals to stay up-to-date with the latest tools, frameworks, and technologies, and provide them with resources to do so.\nBridging the technical skill gap in QA is crucial for the industry to evolve and keep up with the rapid advancements in technology. By raising expectations, fostering a strong community, and promoting continuous learning, we can elevate QA professionals\u0026rsquo; expertise and, in turn, ensure that the products they help deliver are of the highest quality.\n","permalink":"https://fonzi.xyz/blog/how-to-scale-a-qa-team/","title":"Why Modern QA Needs an Upgrade: Addressing Technical Skill Gaps"},{"content":" I was in a podcast. Somehow. First, I want to thank Ruslan Akhmetzianov from QAMeta for inviting me over. If you have not heard of QAMeta, you\u0026rsquo;ve most likely heard of Allure, as I talk about it quite a bit.\nFeel free to listen to the podcast and share your opinions with me. Did I make a fool out of myself? Did I say enough? Not enough?\nWell, either way, this is one big step in a good direction for the testing industry and QA, as well as for myself. We are witnessing the birth of next-gen testing. The days of just manual testing are nearly done. The days of just knowing enough Selenium or Playwright are nearly done. As software gets larger and more complex, so does the need for QA testing. The testing needs to scale, go faster, and be more stable.\nFor all the companies I\u0026rsquo;ve worked for, it\u0026rsquo;s always been a rare sight to see reporting fully done and fully working, or even a functional process. Automation frameworks usually are an afterthought. There are rarely companies that are willing to implement frameworks from scratch that can scale. However, Allure TestOps has been a big step in the right direction where every person involved, from CTO to QA to PM, can all agree it\u0026rsquo;s a good tool to have.\nThis new paradigm brings a question, a large question:\nAs a QA engineer, can you fully architect an automation framework?\nFor me, it was not until recently that I could answer this as a yes.\nA few months ago, I still had no idea how to do correct load testing and the actual difference between performance vs. load vs. stress.\nIf you answered \u0026rsquo;no\u0026rsquo; to that question. I highly suggest you learn everything you can. As in the podcast, we also spoke about AI tools and how those will eventually make their way into testing (some already have). So you can easily see that manual testing will perhaps no longer be 100% manual. Even if you don\u0026rsquo;t code, you will be required to know some basic universal industry-wide skills, such as Bash, Shell, and Git, just to start testing around modern software.\nWith new tools such as post-SQL DBs, where you can make table changes on the fly, a lot of these stable QA/UAT environments that manual testers depend on to validate could very likely become fully ephemeral. This will require everyone on the team to understand basics like branching or running a script. And TestOps, or something similar, will be the reporting tool for such new testing teams.\nhttps://qameta.io/blog/dreams-and-tech-behind-automation/\n","permalink":"https://fonzi.xyz/blog/testops-podcast/","title":"TestOps Podcast"},{"content":"It\u0026rsquo;s been about 3 months that I switched from Github over to Gitlab. At my previous job. I had to use github actions for pipeline. Now I use Gitlab. I can honestly say that Github is 100 times better and more intuative on how it works. As well as the market place is a great resource. I\u0026rsquo;m not sure if Gitlab has something like that built into their roadmap. However, I keep writing code that I know other people have solved, because I find it in gitlab threads. So why would Gitlab continue to propagate the re-invention of the wheel? Ideally CICD makes you more productive. But if you have to keep writing custom code that other people have solved. Even if it just takes 30 minutes to look up, copy, paste and run, it would still be faster to have a market place with small pieces of code that solve a very specific issue.\nAnother one of my gripes with Gitlab is the fact that you cannot have multiple actions. But rather you must either use templates and pull into a single file, which I understand the concept, but ideally I should be able to seperate files per functionality completly different behavior from one another.\nHere\u0026rsquo;s the example of the issue above.\nI want to run X amount of pipeliens at night I want to run X amount of pipelines that are differnt manually. I must place both of those rules in the same file, instead of having two well defined files that reduce the scope of each pipeline.\nOne project can have multiple pipelines especially in QA depending on the bussiness need. QA Could want to run Smoke or Regression without having to share the file just to make it easier.\nGitlab also forces you to do things by pipeline. However, in a QA world, sometimes you have data generation scripts that you might want to run at any given time that do not fit on a pipeline and you want to outsource that run to less experienced peeps that might not know how to run scripts locally. Github Actions allows you to give them a link and tell them just click run. Vs Gitlab forces you to have a pipeline setup. Makes no sense. I understand the concept of jobs inside pipelines, but not everything is always a pipeline.\nSo if you are looking to go with Github or Gitlab. Choose Github. It\u0026rsquo;s the clear winner from a QA perspective.\n*2023-03-06T19:22:56-06:00\n","permalink":"https://fonzi.xyz/blog/pipelining-qa-in-gitlab/","title":"Pipelining Qa in Gitlab"},{"content":"Sprints. Everyone uses them it seems like. However, there is a reason why there are new ways of developing software. Sprints are waterfalls in essence. Methodologies like Kanban really outshine sprints. In modern software development where you can create infrastructure in IaC and Deploy with tools like AWS / GitHub / Pipeline. These modern tools allow you to deploy faster, which is what every company claims they want to do, but never actually break out of the mold. Now some teams do need sprints, just like some teams do need water fall. But most \u0026ldquo;modern\u0026rdquo; teams will greatly benefit from Kanban. There is no reason why there should be these massive amounts of code getting released every 2-3 weeks where you can exercise every part of the release multiple times a day.\nYou can see how most of these \u0026ldquo;modern\u0026rdquo; companies try to be kanban by adding feature flags to undone features, breaking one of the main tenants of sprints. \u0026ldquo;The focus is on delivering a complete and usable product\u0026rdquo;. Why even call yourself sprint and break one of the major tenants. Also take a look at the \u0026ldquo;planning\u0026rdquo; and how bad people are at estimating time. So why keep failing for years instead of just switching. The nice thing about Kanban is that you can still deploy every 2-3 weeks if it helps you feel better, but at least following the basic Kanban flow will help QA and DevOps.\nI\u0026rsquo;ll take it even further saying that with a true CI/CD and Kanban you don\u0026rsquo;t even need a separate pipeline for hot fixes. You\u0026rsquo;d just release the fix as another normal release, one of many during the day. Also look at the sprint meetings. Sprint planning (which every company I\u0026rsquo;ve seen fails at really planning correctly and delivering), sprint reviews which is an artifact of not planning well. Retrospective, which is way too out in the future to recall anything good done. Usually only the bad shows up. Or vise versa in a nice team.\nAt the end of the day Kanban \u0026gt; Sprint. Sprints are the boomers of tech. If you still use sprints and you have the power to change it. Go apologize to your team.\n2023-02-07T09:10:03-06:00\n","permalink":"https://fonzi.xyz/blog/sprits-are-bad/","title":"Sprints Are Bad For Every Department in Modern Software"},{"content":" ChatGPT. Speeding up every part of the SDLC If you read this blog, then you have heard of ChatGPT. AI for the masses. You know, a lot of people are saying it\u0026rsquo;s the end of software development as we know it, but are they right? I think it\u0026rsquo;s just another tool to help speed up development. I don\u0026rsquo;t think we are at the location where jobs can be fully replaced. Yet\u0026hellip; So how has it increased the SDLC speed. To start doing small simple POC projects has become really easy with this new tool. Not just that, but the context that ChatGPT has is amazing. You can literally use it as a more Junior or Senior Developer, depending on your own personal knowledge. If you know how to code, you will most likely use it to write up quick scripts that you know how to integrate. If you don\u0026rsquo;t know how to code, or you are just starting, it will be able to guide you through a full SaaS setup.\nThis is the magic behind it. You must know some coding and understand some basics for you to be able to tell it how to take some code and arramge it. Or give it well known context so that it can continue the basic items it gave you.\nI wanted to do a small experiement with ChatGPT and see how it could help me be more efficient. So I gave it the following piece of code and asked for it to lint it and comment it.\nimport { test, expect, APIRequestContext, request } from \u0026#39;@playwright/test\u0026#39;; export default class Organization{ readonly reqContext: APIRequestContext; readonly errorBlankName: any; readonly limit: Number; readonly offset: Number; readonly sort: String; readonly organizationId: String; statusResponse: number; callResponse: any; constructor (request: APIRequestContext, limit: Number, offset: Number, sort: String, organizationId: String) { this.reqContext = request; this.limit = limit; this.offset = offset; this.sort = sort; this.organizationId = organizationId; } public async getMessage(token: any) { await test.step(`I can make a GET call to organization`,async () =\u0026gt; { console.log(\u0026#34;Request sending: \u0026#34; + `${process.env.baseAPIURL}/v2/organization/${this.organizationId}/departments?limit=${this.limit}\u0026amp;offset=${this.offset}\u0026amp;sort=${this.sort}`) console.log(\u0026#34;Token: \u0026#34; + token); const response = await this.reqContext.get(`${process.env.baseAPIURL}/v2/organization/${this.organizationId}/departments?limit=${this.limit}\u0026amp;offset=${this.offset}\u0026amp;sort=${this.sort}`, { \u0026#39;headers\u0026#39;:{ \u0026#39;Authorization\u0026#39;: `Bearer ${token}` } }) this.statusResponse = response.status(); this.callResponse = await response.json(); }); } public async StatusResponseCodeIs(status: any) { await test.step(`The organization status is ${status}`, async() =\u0026gt;{ expect(this.statusResponse, \u0026#39;Expected Status\u0026#39;).toBe(status); }); } public async OrganizationBodyIsValid() { await test.step(`The Organization JSON Body is validated`, async() =\u0026gt;{ let jsonObj = this.callResponse as IOrganization; console.log(jsonObj); expect(typeof jsonObj.nextPage === \u0026#39;string\u0026#39; || typeof jsonObj.nextPage === null); expect(typeof jsonObj.offset === \u0026#39;number\u0026#39;); expect(typeof jsonObj.limit === \u0026#39;number\u0026#39;); expect(typeof jsonObj.totalCount === \u0026#39;number\u0026#39;); expect(typeof jsonObj.data[0].userCount === \u0026#39;string\u0026#39;); expect(typeof jsonObj.data[0].clientCount === \u0026#39;string\u0026#39;); expect(typeof jsonObj.data[0].id === \u0026#39;string\u0026#39;); expect(typeof jsonObj.data[0].name === \u0026#39;string\u0026#39;); }); } public async OrganizationBodyIsUndefined() { await test.step(`The Organization JSON Body is undefined`, async() =\u0026gt;{ expect(this.callResponse.data).toBe(undefined); }) } } export interface IOrgInnerData { id: string; name: string; userCount: string; clientCount: string; } export interface IOrganization { totalCount: number; offset: number; limit: number; data: IOrgInnerData[]; nextPage: string; } Sure enough it printed comments with context on the code I wrote. In the future this might be able to get placed in a pipeline where the dev pushes and ChatGPT can now update comments and lint and maybe even optimize?\nHere is the code it gave me back.\nimport { test, expect, APIRequestContext, request } from \u0026#39;@playwright/test\u0026#39;; // Organization class representing the organization\u0026#39;s API calls export default class Organization { // Request context, which holds the request function readonly reqContext: APIRequestContext; // Error message for blank name readonly errorBlankName: any; // Query parameters readonly limit: number; readonly offset: number; readonly sort: string; readonly organizationId: string; // Response properties statusResponse: number; callResponse: any; // Constructor constructor(request: APIRequestContext, limit: number, offset: number, sort: string, organizationId: string) { this.reqContext = request; this.limit = limit; this.offset = offset; this.sort = sort; this.organizationId = organizationId; } /** * Get message by making a GET call to the organization endpoint * @param token - The token for the request */ public async getMessage(token: any) { await test.step(`I can make a GET call to organization`, async () =\u0026gt; { console.log(\u0026#34;Request sending: \u0026#34; + `${process.env.baseAPIURL}/v2/organization/${this.organizationId}/departments?limit=${this.limit}\u0026amp;offset=${this.offset}\u0026amp;sort=${this.sort}`); console.log(\u0026#34;Token: \u0026#34; + token); const response = await this.reqContext.get(`${process.env.baseAPIURL}/v2/organization/${this.organizationId}/departments?limit=${this.limit}\u0026amp;offset=${this.offset}\u0026amp;sort=${this.sort}`, { headers: { \u0026#39;Authorization\u0026#39;: `Bearer ${token}` } }); this.statusResponse = response.status(); this.callResponse = await response.json(); }); } /** * Asserts that the response status code is the expected one * @param status - The expected status code */ public async StatusResponseCodeIs(status: any) { await test.step(`The organization status is ${status}`, async () =\u0026gt; { expect(this.statusResponse, \u0026#39;Expected Status\u0026#39;).toBe(status); }); } /** * Asserts that the organization\u0026#39;s body is valid */ public async OrganizationBodyIsValid() { await test.step(`The Organization JSON Body is validated`, async () =\u0026gt; { let jsonObj = this.callResponse as IOrganization; console.log(jsonObj); expect(typeof jsonObj.nextPage === \u0026#39;string\u0026#39; || typeof jsonObj.nextPage === null); expect(typeof jsonObj.offset === \u0026#39;number\u0026#39;); expect(typeof jsonObj.limit === \u0026#39;number\u0026#39;); expect(typeof jsonObj.totalCount === \u0026#39;number\u0026#39;); expect(typeof jsonObj.data[0].userCount === \u0026#39;string\u0026#39;); expect(typeof jsonObj.data[0].clientCount === \u0026#39;string\u0026#39;); expect(typeof jsonObj.data[0].id === \u0026#39;string\u0026#39;); expect(typeof jsonObj.data[0].name === \u0026#39;string\u0026#39;); }); } /** * Asserts that the organization\u0026#39;s body is undefined */ public async OrganizationBodyIsUndefined() { await test.step(`The Organization JSON Body is undefined`, async () =\u0026gt; { expect(this.callResponse.data).toBe(undefined); }) } } /** * Organization Interface for body response inner data */ export interface IOrgInnerData { id: string; name: string; userCount: string; clientCount: string; } /** * Organization Interface for body response */ export interface IOrganization { totalCount: number; offset: number; limit: number; data: IOrgInnerData[]; nextPage: string; } Pretty cool! Altough, I really wanted to see if it could optimize this. The server became overloaded with all the people using it. So I opted to leave it here. I did take that code and moved it over into my repo since it had comments. :)\nSo this got me thinking if something like this might be possible.\n+----------+ | | | ChatGPT | | | +----^-+---+ | | | | +---------+ +----+-v---+ +---------+ | +-----\u0026gt; | |Deployed | | DEV | | Git +--\u0026gt;|Optimized| | \u0026lt;-----+ | |Code | +---------+ +----------+ +---------+ Could you get a little service looking at Git and as code goes in ChatGPT would just optimize it and comment it if missing. This would require some decent CI in order to not break what\u0026rsquo;s on git.\n*2023-01-17T10:54:36-06:00\n","permalink":"https://fonzi.xyz/blog/chatgpt-and-qa/","title":"Chatgpt and QA"},{"content":" Why I switched to Hugo? If you\u0026rsquo;ve noticed at all. The page has changed drastically. I switched from hand cranked HTML and CSS into Hugo! Found that there is a decent blogging platform out there that is lightweight.\nWriting in markdown files, and just having it generate static HTML is great. No dealing with JS/CSS/HTML anymore. However, a framework does it. The nice thing about it is that there is no heavy JS on the server nor client side to render a neat little page.\nI ended up sorta pigging back off the theme known as monochrome. However, this taught me a little bit of SASS. It does have a tiny bit of JS. But, overall, everything should still be usable without turning on JS on your browser.\nTurns out that maintaining a blog/RSS with pure HTML was taking up too much of my time, without me actually having the time or energy to write more blogs. I would write one blog, and I\u0026rsquo;d be done since following up would be getting the HTML tags working again and if I wanted to add something else, then I\u0026rsquo;d have to modify the CSS to match everything.\nOne thing I do wish that this theme supported is images that support wrapping text. There is a showcase method, however, that will be reserved for when I start photography.\n","permalink":"https://fonzi.xyz/blog/hugo-ftw/","title":"Why I switched to Hugo?"},{"content":" TestOps? What is that? A new word is buzzing around. Let me guide you a bit back with buzzwords. The current hot field is DevOps everyone wants to be in DevOps every company needs DevOps. Before that, it used to be two roles. Developer and Operations. Then someone figured out that merging them would be more efficient and a new role was born. Same with TestOps is happening now. Now I think the general tech industry has still not really realized this as a whole. However, more than likely it will be a very big buzz work here soon. At least that\u0026rsquo;s my hope :). Now that Selenium is getting dethroned and frameworks like cypress and playwright are more mature, or even \u0026ldquo;AI\u0026rdquo; supported testing tools like Mabl. There is a new need for a role that can truly support a massive amount of tests. This is where the ops part come in. Things like EvoMaster that are auto-generating API tests, still need someone to maintain that infrastructure. DevOps, could fill and will fill a lot of these roles. Here is TestOps will become a trend. DevOps will realize that they need someone who is versed in dev practices and test practices. What kind of tests to implement, and at which part of the pipeline they should run at. Usually testers (manual and automation) do not really get involved in the pipe lining in the full software cycle. However, most will be forced to learn or get pushed out of the industry. Software has become faster and more fierce. So testers need to adapt. The idea of testing at the end of a cycle (I\u0026rsquo;m looking at you Sprints) is a old way of thinking. Today software teams needs to follow the three main tenants of DevOps.\nFaster flow (push testing to the left) Feedback (fast information must be provided to developers) CI (Things should be happening when integration takes place and the feedback loop needs to keep moving). This third tenant also has experimentation and learning. Now once you see the new cycle, you can start to see why the role of TestOps will start to appear. Companies will still be interested in having tests ran. And DevOps really still does not take into consideration testing very much. Nor are most DevOps folks in the mentality of finding edge cases. I\u0026rsquo;m not one to think that QA will be pushed out of the industry, it\u0026rsquo;ll still exist, just how it exist for manufacturing. However it will become more automated instead of manual, just like it did in manufacturing. Testers should start adopting the tenants of DevOps and a lot of things will become more clear, and they will become exponentially better at their jobs as well. Testers are a rich mine of knowledge when it comes to workflows, which means that they can share a lot of information with OPS on how clients may use the software which may show a much better infrastructure layout. However, the wind blows. The lines are getting blurred here. TestOps will end up been a part of DevOps and they will mainly focus on the CI side. As soon as tests get kicked off as soon as Pull Request or Merge Request come online. Tests should run. But the big question that QA can fill here, is what tests should run there? Or further down to the right. Why do I think TestOps is the next \u0026ldquo;big\u0026rdquo; thing? Because we went from water fall, where the initial cycle was defined. To sprints (the most common one right now) that are mini waterfalls. To now the new kids on the block, Kanban and clean room. So the more efficient these cycles become the more broad these roles will become.\nFri, 16 Dec 2022 16:14:08 -0600\n","permalink":"https://fonzi.xyz/blog/testopts-what-is-that/","title":"TestOps? What is that?"},{"content":" UI Automation Root Issues Ever since the inception of webapps, there has been issues with UI automation. Teams tend to overlook the automation phase and ignore it. Mostly because it\u0026rsquo;s time consuming and it\u0026rsquo;s really hard to have a decent framework. Test are also brittle. However, I peronslly think the brittle-ness is not Automation specific but usually and underlaying issue in the web app. It usually ends up showing up as bad code. Bad implementations, and bad architecture. Since automation is usually created after the webapp, it usually follows those same bad practices as the webapp. Now I\u0026rsquo;m NOT saying that these are the only issues. But from my experience these are usually the true root issues.\nSo how do we solve for this. Usually there seems to be three main problems to solve.\nBad Architecture Bad Implementation Bad Infrastructure Bad Architecture Usually this is the first issue. When a webapp has no cohesion around UI and functionality, each page will be it\u0026rsquo;s own small domain. This will make it very hard to abstract tests in order to re-use automation methods. The fix here is to get early into the development cycle and try to drive the model that will be used. However, this is easier said that done. Best approach is to point it out to developers in a nice way. However, good architecs are hard to find, so webapps end up displaying very odd functionality.\nModals with functionality - This is the terrbile espeially with smooth appearing Dropdows with a single button inside - Why is there even a dropdown button for a single button Async calls - This is usually where the bad architecture shows itself and it\u0026rsquo;s hardest to debug. Having all the network calls in async, and not understanding how and why they load in certain orders can cause havoc.\nBad Implementation This is usually done when there is some new cool hip JS library (another reason why I hate JS) and it\u0026rsquo;s the modern thing. Developers use the new library. And it\u0026rsquo;s not implemented correctly. Things are getting forced to the way of the webapp instead of the philosophy of the framework. This is usually and issue with developers not giving back to the Opensource Community. They want to take these establish frameworks. Make them work with some very specific need, and instead of making a PR for the framework to support the case, they\u0026rsquo;ll just hack around it. Usually by mixing another framework or another library making another half-assed implementation.\nBad Infrastructure Now this one is a bit harder to track down, but usually it\u0026rsquo;s obvious once you know what too look for. Usually, bad infrastructure shows as the webapp gets really slow when automation is running. This is usually observable by looking at a Monitoring Tool. Another easy spot is to look at the DB calls that it makes and see if something is locking the db. The final and hardest thing to track down with Infrastructure is the complextity around WAFs. If automation is distributed it might be that the WAF is blocking calls.\nSun, 04 Sep 2022 23:55:43 -0500\n","permalink":"https://fonzi.xyz/blog/ui-automation-root-issues/","title":"UI Automation Root Issues"},{"content":" Node IPC Going Back in Time Well I\u0026rsquo;m sure if you follow this blog (if anyone). You most likley heard of node-ipc. This reminds me a lot from when people did not know how malwayre worked, and the famouse worm that self duplicated by looking up everyone in the email contacts and sending itself out. What does this recent event says about the current \u0026lsquo;software developers\u0026rsquo; that it affected. It means that they have or at least had no concern about security. They just trusted their projects to one point of failure. A upstream library gone rouge. How could this been prevented? I think this goes back to the first things that I hinted, central technologies are a bad idea. Let this be a warning to alaways try to audit some code before you let some critical machine do an update. This is why the most important part of open source code is the abilty to audit the code. Now even this is by definition a new type of malware that has been called \u0026ldquo;protestware\u0026rdquo;, I disagree with this. How does deleting data from machines that have a Russian IP \u0026ldquo;protest\u0026rdquo; anything? What if this \u0026ldquo;protest\u0026rdquo; actually deleted work that could had expedited the end of the current Russia v Ukraine war. Or how does punishing every day Russians help them be against the war? If anything it\u0026rsquo;ll make them empathetic and start agreeing with the propaganda that the west is indeed out to hurt them personally. Brandon Nozaki Miller has himself pushed out of any career, nor will he ever be able to clear his reputation from this. He has hurted the open source trust and will be used as an example into why normal every day people should not switch from Windows or OSX to linux. Everyone is to blame here. Brandon Nozaki Miller, devs that just merged code into projects without auditing before (or looking at the releas notes. I highly suggest checking out the github issue page it is indeed comical, and it is even funnier watching Brandon Nozaki Miller delete the complains. Not only did he screw up and every one knows it, he is censoring opinions about it. To everyone commenting on there it would be better if you do a small snippet like this. No way he can delete this post.\nSat, 26 Mar 2022 18:35:15 -0500\n","permalink":"https://fonzi.xyz/blog/node-ipc-going-back-in-time/","title":"Node IPC. Going back in time."},{"content":" DuckDuckGo Failed Search Engine Well then. Here we are again. Another technology that will fall into the bin of dispair. DuckDuckGo, like all the other big tech companies will eventually die off. You have to wonder why they do this to themselves? To me it appears that technologies companies have forgotten their place in the world, and that is that technology moves fast. Really fast, and what is hip today, may not be hip tommorow. If you look at previous tech giants like Google, half the population, at least in the US, already despise it.\nDuckDuckGo is also in a very bad postion to try to manipulate the search results for mis-information. Most users of DuckDuckGo left Google or Yahoo, or even Bing due to the censorship under those platforms. Personally, I beleive that users are smart enough to figure out if something if fake, or at least to take it with a grain of salt. There is also the issue that DuckDuckGo has forgotten the number one rule when it comes to war. \u0026lsquo;The first casualty of war is the truth\u0026rsquo; I\u0026rsquo;m not one to stand on either side of Ukraine or Russia. I like most Americans have no horse in this race, so it should not concern us. However, will the Ukrain news articles also get censored? Has Ukraine never done propaganda? I doubt it. There is no state in this world that does not produce some form of propaganda, and saying otherwise is lying. These recent events just show that me and another small group of people are in the right path to try to detach from this current system of tech giants that control most of the internet services.\nHost your own website to write down rants like I do. Host your own search engine like I do over at searx.fonzi.xyz Host your own instagram. Host your own media. Host your own chat server. Host your own bank. Sat, 12 Mar 2022 01:05:04 +0000\n","permalink":"https://fonzi.xyz/blog/dudkduckgo-failed-search-engine/","title":"DuckDuckGo Failed Search Engine"},{"content":" Facebook down! A warning. So as you\u0026rsquo;ve heard Facebook was down. Not just Facebook, but all of Facebook. Instagram, Whatsapp, Facebook, and some other smaller services. I got to see firsthand how hard this actually was. In the United States, we are pretty lucky that almost every person has a cell phone with data. However, in other countries like Mexico, they use Facebook messenger, and WhatsApp as a means of primary communication. Facebook is free of data usage and so it\u0026rsquo;s WhatsApp down in Mexico with almost every plan that you can buy. For this reason, a lot of people use these services instead of using other non-facebook services. The real issue here is not that Facebook is giving their product for free, but rather, that people are willing to give all that personal information for just a simple messaging app. Data is a Billion dollar industry. Everyone wants data. And people get hardly any compensation for it because they are not aware of how much data is worth. Protect your data. Don\u0026rsquo;t give it away for free, at least make a little profit.\nSat, 09 Oct 2021 00:59:43 +0000\n","permalink":"https://fonzi.xyz/blog/facebook-down-a-warning/","title":"Facebook down! A warning."},{"content":" Blogging Frameworks Are Bloat Yes! Blogging Frameworks are bloat. Think about WordPress. Some people install WordPress just to blog. How many issues do you introduce to a website with WordPress? Even if you look at other frameworks that are found on Github. They all require some other stack that\u0026rsquo;s never on your server. Then you get stuck in limbo trying to get this framework that has 1000 stars because people star it but never actually try it out. So I ended just doing plain HTML with a little script I found in (github)[https://github.com/lukesmithxyz/lb]. I still need to modify this a bit, however, it got me off the ground right away. It\u0026rsquo;s gnu compliant so it\u0026rsquo;ll run on any system that has SED and bash. It just inserts blobs of text into files. In my instance, it throws code to blog.html and adds a new file for a standalone blog HTML as well as inserts text to rss.xml. This allows me to just write and not worry about how to run a specific framework, and all the security issues it brings with it. Now I hope that I\u0026rsquo;ll blog more since this is a much easier way to just add files to the blog list. No more manually adding those, no more cryptic commands that only exist in 1 project. This opens the question about what is happening to the tech industry/community. Do developers no longer enjoy simplicity? I can only imagine the things old-timers think when they see all this bloat on pages. Another popular way people do blogging, journalists mostly pay someone else to host their blog so they get an easy WYSIWYG system, but then complain when their freedom of speech is taken because they never actually owned the blog. It\u0026rsquo;s on someone else server. Their rules at that point. I do hope that this, what I\u0026rsquo;m doing having a very minimal website takes off again, what\u0026rsquo;s better than going back to decentralization with what already exists until the blockchain can fully be adopted if it\u0026rsquo;s ever adopted.\nThu, 07 Oct 2021 02:55:42 +0000\n","permalink":"https://fonzi.xyz/blog/blogging-frameworks-are-bloat/","title":"Blogging Frameworks Are Bloat"},{"content":" Hello There If you ended up here either you agreed with something on the homepage. Or you\u0026rsquo;re just clicking around. Either way.. Hello! This blog is dedicated to things I find interesting. Things about technology most of the time, but I also enjoy sociology a lot. So writing about human interactions maybe something from time to time. Also, you will find just recommendations for different things. This will mostly be something for me but I will try to curate those lists. You will also find quick lessons I\u0026rsquo;ve learned.\nThis blog also follows the minimalist web theme. Where I don\u0026rsquo;t have a blogging platform besides SSH a terminal and my thoughts. So you will just see new entries here without sorting or anything. Perhaps in the future, I\u0026rsquo;ll add something like that along with RSS to keep this going. One of my biggest pet peeves is trying to do a blog site.\nImagine my shock when I looked through countless GitHub repositories just looking for something that allowed me to just write and would auto-publish, after hours I found nothing that\u0026rsquo;s simple enough. Every technology for this sort of stuff has a very very very complex mechanism for what they do.\nTake a look. You\u0026rsquo;ll find things like a specific language for just that one blogging platform with no other uses. The worst thing is that it had about 1k stars. What is going on in the modern technology field? Do we no longer like elegant simple solutions? I have an idea to write about this bloated software and how I think modern society has shaped this.\nThu, 07 Oct 2021 02:55:42 +0000\n","permalink":"https://fonzi.xyz/blog/hello-there/","title":"Hello There"}]