437 karma · joined February 29, 2012
I imagine it would be pretty large, too.
The killer app of Docker isn't the container, it's the depth and uniformity of the UX surrounding the container system. When that is broken by something on the host (non x86 cpu was a major pain for a while before popular images were x-built) and emulation gets in the way and is not as easy, or just mildly different (windows behind corporate firewalls that assign ips used by the docker engine for example), the ease of use falls away for non-power users and it's all painful again.
Tech like Docker for windows and Rancher Desktop and lima has largely matured at this point, but somebody could make a new machine and then the process of gradual improvement starts all over again.
Even with free (in both senses of the word) products, the market will always work itself out.
That just isn't the case nowadays, so you don't know there will be trouble until it occurs at runtime.
I can limit the memory available to ALL the tools I use every day (I only do it for docker and jvm stuff), set priority levels, etc., but it feels very weird for a brand new laptop to hit swap after a few days of uptime.
It's free to produce, but the cost of running more copied software always increases.
Just as testing changes the way you structure your software, designing via formal methods changes the code that you produce as well, and it will attract a different set of people than traditional software dev, just as architecture attracts a different set of people than carpentry.
1. https://danq.me/2020/11/11/blink-and-marquee/#:~:text=Invent....
* lack of usb ports necessitating dongles * lack of hdmi/dvi outs * No camera lens cover * Uncomfortable chiclet keyboard * oversized touchpad * overheating * lack of power cores leads to slower parallel compilations
I do appreciate the ease of use of (especially) the network utilities of mac, but it's definitely not my preferred machine.
Can anyone expand on the differences between the projects (beyond the license)?
Really, you use testcontainers so that you can manage everything for your test with a single build command, instead of running something extra, then running your tests, then shutting down your docker containers. Plus, with it integrated into your test suites, you can run code against your docker containers on setup/teardown, before/after container start, before/after each test, etc.
Testcontainers does have a docker compose integration [1].
Halstead complexity measures the complexity of the "vocabulary" of code and the code "size". It uses the number of unique terms (arguments, variables), the number of unique operations (functions/methods/symbolic operators), and the total number of terms and operators to calculate difficulty and effort to produce. Lower is better. Obviously, more things and aliases and combinations of things are harder to understand than fewer things.
LCOM4 measures how many different responsibilities a module of code has. It measures whether or not two things in a module belong together by treating the code as a graph of nodes and counting the unique connected components in the graph. Greater than 2 means there is too much going on in the module, and it should be split to enhance understanding and reduce churn during maintenance. Obviously, if you are reading parts of the code that end up being irrelevant to the task at hand, you are going to be slower to accomplish whatever you are trying to accomplish.
Cyclomatic complexity measures how many execution paths there are in a given piece of code. Obviously, the fewer the better.
There are others - the counting complexity of the number of possible inhabitants of a given interface is a favorite of mine as well (is your interface a product, or a sum? Do you need strings or will an enum work? Do you need Long or can you get away with something smaller like Short or Int? Sum interfaces are smaller than product interfaces, and smaller ranged sum types - Short/int vs. Long - are better than larger ones because they reduce the number of possible satisfying implementations of the interface).
But the point is that all good simplicity metrics are static analysis metrics that are quantitative and not qualitative. Most are automated checks that can be performed given an abstract syntax tree of a program.
1. https://en.wikipedia.org/wiki/Halstead_complexity_measures 2. https://www.researchgate.net/publication/238729882_Measuring... 3. https://en.wikipedia.org/wiki/Cyclomatic_complexity
(
f andThen
g
)(x)
vs
a = f(x);
g(a);_andThen_ is of course just compose with the arguments flipped such that you can compose from left to right instead of right to left.
In FP languages, and languages that use FP combinators, it is usually more efficient to use composed functions with combinators that do iteration and copying like _map(list, f):List_, because the iteration and copying happens during each map application:
map(map(l, f), g)
and map(l, f andThen g)
produce equivalent results, but the second is faster and has fewer allocations.For determining the arguments to f and g and map, typed fp languages usually have ide features which can show you the inferred type of each expression, or you can jump to the definition and see it, usually by hovering or key chord while the cursor is over it.
map[A, B](
fa: List[A],
f: A => B
): List[B]
and etc.This allows you to read things easily and avoid cluttering the code with types where they can be easily inferred.
Point-free style is important to make the usage of such combinators acceptable but experienced devs do extract and name a composition when it becomes difficult to understand. Of course, the treatment of functions as effect-free black box transformers for equational reasoning also makes these refactoring extractions to variables safe to do.
You get a feeling for what is too much over time, and settle on when to use point free style and when not to.
On efficiency - good compilers can often identify nested/chained map applications and rewrite them as a single map application during compilation, but map fusion isn't guaranteed by all compilers or all _map_ instances. The evaluation strategy (lazy/eager) of the language and/data structure also plays a role in whether or not map fusion with point-free style is more efficient or optimisable.
NGINX is the de facto standard today, but I can remember running servers off apache when I began professionally programming. I remember writing basic cross-broweser spas with script.aculous, and prototypejs in 2005, before bundlers and react and node.
Everything gets gradually replaced, eventually.
I can do that via more complicated emacs web browsers that essentially render chrome in a buffer. But I shouldn't have to for things that are only text in the first place.
You also need to close issues after a set amount of inactivity[2].
If there is a bug without a CVE, or a feature someone wants fixed that users don't want to submit a fix for themselves AFTER it has been discussed with the maintainer in an issue with a replication or strawman proposal and the owner has created a draft pr and asked you to work on it, it probably needs to come with a Patreon donation[3]. This can help alleviate maintainer burnout by allowing the maintainer to hire someone to make the contribution.
A software shop wouldn't operate without some kind of iterative plan. Large open source projects with single maintainers shouldn't either. Scheduling 1 or 2 hours a week for issue triage, hosted in an online meeting, and limiting WIP in terms of open PRs to be discussed during this triage meeting should allow for both community interaction and strong governance for the project and prevent burnout for the maintainer.
All of this can be placed into the Readme or Contributor guide and a CLA that contributors have to sign.
Otherwise, people can fork and maintain the project themselves.
If you want to prevent flame wars, or demotivating comments, something like a comment sentiment analysis app[4] might even be a good idea to add to your project. There are plenty of models available that you can delegate to for this in the wild, and it's worth automating moderation to prevent burnout.
Finally, really toxic users can and should be banned[5]. It's not worth it to deal with anonymous negative contributors all the time.
1. https://github.com/marketplace/actions/close-pull-request
2. https://github.com/marketplace/actions/issue-triage
3. https://github.blog/changelog/2023-10-03-sponsor-projects-th...
4. https://github.com/marketplace/comment-sentiment-analyzer
5. https://docs.github.com/en/communities/maintaining-your-safe...
If your civilization is technically advanced enough to be a potential threat to such an actor, the highly energetic actions you are undertaking for interstellar travel will be visible to all of space via radio and infrared telescopes. Given that it will be economically infeasible to launch all of the payloads required to produce interstellar spaceships from within the gravity well of a planet, the orbital infrastructure required itself will lkely be visible as a periodic dimming of the planet's sun. It too, will give off infrared radiation detectable by a far-off technically advanced malignant actor.
There is no hiding in space. Your only hope for species and evolutionary survival in a dark forest is to aggressively disperse to uninhabited target systems. However, this also increases the likelihood that one of those systems will go rogue and eliminate the other ones it knows about.
Given this, the best strategy seems to be first avoidance of contact, then diplomacy, then detente, and finally alliance and assimilation in a Dark Forest universe. The allied powers can ensure that any bad actors that attempt elimination strikes are outnumbered and eliminated themselves.
On top of that, space is infinitely large. There are an enormous amount of finite resources within a planetary solar system which are way more energetically economic to exploit than ones in other systems. Once a civilization is forced to expand for survival beyond its local system, it is likewise economically cheaper to avoid warfare to claim one particular planetary system for its resources than to fight an interstellar war that risks the annihilation of the conflict participants' civilizations. There are literally an infinite number of systems to choose from.
There's no reason to destroy other competitors when the resources you are competing for are infinite. In such a scenario, which our universe seems to be an example, the only reason for conflict is malignant choice.
The prisoner's dilemma between two or more civilizations presented in the series would never need to occur.
The philosophy behind Three Body is just terribly cynical and illogical in the face of what we know of the existing universe. It makes for a great story, but the type of aggression posited in technical species doesn't provide an evolutionary advantage.
It should be noted that the entire Dark Forest philosophy presented in the book came from an unstable, traumatized, suicidal, xenophobic, nihilistic genius. Not the sort of person who you want forming the zeitgeist for existing in a much larger ecosystem of other civilizations.
If you accept the premise, then the series is great. But the premise assumptions are fundamentally flawed.
The U.S. is an extremely productive economy with at least one enormous cyclical natural catastrophe attached to it. If this natural catastrophe is preventable, and the costs of prevention are outweighed by the costs of losing the US economy, then it's probably worth doing.
I just assumed that it was one of those things that isn't economically or technically feasible.
Hodgepodge copy-template code that has minor context-sensitive structural differences is relatively difficult to find all instances of in a codebase without tracing execution paths unless you were the original author and you have the uses memorized. In contrast most IDEs have a find all references and even grep can find all the common names of something in a codebase.