1. 4

    This is progressing towards the rediscovery of regular expressions.

    1. 4

      Indeed. If anyone finds this article interesting and doesn’t know regular expressions (“regexes”) yet, I recommend reading regular-expressions.info/tutorial.html. When I learned regexes from that site I found it to be well-written. The site plugs the author’s own regex-testing tool in between explanations, but you can just use regex101.com, which is free and equally powerful.

      Here’s an example of using a regex in Python to extract text within square brackets:

      import re
      string = "123[4567]890"
      re.search(r'\[(.*)\]', string).group(1)  # evaluates to '4567'
      
      # You could also write the regex with whitespace for readability:
      # re.search(r'\[ (.*) \]', string, re.X).group(1)
      

      Regexes have some advantages over the extract DSL defined in the article. They support powerful features such as extracting multiple parts of the text with one search. They are supported by all major programming languages. Most text editors let you use them to search your text. They are also very concise to type. However, they have flaws of their own, particularly how hard they can be to read. So though regexes are useful to learn, they are not the ultimate way of extracting parts of text.

      Here are some projects that aim to improve on regexes (but are much less widespread):

      • Regexes in the Raku language. Raku, formerly known as Perl 6, breaks compatibility with Perl 5’s regex syntax (the same syntax used by most regex engines) in an attempt to make regexes more readable.
      • Egg expressions, or eggexes, are a syntactic wrapper for regexes that will be built into the Oil shell.
      1. 2

        And Parse in Red is also a nice alternative to regexes.

        1. 2

          I’d prefer r'\[(.*?)\]' or r'\[([^]]*)\]' to avoid multiple square brackets in the string matching more than expected. Also, in newer versions of Python, you can use [1] instead of .group(1)

          https://www.rexegg.com/ is another great site for learning regexp. And https://github.com/aloisdg/awesome-regex is a good collection of resources for tools, libraries, regexp collections, etc.

        2. 3

          Perhaps we can coin a new aphorism! Greenspun’s Tenth Zawinski’s Law: Any sufficiently complicated Lisp text processing program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of regular expressions.

          Edit: Or perhaps ‘Every Lisp program attempts to expand until it contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of regular expressions. Programs which cannot so expand are replaced by those which can.’

          1. 8

            Summary: this person’s team narrowed their choices down to C++ or Rust, then chose C++ because they were more familiar with that language. The article describes no further reasons to avoid Rust.

            1. 7

              The article describes no further reasons to avoid Rust.

              … or advantages that would support its adoption over C++

              1. 10

                Will it let me modify this website to be accessible to people who can’t or don’t want to watch videos?

                1. 3

                  Yeah, it is infuriating (and embarrassing) for an accessibility tool to not provide an accessible transcription of the videos. Meh.

                  1. 7

                    I don’t know why this is labeled “a11y”, it’s not necessarily a tool for enhancing accessibility.

                  2. 2

                    My phrasing here is trollish (apologies to anyone hurt) but my point is serious.

                    1. 1

                      If you follow the link to the web version of the Convivial Computing Salon paper, that page has plenty of writing about the project:

                      In this paper, we present spreadsheet-driven customization, a technique that enables end users to customize software without doing any traditional programming. The idea is to augment an application’s UI with a spreadsheet that is synchronized with the application’s data. When the user manipulates the spreadsheet, the underlying data is modified and the changes are propagated to the UI, and vice versa.

                      We have implemented this technique in a prototype browser extension called Wildcard.

                    1. 5

                      Reply to zb1c4k and should be merged.

                      1. 5

                        Didn’t we just get told not to use langs installed by homebrew because other casks use it as a dep and it will be upgraded without notice?

                        1. 6

                          Yes. So:

                          use a version manager such as asdf, chruby, rbenv, or rvm.

                          This author didn’t get the memo on Homebrew yet. That’s okay.

                          1. 2

                            Link in case anyone missed that story: Homebrew Python Is Not For You

                            1. 1

                              Just wanted to say thanks for the link. I’ve updated the advice about installing Ruby with Homebrew.

                          1. 2

                            As somebody who is implementing a dynamically typed programming language, I don’t agree with the author. Generating high quality error messages is a lot of work regardless of what kind of language you are implementing. You don’t automatically get high quality errors in a statically typed language. High quality errors are not categorically impossible in a dynamically typed language (as claimed), it’s just an engineering problem. It looks to me that the GHC team has invested more effort in producing good errors than the Nix team, that is all.

                            1. 1

                              High quality errors are not categorically impossible in a dynamically typed language (as claimed), it’s just an engineering problem.

                              Engineering effort can certainly improve error messages in dynamically typed languages, resulting in high quality errors in certain cases. But I have trouble believing that dynamically typed languages can always produce an error as good as one from a statically typed language.

                              Consider how a dynamically typed language could possibly produce an error as useful as this hypothetical Nix static type error from the article:

                                  { option = [
                                      "max-jobs=5"
                                      "cores=4"
                                      enable "fallback"
                              #       ~~~~~~
                              #       This element of the list is not a string
                                    ];
                              

                              One of the article’s key points is the convenience of seeing where the error is in your actual code. How could dynamically-typed Nix provide that?

                              If it tracked function names better, its error message could have “enable” in place of “<λ>”, resulting in ‘generators.mkValueStringDefault: functions not supported: enable’. But that’s still not as useful as the above error. Knowing the unexpected function’s name is enable wouldn’t be much help if you had many instances of enable in the list, but you forgot to parenthesize only one of them.

                              An additional problem with that dynamic error message is that it says the error is within the function generators.mkValueStringDefault. The user’s code never explicitly called that function, so they might have to read their whole program to locate the problem. This could be mitigated by displaying the stack trace along with the error:

                              generators.mkValueStringDefault: functions not supported: enable
                              something.blah
                              something.foo
                              pkgs.lib.cli.toGNUCommandLine
                              something.processOptions
                              

                              But that still forces the user to scan the list until they find a function in their actual code, then read all parameters they pass to that function (and that’s assuming global state didn’t cause the error). The example static type error above skips those steps by highlighting the exact line the error was on.

                              Now, I could imagine some hybrid type system that doesn’t raise errors until a runtime problem is encountered, and then parses the source code to find all the values that contributed to the problematic value existing. That could be neat… but at that point the work has already been done to implement a static type system. At that point, it would be better make the language also do static type checking, allowing users to sometimes be notified of problems before they happen.

                              It looks to me that the GHC team has invested more effort in producing good errors than the Nix team, that is all.

                              Above I was describing how creators of a dynamically typed language could invest extra effort to replicate something the hypothetical statically typed language got almost for free. To get the type error “This element of the list is not a string”, the hypothetical static-typed-Nix team only had to annotate function return types. If that team tried to invest as much effort as the hypothetical dynamic-typed-Nix team, they might improve the type error further to this:

                                      enable "fallback"
                              #       ~~~~~~
                              #       This element of the list should be a string, but is a function.
                              #       
                              #       The formatting of your source code makes me think you might
                              #       have wanted this line to be a function call, like this:
                              #           (enable "fallback")
                              #       That would produce a string.
                              

                              Could you produce an error message like this with a dynamic type system?

                              1. 1

                                Racket is dynamically typed and this is how you can get similar error messages in it:

                                #lang racket
                                 
                                (module+ server
                                  (provide (contract-out [foo (-> (listof (and/c string? lower?)) number?)]))
                                  (define (lower? s) (sequence-andmap char-lower-case? s))
                                  (define (foo l) (length l)))
                                 
                                (module+ main
                                  (require (submod ".." server))
                                  (foo (list 'enabled "baz")))
                                

                                will produce:

                                foo: contract violation
                                  expected: string?
                                  given: 'enabled
                                  in: an and/c case of
                                      an element of
                                      the 1st argument of
                                      (-> (listof (and/c string? lower?)) number?)
                                  contract from: (/tmp/c.rkt server)
                                  blaming: (/tmp/c.rkt main)
                                   (assuming the contract is correct)
                                  at: /tmp/c.rkt:4.26
                                

                                In fact as you can see, Racket is able to enforce not only simple type level properties (is it a string?) but also much more interesting properties about values - does the list contain only lower case strings? (foo (list "baZ")) will produce:

                                foo: contract violation
                                  expected: lower?
                                  given: "baZ"
                                  in: an and/c case of
                                      an element of
                                      the 1st argument of
                                      (-> (listof (and/c string? lower?)) number?)
                                  contract from: (/tmp/c.rkt server)
                                  blaming: (/tmp/c.rkt main)
                                   (assuming the contract is correct)
                                  at: /tmp/c.rkt:4.26
                                
                                1. 1

                                  The error message in your first example is certainly more useful than error-checking in most dynamically typed languages. However, I think you missed the point of my comment, because that example doesn’t really address any of these problems that I noted Nix’s dynamically-typed message has and the statically-typed error message wouldn’t have:

                                  • Your example’s error message does show the incorrect value, “given: 'enabled”. But would this still work if the incorrect value were an anonymous function rather than a symbol? Or would Racket just say “given: <λ>” like the Nix example unhelpfully does?
                                  • Your example’s error message doesn’t include the stack trace at the point the incorrect value 'enabled was found. So if your example program used 'enabled correctly many times within the list but uses it wrongly once, you would have to manually scan all your program’s usages of it.
                                  • Even if Racket outputted the stack trace when 'enabled was found, that’s still not as helpful as knowing exactly where in your code 'enabled is written. By “exactly where”, I mean outputting a range of characters in the user’s source code, which is often rendered as an underline in an IDE. Your Racket example does include similar output with /tmp/c.rkt:4.26 in its last line, but this points to the contract that failed (library code), not to the code that broke the contract (the user’s code).

                                  In my previous comment, I showed why I thought the article was correct by explaining the above three ways that static type errors can give more relevant information than dynamic type errors.

                                  Regarding your second example, being able to assert things about run-time types can indeed catch errors that can’t be caught with static typing. I agree that this can be a useful feature. However, there’s no technical barrier to a statically-typed language supporting runtime-checked contracts as well. Assertions can usually be implemented as a library that throws an exception or returns an error type.

                                  I would guess that statically typed languages are less likely to have support for contracts in their standard libraries, due to static types covering some of their use cases. I acknowledge that this could be seen as a bad thing about statically typed languages if you want an ecosystem of programs that often make use of run-time contracts.

                            1. 1

                              My initial solution, written in 11 minutes with the help of online documentation:

                              (vec (map
                                     (fn [run] (conj '() (count run) (first run)))
                                     (partition-by identity input)))
                              

                              The hard part was discovering the partition-by function. Knowing about Ruby’s Enumerable#partition method helped a lot with that.

                              After reading some other answers, I decided I should not accept my hacky conj, and should look up the actual way to construct a list. My final solution:

                              (vec (map
                                     (fn [run] (list (first run) (count run)))
                                     (partition-by identity input)))
                              

                              I was testing with ClojureScript, so first was enough to get a one-character string like "a". With Clojure on JVM, it is indeed necessary to use (comp str first) instead, as the post does.

                              I used vec and list because the original question specified the output using that syntax: [("a", 4), ("b", 3), ("c", 2), ("a", 1)]. When I look at the question more, though, I think that data structure was meant to be Python, so my vec was unnecessary.

                              1. 3

                                One of the things this video explains is how to configure less as your pager. The next thing I would suggest trying is setting up delta as your Git pager. It adds syntax highlighting to your diffs, then passes the formatted diff on to your $PAGER. You’re still using less, but any diffs you’re looking at are a little more readable.

                                You may want to change Delta’s configuration. I use --color-only. I find that without that flag, Delta’s reformatted filenames blend in too much with code around them.

                                1. 1

                                  Thanks for the suggestion! That’s a handy tool.

                                1. 3

                                  By coincidence, I read this right after reading The Framley Examiner (example page). It felt surreal, like The Framley Examiner’s writing style was so crazy it had infected the whole internet.

                                  Which is not to say I enjoyed this article. The article seems to hint a lot of things, but as far as I can tell, it’s just reminding you with obscure terminology that you’re living real life right now, not just rehearsing for it. Well, I already knew that.

                                  1. 1

                                    Is this eatmydata?

                                    1. 3

                                      This article is about NoFS, a filesystem, not eatmydata, a command-line tool. Perhaps you meant to ask whether NoFS allows one to call programs via eatmydata without an increased risk of data loss.

                                    1. 1

                                      I am posting my simillar query here ( because i am not able to make it as post) Is there any open source solution for sharing TOTP, HOTP (Multifactor Auth Systems) across team for accounts?

                                      1. 1

                                        KeePassXC can save TOTP secrets, not just passwords, in its database file. You could put that database file in a shared folder (e.g. OneDrive or Dropbox) to allow all team members to access or change it.

                                      1. 7

                                        It seems to me that the CARE (Code Aspires to Resemble Explanation) idea is fine, but I’m not seeing how DRY has anything to do with what is going on here.

                                        Here’s some smells that might indicate code could be more CAREful: … The existence of comments explaining what is happening, suggesting the code doesn’t explain itself well.

                                        I wince when I read advice like this these days. I suspect this is because I’ve always seen it come out of examples that are like something you would find in an introductory programming textbook. A lot of the time having a “what” comment is incredibly useful, as long as it’s not an obvious repeat of the code itself. This is, of course, not very practical advice. That’s why I can’t say the author’s advice is wrong (it’s not), but I do think it’s overly simplistic.

                                        I guess I’m just reacting to the simplicity of it, and my experience in seeing it misapplied.

                                        1. 4

                                          but I’m not seeing how DRY has anything to do with what is going on here.

                                          Actually I do believe this is relevant. Blindly following DRY instead of thinking about how this helps structure code to support its narrative is more easily avoided if you follow CARE as an overarching principle.

                                          Take the example of going to extreme lengths (crossing multiple namespaces or providing a global interface just for this purpose) to link to a library that is otherwise never used in an isolated part of your code, just because you want ro re-use a simple method it contains.

                                          This might not be such a great idea, and CARE hints at why: it would make the part much harder to explain. Instead of just saying ‘this part takes the time and deterministically outputs the current positions of all moving objects’, you’d have to add ‘AND it refers to the math library from the financial module from the in-app purchasing module because that already contained a sum method’.

                                          1. 1

                                            It seems to me that the CARE (Code Aspires to Resemble Explanation) idea is fine, but I’m not seeing how DRY has anything to do with what is going on here.

                                            This is good feedback, thank you! To expand a bit about how I see the relation with DRY: I think of both DRY and CARE as examples of heuristics I can use to help improve a bit of code. DRY will drive me to trigger on duplication and stamp it out. CARE invites me to consider whether the code looks like the explanation I would give of it. I think code will come to look pretty different depending on which heuristic I apply.

                                            A lot of the time having a “what” comment is incredibly useful, as long as it’s not an obvious repeat of the code itself.

                                            I do believe there’s situations where “what” comments can be useful. One that’s top of my mind is when performance requirements require me to compromise a bit on code legibility. I don’t believe that performance-optimized code would turn out particularly CAREful, but with good reason.

                                            I’m curious, were you also thinking of particular types of situations where you feel “what” comments are particularly useful?

                                            1. 5

                                              I’m curious, were you also thinking of particular types of situations where you feel “what” comments are particularly useful?

                                              Here’s one of my favorite examples:

                                              b=( "${a[@]}" ) # copy array
                                              

                                              That’s the shortest correct way to copy an array in bash. If you use bash a lot you’ll probably memorize it, but if you’re touching bash once every couple months then the comment will save you a lot of pain.

                                              1. 4

                                                This is the kind of comment (or sometimes documentation) that I often see added during code review when the reviewer isn’t familiar with the library/language/etc. and requests it. It is not usually some subtlety, and when the reader becomes more familiar they don’t tend to ask for it in the future. It rubs me the wrong way because it is usually addressing a different “audience” than the rest of the comments, generally the point of writing this program is not to teach the next person who reads this about X, and the program that ends up with the comment explaining X ends up being arbitrary, as does the particular X that happens to trip somebody up this time.

                                                This particular instance is kind of compelling, but I wonder if that’s just because I don’t write enough bash, and I get the impression you add this comment consistently which maybe changes things.

                                                1. 5

                                                  Most code can and should assume the reader is familiar with the language in use, but in the case of code written in a language that’s rare-within-the-codebase (a role which eg bash & make often fill), I don’t think that’s a good assumption.

                                                  1. 2

                                                    I agree with your misgivings, but on a team using multiple languages, with developers of varying experience and familiarity with each, you’re better off anticipating likely pitfalls and steering people away from them with over-explanation, or just saving them googling time, than saying “well, an X programmer should know this, and if you don’t, it’s on you” – even if the latter is true.

                                                    1. 1

                                                      it’s on you

                                                      To be clear I’m happy to explain in say the discussion/email etc., it’s just immortalizing that explanation in the source that tends to put me off.

                                                      1. 1

                                                        Sure, I didn’t mean suggest you were being dickish. The problem is on a large code base at a big company, with people working in multiple time zones, you won’t always be around, eventually you’ll leave or move to a new team, etc, etc. Again, I agree there is something ugly about it – a better long term solution imo to document the feature set of the language everyone is expected is to know, and invest in training – but that’s a lot of work, and if it’s not going to happen comments are a decent mitigation.

                                                  2. 2

                                                    b=( “${a[@]}” ) # copy array

                                                    This comment would help me a lot as I’m not too familiar with Bash myself.

                                                    In the post I describe a “what comment” as a smell that might indicate code isn’t particularly CAREful, and I do feel that applies to this example. Specifically the word “copy” is essential to an explanation of the code but doesn’t appear in the code itself. I think it might just be harder to write CAREful code in some languages than in others.

                                                    That said, I wonder how you’d feel about these alternatives to the comment:

                                                    • Extract the copying logic into a bash function called copy_array. If that’s possible. I know Bash has functions but am not familiar enough to know for sure we could use them in this situation.
                                                    • Rename variable b to copy_of_a.
                                                    1. 5

                                                      Option 1 is basically not possible in bash (functions don’t “return” values) unless you use a nameref which will be far worse than the comment and not supported in all bash versions anyway.

                                                      copy_of_a might be a good alternative but not always, since sometimes it won’t semantically describe the new variable clearly (ie, it describes how you produced the new variable but not the meaning of that copy in the narrative of your code, thus violating CARE)

                                                  3. 3

                                                    I’m curious, were you also thinking of particular types of situations where you feel “what” comments are particularly useful?

                                                    Any time a name is ambiguous or reading the code would take much longer than reading the comment. Of course, both of these things can (and usually should) be considered code smells, but any time you aren’t able to find a perfect name, or make the code completely crisp, a short comment that will save a future developer reading time is usually a better alternative than blindly following “don’t comment what.” The master rule is: If I were coming to this for the first time, would the comment make my experience better or worse?

                                                    1. 2

                                                      Don’t forget about the costs of a comment beyond the time spent reading it when someone first encounters that code.

                                                      At some point the commented code might change. If the developer then remembers to update the comment too, it will cost them only a little time. But if they don’t update it, the comment will cost future readers a lot of time as they recover from being misled by a comment that doesn’t match the behavior of the code.

                                                      1. 1

                                                        Agreed. The cost/benefit is a judgment call and prediction based on the likely needs and probable mistakes of future readers. Also a good argument for clarity and brevity when you do make comments.

                                                    2. 2

                                                      I’m curious, were you also thinking of particular types of situations where you feel “what” comments are particularly useful?

                                                      In codebases like GCC. Here’s an example in the integrated register allocator. It’s code I had to work through recently. Stuff like the comment on line 3811 are incredibly useful when you’re reading through. It’s code that you have to read to understand the workings of other parts of the code (and probably aren’t directly related), but it’s something you will rarely have to touch. Having comments that guide you through the steps is a godsend.

                                                      The obvious retort here is to refactor so that it’s clearer, but that is very unwise. For one thing, the data structures would have to be redone because they are multi-purpose and meant to be generic (otherwise you’d have so many alises or copies it would be more confusing). Another is the sheer legacy to be overcome. And then there is the testing. This kind of code is really tricky to get right, and messing with it can be an awful lot of work.

                                                  1. 7

                                                    Quicksilver is another open source launcher for macOS. What does this project aim to do differently?

                                                    1. 2

                                                      Hmm, I hadn’t heard about this project before. Thanks for the link.

                                                      It turns out that there is only one difference between it and spotter - spotter is a cross-platform application which will be released also on windows.

                                                      1. 6

                                                        Quicksilver was the app that inspired Alfred, LaunchBar, Gnome-Do, and I think much of the “launcher” market.

                                                        It was a fantastic app in its heyday, but unfortunately lost some of it’s quality as macOS progressed and it didn’t quite keep up. It also depended on compiled, typically Objective-C, plugins, which is not how most newer plugin systems are working now, with Node, Python, Lua, etc, being more typical.

                                                        1. 4

                                                          I remember using LaunchBar in the Mac OS 7 days (mid-1990s). It well pre-dates Quicksilver.

                                                          1. 1

                                                            Apologies, I didn’t know that! Thanks!

                                                        2. 3

                                                          Another open source thing like Alfred is Albert, might be worth checking out for further inspiration.

                                                          1. 2

                                                            Great app, but looks ugly tbh

                                                        3. 2

                                                          I’ve been using Quicksilver for the past 15 years, and I just can’t switch to anything else. I might not be using it’s full potential, but for quickly starting an app or getting me contacts/calculations/files, it’s invaluable.

                                                          1. 2

                                                            Man, I had no idea Quicksilver was still alive and kicking. I seem to remember it being dead awhile back, which is when I switched to Alfred.

                                                          1. 3

                                                            I expected Elixir for web, but for MCU IoT it was a surprise to me. Give a try to Nerves with your Raspberry PI.

                                                            1. 2

                                                              I had to look this acronym up: MCU = microcontroller unit

                                                              1. 1

                                                                Sorry. Correct (with Raspberry) is SBC = single-board computer. My fault. Thank you

                                                                1. 2

                                                                  It looks like there’s a project to run Erlang and Elixir on some MCUs as well: GRiSP.

                                                            1. 2

                                                              True, for a given task there are generally multiple tools that could get the job done. But don’t take that idea too far: sometimes your dev environment, like a leaky abstraction, does matter to the user. Some reasons this can happen:

                                                              • Time to write. The time it takes to you write software can change depending on the environment. This affects what users see because they will never see a feature you don’t have time to to write. For example, if your app shows some handy statistics, your users won’t care whether they were generated by Python or Ruby, but they certainly would care if the reason you bothered to implement those statistics was the availability of the NumPy library for Python.
                                                              • Performance. Many users complain about apps whose dev environment included Electron, because those apps generally take up more disk space and memory. Similarly, it’s better that git status is implemented with C than if it were implemented with Java, because the JVM’s startup time would make it impractical to include a Git status in a shell prompt.
                                                              • Supported platforms. Writing a game might take a similar amount of effort whether you write it with LÖVE or Godot… but if you choose LÖVE, the resulting game will not run in web browsers, limiting your audience to some extent.
                                                              1. 6

                                                                This technique, temporarily banning vague words to avoid miscommunication, is also known as tabooing your words. Less Wrong has many posts on the technique.

                                                                1. 1

                                                                  Nowhere in the article or on that website is “BPF” defined. I found this page with a definition: Linux Journal – BPF For Observability: Getting Started Quickly.

                                                                  BPF is a verified-to-be-safe, fast to switch-to, mechanism, for running code in Linux kernel space to react to events such as function calls, function returns, and trace points in kernel or user space.

                                                                  According to that page, BPF was originally an acronym for Berkeley Packet Filter, but is now the whole name of the technology.

                                                                  1. 8

                                                                    Was excited about the project and then saw this. When are we going to stop abusing the name open source? If it’s not an OSI approved license, it’s not OSS in its true essence. /end-rant.

                                                                    1. 6

                                                                      I agree that it was misleading of the original poster to mention “open source” in their post while not mentioning that Meli’s license is the Business Source License, which is not an open source license (as the license itself proclaims).

                                                                      However, I don’t think “OSI-approved” is the ideal criterion for open source software. To give a counter-example, I think that the non-OSI-approved Blue Oak Model License is as much open source “in its true essence” as the OSI-approved MIT License is. For more examples of “OSI-approved” falling short as a standard, see the blog post Don’t Rely on OSI Approval, written by one of the lawyers who wrote the Blue Oak Model License.

                                                                      1. 2

                                                                        While I agree with you that OSI-Approved isn’t a “standard” or a definitive list, however I am yet to see a legal precedent of Blue Oak Model License or similar licenses standing in courts.

                                                                      2. 6

                                                                        I don’t think the abuse is using an unapproved license. The abuse is that the license doesn’t meet the criteria for open source distribution. Approval is useful for other reasons but not necessary to meet the definition.

                                                                        I don’t think this license is bad. It certainly won’t stop me from considering usage of this tool.

                                                                        But IMO they should choose a different term (“source available”? “shared source”? “will be open source 4 years from now”?) to use when promoting the project.

                                                                        Calling it “Open Source” makes people believe distribution meets the OSD conditions and this says very plainly in the license text that it doesn’t:

                                                                        The Business Source License (this document, or the “License”) is not an Open Source license.

                                                                        So it’s easy to understand your disappointment after seeing it promoted as Open Source.

                                                                      1. 3

                                                                        Adding preferences and config options have costs that this post doesn’t acknowledge. The blog post “Choosing our Preferences”, from 2002, explains those costs from the perspective of a GNOME developer. Someone else’s blog post “The GNOME Way”, from 2017, summarizes it thus:

                                                                        The key lesson: preferences have a cost. A usability cost, an engineering cost, a QA cost. They result in software that isn’t inclusive. They decrease the engineering quality of the software. They put responsibility for the experience in the user’s hands, whether they want it or not.

                                                                        This is not an argument for never including options, but it is an argument for being careful about which options are supported.