×


dumpster.baby - The Aborted Fetuses of the Industry.

A blog on software failures.

See All Articles

Fragile Dependency Management

Ahmed Allen, Dead Babe 2024-07-05

When starting our C++ journey, we tested most of the industry-standard dependency management solutions like vcpkg, conan, github submodules, and several others.

We found all of these solutions to be fragile, unwieldy, or otherwise in bad taste. So we eventually found CMake Package Manager.

It's straightforward, a single script you add to your CMakeLists which allows pulling from our self-hosted git repositories. It allows us to link to specific releases to prevent versioning conflicts.

After several months of seamless and productive work with our technology stack, we've encountered the strangest issue.

Out of seemingly nowhere, Gitea changed it's behavior in regards to releases.

We publish releases for our projects, and gitea generates an archived zip file that can be directly downloaded. We use CPM in our projects to automatically pull these dependencies and build them.

However, a CPM call given a package url like "https://git.redacted.cc/maxi/mcolor/archive/Prerelease-1.zip", will expect to download a file with the name Prerelease-1.zip. This is obvious. At some point, the format changed. The file it actually downloads has the package name prefixed to it, i.e. "mcolor-Prerelease-1.zip".

What's the problem, you may be asking? It's a simple filename change, how hard can it be to accommodate?

Unfortunately, there is no straightforward way to specify a custom archive name, and there is no apparent way to set the format gitea uses to create the zip archives.

EDIT:

While writing this article, the issue seems to have disappeared. What the fuck? At least it works now.

This issue was a major pain in the ass. We frantically and angrily read through our configs, looked through the site-administration settings, read the Gitea source code for our version, and upgraded Gitea to a newer version to no avail. There's absolutely no reason why this issue occurred and remains unexplained. At one point we suspected someone may have gotten into our systems, but everything looked untampered with. While a giant leap the idea of that could cause this issue it didn't hurt to check just in case.

The strangest thing we found when debugging this issue was when we downloaded release archives with curl and wget. Curl and wget were not affected, but CPM and firefox were. Even stranger CMake uses the curl library for downloading files, so it's hard to say why this was happening.

Anyway fuck Gitea

Fuck Docker

Dead Babe 2024-07-03

Docker fucking sucks. Nothing too technical to say here about my gripes with the most well known container system in the world. I'm mostly just pissed.

Why Docker Fucking Sucks

Docker fucking sucks because it is the most overcomplicated garbage I have ever used. Docker has too many variables to keep track of and makes the simpliest of tasks more difficult than need be. Often times Docker builds up bad habits in developers. One of the worst habits I've seen is the overreliance on Docker to run web applications. Testing applications with docker is one thing, but a completely different story when the application in question cannot run outside of a Docker container. Too often I see large bloated web applications that constantly shit themselves because of their overreliance on container technology. These applications are developed to be tightly bound to their dependencies. It also doesn't help that languages like Python and the Node JS runtime constantly change in breaking ways. Python is really fucked because of the fact if you wrote a program for Python 2 good luck running it on Python 3 without suicidal ideation. Node JS is even more fucked because for 1 Java Script for 2 fuck you.

If It Needs Docker Its Garbage

If your application needs docker to run your application is garbage. It's a sign you need to reevaluate the work you've done. It's a sign your application is far to dependent on specific constantly changing dependencies. You're application is not robust and should not be running in production. Use Docker for its intended use case instead as a diaper to hold in your diarrhea of software engineering skills. This article took a turn didn't it?

Docker's Intended Use Case

Docker is intended to make running applications more secure by sticking them in a box isolating them from the host however too many shitty developers don't use it that way. To get more technical about it Docker and containers as a whole are designed to easily setup a namespace for an application to force the application to only have access to resources that it is permitted to have access to. In reality Docker and Linux containers overall are just a bastardization of Plan 9 namespaces. Every application in Plan 9 is started with its own namespace and only inherits resources when told to. It's all baked in and not this half-ass interpretation of it. Did you know the idea of namespaces came from Plan 9? Anyway all this namespace and container mumbo jumbo is for security reasons NOT a safety net for dogshit software engineering. Docker is also a shit implementation of Plan 9 namespaces.

Thank You For Coming To My Uncle Ted Talk

Thank you for coming to my uncle Ted Talk. I'm so greatful to have you as a reader and hope this article gave you a chuckle. Please consider donating to my Only Fans to support this content.

Monero: 42dAoQQFiT31Z86XPhrj7Y1nKwW8jvMDpTPZZTV1SfgS7vvBt24xgRneuQ3gmCuhQVUmKtMnVNEnQ8K589g2eFtTEam8HqU

Don't work with children.

Ahmed Allen 2024-07-03

For all it's faults, the ROBLOX community really was a magical thing.

A young boy from North Alabama fancies himself a tinkerer. Any old electronics found by the roadside, or in mom's closet, is subject to dissection, study, (attempted) reassembly. Dreams of building giant robots or rocket engines abound.

Then came the spark - watching an older brother bring over his PlayStation2, later an XBox360. Hitman, Call of Duty, GTA, you know them all already. The child was intensely fascinated with how a plastic box could make interactive games appear on the TV. But the details and capability to do so eluded the 6-year-old for some time. He resigned himself to sketching map concepts on graph paper.

Later on, that child gets a laptop for his 10th birthday. Immediately he takes an interest in building games, and rather obviously, stumbles upon this thing called ROBLOX.

The CaveGame Post Mortem

Ahmed Allen 2024-07-03

CaveGame was my baby. A personal passion project, dragged into oblivion due to a multitude of personal issues.

This Post-Mortem will discuss personal struggles with addiction and motivation, insofar as it relates to productivity in software development

The "While-Wait-Do" Idiom

Matthew I. (CntKillMe)

Written September 2018

Introduction

 First and foremost, this is a document about a Roblox-specific concept that plagues experienced and inexperienced developers alike. If you don't do scripting within Roblox, this article is probably not going to be useful.

 It is very popular among the community to "shorthand" while loops by expressing the condition of the while loop with (or containing, typically as part of a conjunction) a function call to wait. At first glance, this seems rather innocent: an extra line is usually saved and the code is often just as readable. However, the drawbacks of such an idiom completely dominate all assumed (often inaccurately) benefits and can result in illogical coding habits.

 Not following this idiom has become almost a stigma in Roblox. There will always be a group of people telling you that you can and should be calling wait within the conditional portion of the while statement as opposed to in the body. The "apparent" benefits to this typically masks the problems encouraging such an idiom results in. Newcomers are taught to do this from an early stage and it infects their habits in a somewhat significant way.

Benefit - "Less code is cleaner [or more readable] code"

 This is by far the most popular rationale behind why people prefer to use this idiom. I cannot deny that this appears to often be true when taken at face value, but it is really only true when less code results in less complexity, which is not always the case.

 If we define cleaner in a way that reasonably minimizes line count, then sure, you have an argument. You sometimes save what on average is about 1 line per all applicable while loops (more on this later). However cleaner is best defined as something that is more simple and maintainable (which typically yields more readable code). A few extra lines typically will not affect readability, however abusing the purpose of the conditional portion of a while loop is clearly less simple.

 When you call wait in the condition for whether the loop should continue, you make the implication that the return value is somehow important in determining whether or not the loop should terminate. Except that in all scenarios where this happens, the return value of wait is irrelevant. The fact that it returns anything at all is irrelevant, we just abuse the fact that wait does return something that is neither false nor nil. This is clearly less simple code, because we introduce an unnecessary test for our condition when we already know it will never be false or nil.

 The entire purpose of the conditional part of a while loop is to determine when the loop should terminate. When while true do is read, you understand it is as an infinite loop immediately. True is always true, which makes it obvious that the loop does not necessarily have a terminating condition.

 When while f() do is read, the general idea is the loop will not terminate until f returns a falsy value. while wait() do then, when directly interpreted, means the loop will terminate once wait returns a falsy value. The problem is this idiom alters our perspective and makes an exception to this rule, we no longer treat the terminating condition as a terminating condition when wait is called. We learn to associate while wait() do as a non-terminating loop. Clearly an unnecessary distinction, and one that can be quite confusing for beginners who have not yet come across this idiom. Although the added complexity is quite small, the pitfalls that come about utilizing such an idiom can be quite alarming (more on this later).

Benefit - "Less code is faster code"

 Most people already know this is false, and admittedly this rationale is not often used as an argument in favor of this idiom. However I have come across quite a few people who believe this to be true. Of course it is not true, the performance difference between the two are beyond negligible that outside noise is likely to make more of an impact. It is unfortunate that people always fall accustom to premature optimization, but it is these people that argue in favor of this idiom just for this reason. If they can be pedantic, so can I. Technically, following this idiom actually results in slower code as the return value of wait must be tested. However Lua does a small optimization when certain truthy constants are used as the condition, no value testing will need to be done and instead it will fall straight through into the loop's body (see luaK_goiftrue in lcode.c). Of course testing a value is quite quick, so for me to tell you to not to use this idiom because it is slower would make me a victim of premature optimization. Truth is, there is practically no difference and it is not even worth thinking about.

Benefit - "Everyone uses it"

 This rationale is perhaps the only real benefit. In general, it is a good idea to follow the same conventions everyone else uses to write more consistent and easily-understood code. Unfortunately, not all popular conventions are sound. There is no doubt that many have become accustomed to this idiom, but following it is bad practice. Needlessly increasing the complexity of our code in such a way is just unnecessary and following this idiom almost always redefines what the conditional part of a while loop is even meant to be used for.

Non Maintainability

 Perhaps the most obvious problem is how the idiom strips our freedom by forcing us to yield at the start of each iteration rather when it may be more appropriate. From a functionality standpoint, this seems to be hardly a problem. However by staying consistent with this convention, the return value of wait will always be lost. Normally that is fine, however in some cases it is very useful to know how long the thread has actually been yielded for. Typically if logic needs to be adjusted precisely over time, the return value of wait can be important to ensure consistent logic across fluctuating yield times. In such a case, the call to wait will be moved into the body. In the worst case, wait is called again within the body because the idiom is too deeply rooted that it becomes impossible to imagine a while loop that does not call wait in its conditional part. As stupid as this might sound, it is a somewhat common mistake that occasionally affects newcomers. By consistently pushing this idiom, beginners see it to be a good convention to follow and stick to it. Before they even fully understand while loops they are writing code that abuses it.

Bad Habits

 Since following this idiom results in a sort of mindset change that makes abusing while loops like this okay, it becomes easy to forget what the purpose of the conditional part even is. All too often code is written in the following manner:


      1. while wait() do
      2.     if ((p1 - p2).Magnitude <= 100) then
      3.         break
      4.     end
      5. end
      

instead of in the correct manner:

      1. while (p1 - p2).Magnitude > 100 do
      2.     wait()
      3. end
      

 Actually utilizing while loops correctly instead of sticking with this idiom can easily increase simplicity, readability, maintainability, and (to a miniscule extent) efficiency. This is not just a trivial example, a lot of people write similarly to the first example all the time. I was at one point a "While-Wait-Do Idiom Follower" as well. Time and time again I would see people spouting nonsense like "while true do crashes your place, always do while wait() do instead." Or when people were being convinced to follow this idiom if they have not already because some established group of people (i.e. active forumers and popular developers) were doing so.

Too Long, Didn't Read

I follow this idiom for:

  • Readability reasons: No.

  • Maintainability reasons: No.

  • Performance reasons: Read benefit 2.

  • Conventional reasons: Get over it.

  • Because I can: Congratulations! You're a bad programmer.

I don't follow this idiom for:

  • Readability reasons: Okay.

  • Maintainability reasons: Yes.

  • Performance reasons: Read benefit 2.

  • Conventional reasons: You're a rebel. 🤘

  • Because I can: Congratulations! No one cares.

This work is dedicated to the public domain.