diff --git a/assets/_cheese/2022/brick-house.jpg b/assets/_cheese/2022/brick-house.jpg new file mode 100644 index 0000000..281d7f5 Binary files /dev/null and b/assets/_cheese/2022/brick-house.jpg differ diff --git a/assets/_cheese/styles.scss b/assets/_cheese/styles.scss index 9fd2065..75c4d34 100644 --- a/assets/_cheese/styles.scss +++ b/assets/_cheese/styles.scss @@ -26,7 +26,7 @@ body { } p { - margin: 0.5em 0; + margin: 1em 0; } header { @@ -78,14 +78,12 @@ figure { img,figcaption { margin: 10px auto; - width: 90%; - max-width: 600px; padding: 0 10px; height: auto; display: block } -@media (max-width:500px) { +@media (max-width:600px) { img,figcaption { margin: 0; padding: 0; @@ -249,7 +247,7 @@ nav#TableOfContents ul { margin: 0; } -@media (max-width:500px) { +@media (max-width:600px) { nav#TableOfContents { float: none; width: 100%; @@ -294,7 +292,7 @@ nav#TableOfContents ul { content: ' - '; } -@media (max-width:500px) { +@media (max-width:600px) { .article-list li .article-date, .article-date li .article-title { display: block; diff --git a/content/log/git-subtrac.md b/content/log/git-subtrac.md index 9902168..3563aa9 100644 --- a/content/log/git-subtrac.md +++ b/content/log/git-subtrac.md @@ -1,11 +1,95 @@ --- -title: "git-subtrac and Zig" +title: "zig, git-subtrac and dependencies" date: 2022-04-23T05:37:51+03:00 draft: true --- -TLDR: I wish plain `git clone ` would check out submodules if they -are in the same repository. +TLDR: modern programming languages make it very easy to add many dependencies. +That is nice for development, but a nightmare for maintenance. Unfortunately, +zig is following suit. I wish we could accept that adding dependencies does not +have to be trivial. If we accept that, thanks to ubiquity of git, we may have +almost solved the dependency problem. + +Adding dependencies +------------------- + +All of the programming languages I've used professionally whose name does not +start with "c"[^1] have package managers[^2], which make "dependency +management" easy. These package managers will, as part of the project's build +process, download and build the dependencies, making adding and using +third-party dependencies easy. + +Because C/C++ still does not have a universal package manager, not adding +external dependencies to C/C++ is the path of least resistance. Instead, it is +common to rely on libraries already installed in the system. Because of this +cultural difference, there is a plethora of dependency managers that will +discover, but not install dependencies: autotools, cmake, pkg-config and +others. As a result, C/C++ projects I've been involved usually had 0-5 +non-system dependencies, whereas non-C/C++ projects -- tens, hundreds or +thousands[^3]. Having many system dependencies is painful for user experience, +so (the good) C/C++ projects also avoid having too many of them. + +Not doing things that are easy to do requires discipline: brushing teeth, +limiting candy intake, not adding dependencies all over the place. If it is +easy to add dependencies and there is no discipline not doing so, the project +will gain a lot of dependency "weight" with time. + +{{House made out of Duplo pieces}} + +In Go and Python small number of dependencies is often a sign of care and +quality. [mattn/go-sqlite3](https://github.com/mattn/go-sqlite3), +[uber/zap](https://github.com/uber-go/zap), +[apenwarr/redo](https://github.com/apenwarr/redo) and +[django](https://djangoproject.com) are good examples. Making it easy to depend +on external code is is convenient during development, but frees developers from +their basic right (or obligation?) to audit understand them. And adds real +long-term maintenance costs. + +The costs of just having dependencies are huge. I haven't done a survey and +have only my experience to base this on (read: "many anecdotes of me failing to +build stuff I wrote a decade ago"). But it is bad enough that I have a +dependency checklist and am prepared to do grunt work to avoid or strip it. +Here is my checklist: + +- Obvious: does it work at all? +- How easy is it to build, run and run it's tests? +- Is it well written? API surface, documentation, tests, error handling, error + signaling, logging, metrics (if applicable), etc. +- It's system dependencies. +- It's transitive dependencies. + +If a dependency is well written, but has more transitive dependencies than I +need and there is no good alternative, I will fork it and remove unnecessary +code and dependencies. My recent example is +[sql-migrate](https://github.com/motiejus/sql-migrate). + +To sum up, the "modern" languages optimize for initial development experience, +not maintenance. And as [Corbet says][linux-rust]. "We can't understand why +Kids These Days just don't want to live that way". Kids want to build, John, +not maintain. A 4-letter Danish corporation made a fortune by selling toys that +do not need to be maintained: they are designed to be disassembled and built +anew. It is very hard to change the guts of an existing structure without +rebuilding it. + +If I may combine Corbet's views with mine: if we understand and audit our +dependencies (and transitive ones), we will have less dependencies and a more +maintainable system. Win-win. + +Which brings us to... + +Transitive dependencies and git-subtrac +--------------------------------------- + +[`git-subtrac`][git-subtrac] does not deal with transitive dependencies. At +least not directly. Or I am not aware of it. Ok, I haven't tried. + +If we audit and thus understand our dependencies, we will be able to add +transitive ones to our project even without support of git-subtrac. So perhaps +git-subtrac shouldn't care? I use [`git-subtrac`][git-subtrac] for some of my projects, and am not very enthusiastic about Zig getting it's own package manager (can we all use @@ -13,8 +97,8 @@ git-subtrac and be done with it?). A few weeks ago in a park in Milan my conversation with [Andrew Kelley](https://andrewkelley.me/) was something like: - me: "git-subtrac yadda yadda yadda submodules but better yadda yadda yadda". -- Andrew: "if I clone a repository that uses git-subtrac with no extra - parameters, will it work as expected?" +- Andrew: "if I clone a repository that uses it with no extra parameters, will + it work as expected?" - me: "no, you have to pass `--recursive`, so git will checkout submodules... even if they are already fetched." - Andrew: "then it's a piece-of-shit-approach." @@ -37,80 +121,6 @@ make our dependency unavailable. It is, howerver, harder to *add* a dependency with submodules than with, say, `go get `. Let's talk about adding dependencies. -Adding dependencies -------------------- - -All of the programming languages I've used professionally whose name does not -start with "c"[^1] have package managers[^2], which make "dependency -management" easy. These package managers will download and build the dependency -tree, sometimes conveniently generate a "lock file", so your project has an -illusion of being "reproducible". - -C/C++ projects I've been involved usually had 1-5 non-system dependencies, -whereas all others -- tens or hundreds. This uncovers an obvious correlation: -if it's easy to add dependencies, they will be added. En masse. Not adding -dependencies in Go/Python/whatever requires discipline. Slip once, add some -crap -- it will be very hard to remove, as changing dependencies often require -large rewrites. Not adding dependencies in C/C++, however, is the path of least -resistance. However, in the long term, my C/C++ projects tended to survive -longest (or required least amount of changes to build and run after the world -moved on) just because of this. - -Making it easy to depend on external code is is convenient during development, -but frees (or denies, depending how one looks at it) developers from their -basic right (or obligation?) to understand them. And adds real long-term -maintenance costs. - -To sum up, the "modern" languages optimize for initial development experience, -not maintenance. And as [Corbet says][linux-rust]. "We can't understand why -Kids These Days just don't want to live that way". Kids want to build, John, -not maintain. This house is in desperate need of maintenance, but my son -refuses to do so, and builds a new car instead. - -{{House of Duplo pieces}} - -This is why I am always hesitant to pull in code to my project, and have a my -dependency checklist: - -- Obvious: does it work at all? -- How easy is it to build, run and run it's tests? -- Is it well written? API surface, documentation, tests, error handling, error - signaling, logging, metrics (if applicable), etc. -- It's system dependencies. -- It's transitive dependencies. - -Zooming into the last part: C projects tend to do it well. For Go and Python -projects a small number of dependencies is often a sign of care and quality on -other areas, too. [mattn/go-sqlite3](https://github.com/mattn/go-sqlite3), -[google/brotli](https://github.com/google/brotli), -[apenwarr/redo](https://github.com/apenwarr/redo), -[cmph](http://cmph.sourceforge.net/) are good examples. - -If a dependency is well written, but has more transitive dependencies than I -need and there is no good alternative, I will fork it and remove unnecessary -code and dependencies. My recent example is -[sql-migrate](https://github.com/motiejus/sql-migrate). - -If I may combine Corbet's views with mine: if we understand and audit our -dependencies (and transitive ones), we will have less dependencies and a more -maintainable system. Win-win. - -Which brings us to... - -Transitive dependencies and git-subtrac ---------------------------------------- - -[`git-subtrac`][git-subtrac] does not deal with transitive dependencies. At -least not directly. Or I am not aware of it. Ok, I haven't tried. - -If we audit and thus understand our dependencies, we will be able to add -transitive ones to our project even without support of git-subtrac. So perhaps -git-subtrac shouldn't care? - Conclusion ---------- @@ -118,10 +128,12 @@ Can git checkout local submodules when they are in the same repository, so our conversation of reconsidering (or not having) a zig package manager doesn't stop after 5 seconds? -[^1]: Alphabetically: Erlang, Go, Javascript, PHP, Perl, Python. +[^1]: Alphabetically: Erlang, Go, Java, Javascript, PHP, Perl, Python. [^2]: Usually written in the same language. Zoo of package managers (sometimes a couple of popular ones for the same programming language) is a can of worms in an on itself worth another blog post. +[^3]: `go.sum` of a project I am currently involved clocks around 6k lines. + This is quite a lot for Go, but still peanuts to Node.js. [git-subtrac]: https://github.com/apenwarr/git-subtrac/ [linux-rust]: https://lwn.net/SubscriberLink/889924/a733d6630e3b5115/ diff --git a/layouts/shortcodes/img.html b/layouts/shortcodes/img.html new file mode 100644 index 0000000..aee10a7 --- /dev/null +++ b/layouts/shortcodes/img.html @@ -0,0 +1,79 @@ + + + +{{ $src := resources.GetMatch (.Get "src") | resources.Fingerprint }} +{{ $max := $src | resources.Fingerprint }} +{{ $j350 := $src.Resize "350x" }} +{{ $j700 := $src.Resize "700x" }} +{{ $j1400 := $src.Resize "1400x" }} +{{ $j2800 := $src.Resize "2800x" }} + +{{ with .Get "hint" }} +{{ else }} + {{ errorf "missing value for param 'hint': %s" .Position }} +{{ end }} +{{ $hint := .Get "hint" }} +{{ $w350 := $src.Resize (print "350x webp " $hint ) }} +{{ $w700 := $src.Resize (print "700x webp " $hint ) }} +{{ $w1400 := $src.Resize (print "1400x webp " $hint ) }} +{{ $w2800 := $src.Resize (print "2800x webp " $hint ) }} + +
+ {{ with .Get "link" }}{{ end }} + + + + + {{ if .Get "link" }}{{ end }} + {{ if or (or (.Get "title") (.Get "caption")) (.Get "attr") }} +
{{ if isset .Params "title" }} +

{{ .Get "title" }}

{{ end }} + {{ if or (.Get "caption") (.Get "attr") }}

+ {{ .Get "caption" }} + {{ with .Get "attrlink" }} {{ end }} + {{ .Get "attr" }} + {{ if .Get "attrlink" }} {{ end }} +

{{ end }} +
+ {{ end }} +
+