Rui Vieira's blog

2023

Orca's fashion

September, 18th - The waters around the Iberian Peninsula (mostly reported off the Spanish and Portuguese coasts) have been of interest for marine biologists due to a notable increase in interactions between orcas and boats. Having intricate social structures and intelligence, orcas display behaviours that may be influenced by a multitude of factors such as environmental and social ones.

Scientists postulate that these interactions might be representative of a transient “fad” within orca pods. For perspective, in 1987, there was an observable trend among the southern resident orcas of Puget Sound, who took to carrying dead salmon on their heads. This behaviour, while seemingly anomalous at the time, did not persist.

ocean2.gif

Modernism and Gazette

September, 16th - Recently, I’ve been reading a fair bit about John Dos Passos, and while I haven’t still read any of his books, his approach to literature seems quite avant-garde for his time. The “USA Trilogy” is frequently cited as a significant exploration of American life in the early 20th century, using techniques like the “Newsreel” and “Camera Eye” to tell his narratives. From the discussions and summaries I’ve encountered, Dos Passos seemed to have a knack for interweaving fiction with the pressing sociopolitical issues of his era. It’s intriguing to think about the depth of his works without having directly experienced them.

john_dos_passos.jpg

Gazette and scroll

I was considering moving the entirety of the blog (not the site, just these pages) to scroll. Unfortunately, scroll is not a great fit for the rest of the site’s workflow.

At the moment, it’s a bit of a compromise. I’m using the Gazette style for the blog page, but it’s just the CSS. The underlying process of building the site is the same (still using Markdown).

A thought on !important

In CSS, !important is really not a good idea. It’s make debugging very time-consuming and fundamentally breaks the Cascading part of CSS.

Reducing software bugs

Just read Daniel J. Bernstein’s “Some thoughts on security after ten years of qmail 1.0paper on mitigating software bugs, I found these to be the main takeaways:

  1. Code Reviews Matter: By thoroughly reviewing your code, you can get a sense of its vulnerability to bugs. This isn’t just about finding immediate errors, but evaluating the overall quality of your software-development approach. Adjust your strategies based on these reviews for better outcomes.

  2. Measuring Bugs: There are two primary ways to gauge the ‘bugginess’ of software—either by looking at the bugs per specific task or bugs per line of code. Each approach has its merits. While the former can give insights into the efficiency of a task, the latter can be an indicator of how long debugging might take.

  3. Eliminate Risky Habits: In coding, as in life, some habits are more prone to mistakes than others. Identifying these risky behaviours and addressing them head-on can dramatically cut down on errors. This might even mean reshaping the coding environment or tools used.

  4. The Virtue of Brevity: A larger codebase naturally has more room for errors. If two processes achieve the same result, but one does it with fewer lines of code, the latter is generally preferable. It’s not about cutting corners but about efficiency and clarity.

  5. Access Control: Just as you wouldn’t give every employee a key to the company safe, not all code should have unrestricted access. By architecting systems that limit code permissions, you add another layer of protection against potential issues.

In conclusion, a proactive, thoughtful approach to coding—paired with smart strategies and tools can significantly reduce software bugs.

Issue bankruptcy

Today Lodash declared “issue bankruptcy” and closed 363 issues 325 PRs to start afresh.

KNative missing CRDs

September, 7th - If you’re using Kubernetes 1.27.3 to install KServe 0.9 or 0.10, you might encounter this error:

resource mapping not found for name: "activator" namespace: "knative-serving" 
from "https://github.com/knative/serving/releases/download/knative-v1.7.0/serving-core.yaml": 
no matches for kind "HorizontalPodAutoscaler" in version "autoscaling/v2beta2"
ensure CRDs are installed first
resource mapping not found for name: "webhook" namespace: "knative-serving" 
from "https://github.com/knative/serving/releases/download/knative-v1.7.0/serving-core.yaml": 
no matches for kind "HorizontalPodAutoscaler" in version "autoscaling/v2beta2"

Here’s the main issue:

Kubernetes 1.27.3 no longer supports the autoscaling/v2beta2 API version of HorizontalPodAutoscaler. The Kubernetes release notes state:

The autoscaling/v2beta2 API version of HorizontalPodAutoscaler is no longer served as of v1.26.

Meanwhile, KNative’s release notes indicate that its v1.7 version is validated for Kubernetes v1.24 and v1.25 only, which leads to this compatibility problem.

Possible solutions:

  1. Downgrade: Use Minikube v1.25 to ensure KNative works without changes.
  2. Edit the Manifests: Adjust the manifests to resolve the version discrepancy.
  3. Wait for an Update: A future KNative release will likely fix this compatibility issue.

A note that if you go the Downgrade route, you might see the following warning on your logs:

Warning: autoscaling/v2beta2 HorizontalPodAutoscaler is deprecated in v1.23+, unavailable in v1.26+;
use autoscaling/v2 HorizontalPodAutoscaler

JUnit null and empty sources

September, 5th - Today I learned about JUnit’s ability to use null sources in conjunction with @ParamterizedTest. Example:

@ParameterizedTest
@NullAndEmptySource
@ValueSource(strings = {"test", "JUnit"})
void nullAndEmptyTest(String text) {
    Assertions.assertTrue(text == null || text.trim().isEmpty() || "test".equals(text) || "JUnit".equals(text));
}

There’s also @NullSource and @EmptySource.

LunarVim

September, 4th - Been trying out NeoVim in the format of LunarVim.

To use with a GUI on macOS, I use NeoVide, with the command

neovide --neovim-bin ~/.local/bin/lvim --multigrid --maximized --frame none

If you are planning on using Neovim I recommend using a tree-sitter-aware theme. You can find a list here. My personal favourites are modus and gruvbox-material.

Hatch Poetry

September, 3rd - I’ve been a long-time user of Poetry for my Python projects, and it’s been a welcome change. However, my recent exploration into Hatch has sparked my interest.

Poetry simplifies dependency management with its unified pyproject.toml, but Hatch excels in scenarios requiring complex workflows. A common personal use-case is Docker multi-stage builds. Hatch, with its conventional requirements.txt and setup.py, offers more granular control, making complex configurations easier.

Hatch also aligns closely with the existing Python ecosystem due to its use of traditional setup files, linking old with new workflows, ensuring a better integration.

For instance, if using a container image manifest such as

# Use a base Python image
FROM python:3.9-slim as base

# Set up a working directory
WORKDIR /app

# Copy requirements and install dependencies
COPY requirements.txt .
RUN pip install -r requirements.txt

# Copy the rest of the application
COPY . .

# Other Docker configurations...

Whereas with Poetry, you might need to install it within the Docker image and use poetry export to generate a requirements.txt equivalent, with Hatch, since it supports the traditional requirements.txt, integration with multi-stage builds can be simpler.

Exception Bubbling in Python

September, 2nd - One aspect of Java that occasionally nudges at me is its explicit approach to exception handling. Java requires developers to either handle exceptions via try-catch blocks or declare them in method signatures. While it does enforce robustness, it sometimes feels a bit too constrained, especially when compared to the flexible nature of Python.

Recently, I crafted a solution in Python for k8sutils. Instead of the usual explicit exception handling or modifying method signatures, I created a Python decorator - akin to annotations in Java - that substitutes an exception for another without altering the underlying code. Here’s what it looks like:

import functools
import subprocess

def rethrow(exception_type=Exception):
    """Rethrow a CalledProcessError as the specified exception type."""
    
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except subprocess.CalledProcessError as e:
                raise exception_type(f"Command failed: {e.cmd}. Error: {e.output}") from e
        return wrapper

    return decorator

Using this decorator, it becomes straightforward to alter the exception being thrown:

@rethrow(ValueError)
def get(namespace=None):
    """Get all deployments in the cluster."""
    cmd = "kubectl get deployments -o json"
    if namespace:
        cmd += f" -n {namespace}"

    result = subprocess.run(cmd, shell=True, check=True, capture_output=True, text=True)
    deployments = json.loads(result.stdout)
    return deployments

The @rethrow(ValueError) decorator automatically translates a CalledProcessError to a ValueError without the need to change the method’s code.

For another example:

@rethrow(RuntimeError)
def delete_deployment(deployment_name):
    """Delete a specific deployment."""
    cmd = f"kubectl delete deployment {deployment_name}"
    subprocess.run(cmd, shell=True, check=True)

Here, instead of bubbling up the generic CalledProcessError, any error encountered will raise a RuntimeError.