1. 31

    Oh boy, I have a lot of feelings about this. Good on the author for bringing it up.

    Junior developers (having been one) are amazing to have around and, if handled properly, are a major force multiplier.

    Personally observed benefits of junior devs:

    • They are hungry. They are looking to get that paycheck, no matter how small it is compared to a senior developer, and since they’re often hourly they’ll actively look for additional work to do if managed properly to pad out beer money or rent or childcare or family care or whatever. Senior devs begin playing a game (if they’re smart) of “I am salaried…how can I exert minimum effort for maximum possible revenue?” Senior devs also know themselves better, and so they can often say “Yeah, $X is enough, I don’t see the personal upside in taking on more work even with a pecuniary benefit”.
    • They don’t know what is hard and what isn’t. They are juniors, and so they attack tasks (architectural and scutwork) with near equal optimism. You can give them something that’s impossible and they’ll come back with solutions that actually are good-enough fudges for business purposes.
    • They want to learn. The only way to become a senior developer is by learning things, and a lot of junior devs have a chip on their shoulder (acknowledged or not) about not knowing enough–so, they’ll go do new things and learn about them and try to show off that learning. Senior devs often go with tried-and-true knowledge because they know how to execute most quickly with it; a junior dev can help uncover better solutions that would be ignored otherwise.
    • They might know things you don’t. Hell, I learned React in from an excellent junior dev.
    • They’ll stick around longer. Similar to being hungry, the friction for a junior dev to switch companies is higher (they underestimate their own knowledge and value, remember?) than for a senior dev. So, if you display even marginal competence and compassion towards them, they probably won’t jump ship. Also, their pay scale starts so much lower so that you can keep giving real raises without worrying about breaking the bank.

    However, there are severe pathologies to junior devs:

    • They suffer extra from morale-stressing situations (modulo life experience). A junior dev can get stuck in a project or stuck with a bad situation and really just ground down by it, where in the same place a senior might go “well, this sucks, but we can see it through”. They haven’t had a lot of history of failed and successful projects, so they can take things too hard.
    • They love learning new things, and want to try them out all the time. Until trained properly, junior devs have very little conservatism in their engineering. They’ll switch from Backbone to Angular to React because they’re learning new and exciting things–even if the original domain just needed a static server-side page.
    • They are really bad at software estimates. Like, even moreso than normal, because they lack the breadth of experience to know what paths in a project are probably most filled with spiders and which ones are tedious but quick.
    • They are bad at managing others. Juniors are just barely getting their own career and projects in order, and usually lack the technical, political, and engineering proficiency to organize and communicate effectively with others in a leadership role. This does not mean they shouldn’t (with careful and direct supervision) be forced into it–after all, that’s how they learn!
    • Modulo life experience, they focus on tech more than customers. Due to their desire for knowledge and improvement, they often miss the essential chatting with customers/users of a software project that can pull out hidden requirements or even allow for shipping partially complete work.
    • They can make a huge mess. Given credentials to production system, or given large foundational architecture work, juniors can do bizarrely well-intentioned things that result in total chaos. Seniors can (and do!) have the same problems, but they’re usually more likely to ask for help or exercise caution.
    • Modulo life experience, they don’t understand themselves. Juniors have a hard time spotting when they’re getting overloaded or burned out, and they have a hard time figuring out why they feel a certain way about technical and interpersonal conflicts. This results in communication problems, chaos, and general bad vibes until addressed.
    • They will dutifully reproduce the dev practices around them. So, if all of the example code for solving something does weird shit, juniors will dutifully continue doing weird shit. If the build process is crackheaded and error-prone, the juniors will dutifully keep running it and running into problems and, as noted above, probably continue creating problems. And they’ll teach other more-junior devs to do the same!

    I’ve got thoughts on the care and feeding of junior devs, but this post is already rather long.

    1. 4

      Thanks for sharing this, you’ve crystallized a lot of my own thoughts on junior devs excellently. I taught at a bootcamp for a while, and my favorite thing about new dev you summed up as, “They don’t know what is hard and what isn’t.” It was so cool to see these fresh students attack problems that I would have immediately dismissed simply because they didn’t know how hard it was. I think this is an excellent lesson for senior devs as well, a kind of “beginner’s mind” that’s hard to obtain.

      I think any project is like this: if you knew how tough it would be at the end, you probably wouldn’t have started it. Our ability to over- and under- estimate can sometimes be a huge boon.

      1. 3

        If you get the urge to write about the care and feeding of junior devs, I would be interested in reading it.

        1. 2

          It’s not totally independent of the items you’ve listed, but one thing I’ve noticed about juniors is that they also don’t stop to think whether the things they build upon are designed to be taken to scale. So with juniors around, it can be dangerous to say “OK, let’s embrace the fact that we have 5-10 of these things currently, so we’ll do something quick that relies on this fact, and we’ll switch to something more sensible when we need to scale in this direction.”. The moment you look away, you’ll find that a junior has written a script to auto-generate thousands of those things and built an entire structure around it without questioning whether the rest of the system was ready for it (however obvious that might seem to you).

          I think the broader point here is that juniors are much more susceptible to tunnel vision, where they only focus on what they’re trying to solve at a given moment without considering the big picture.

        1. 2

          Maybe another way to think about this is “Can I not do FP in my language?”. Yes for JavaScript and Scala and Rust - you can write procedural code to your heart’s content in these languages, even if JavaScript gives you the tools to use functional abstractions and Scala and Rust actively encourage them. No for Haskell and Elm - there’s no way to write code that looks imperative in these langauges.

          1. 9

            No for Haskell and Elm - there’s no way to write code that looks imperative in these langauges.

            main = do
              putStrLn "What is your name?"
              name <- getStr
              putStrLn $ "Hello, " ++ name
            
            1. 5

              No for Haskell and Elm - there’s no way to write code that looks imperative in these langauges.

              What do you mean by “looks imperative”? Doing everything inside the IO monad is not much different from writing a program in an imperative language.

              1. 2

                You mean StateT and IO. And then learning how to use both.

              2. 3

                Writing Haskell at my day job, I’ve seen my fair share of Fortran written in it. The language is expressive enough to host any design pathology you throw at it. No language will save you from yourself.

              1. 9

                Okay, sure. But does that really mean that every language would be better off with monads? From what I’ve seen, buying into monads can strew code with long, confusing type signatures and higher-order functions (e.g., flip, liftM) that leave the code more cluttered and removed from its writers’ intentions than the ad hoc solutions do.

                Every approach to programming touts the pretty examples its creators thought up while it was being designed, but I believe the true test of such approaches is how ugly and unreadable they get at their worst. Learn Rust from scratch and write a basic program that does more than implement a basic calculator in the first week if you want to prove me wrong. You’ll run headlong into the type system before you know it.*

                Now, given that many of the people who clicked through to this thread have probably bought into monads for long enough that they’ve gotten used to them, I’m probably going to get slaughtered. However, even if you are planning to downvote me and write a point-by-point rebuttal about how you had a dandy time with monads/Rust/etc., I hope you understand that I’m not saying that monads and the like don’t fix the problems they set out to fix. In fact, I’m not even saying that they don’t solve those problems well. I’m just saying that any attempt to create a system that abstracts over different types of code will inevitably restrain the programmer themselves, and this can often force them to write more of their code for the sake of the language than for the functionality of the program itself.

                Replacing excessive boilerplate with excessive abstractions is jumping out of the frying pan and into the fire. It’s not the job of a good programming language to avoid boilerplate at all costs, but rather to keep the programmer focused on describing the actual behavior of their program; this precludes both boilerplate and abstractions when they are in excess. We must not let the problems we encounter most often while writing code induce us to implement solutions that create unavoidable barriers to entry as applications scale, especially not for what I think is otherwise some of the most innovative, pragmatic, and forward-thinking work in the field of programming languages today.

                *This is something the Rust developers are aware of and actively working on, but that just gives you an idea of how far into development language designers can get before they realize they’ve created something that only the most patient, intelligent, and experienced developers can wrangle.

                1. 11

                  The issue I’ve been noticing is that weaker versions of monads are making it into languages, like Kotlin and Swift which have this ? version of bind. So they have recognized that there is value in the abstraction but only offer the programmer a specialization. But this is a problem because this style of controlling sequencing opens up a lot of doors. For example, while everyone loves to talk about the Maybe monad, that’s actually so 5 years ago. I use the result or Either monad almost exclusively over Maybe. I want to be able to encode the error that happened so I can give the user a more valuable response than “something bad happened”. I use Ocaml and, while not as powerful as Haskell in this regard, I can just switch over to the result monad and get the same pretty code that I had with the Maybe monad (option in Ocaml). You can’t do that in Swift or Kotlin. I’m sure you could hack something in there but in Ocaml and Haskell it’s not a hack, it’s equally elegant no matter what monad you want to use.

                  For Ocaml, since we don’t have type classes, you explicitly pick the monad you want to use in a function so the function type doesn’t change but the implementation does. I think the functions I use the result monad on would be significantly harder to understand without being to redefine the sequencing operator so it is a net win.

                  1. 4

                    Having very little experience with monads and the likes, I believe the goal is to use monads as an abstraction over the lower-level elements in the language, like checking for null values.

                    For example, I’d argue that it’s more obvious what this block of code does:

                    do
                      a <- getData
                      b <- getMoreData a
                      c <- getMoreData b
                      d <- getEvenMoreData a c
                      print d
                    

                    which is print the value of d, compared to this:

                    var a = getData();
                    if (a != null) {
                      var b = getMoreData(a);
                      if (b != null) {
                         var c = getMoreData(b);
                         if (c != null) {
                            var d = getEvenMoreData(a, c)
                            if (d != null) {
                              print(d);
                            }
                         }
                      }
                    }
                    

                    which might print the value of d based on a number of conditions that need to happen at the same time (and we don’t even have the else branches shown which would make the code even more cluttered!). It’s also a lot easier to reason about the code that’s based on the usage of the Maybe monad, at least in my opinion.

                    Otherwise, I do agree with the point that, at the end of the day we do ship features, not monads.

                    1. 7

                      I don’t think that imperative code is a reasonable point of comparison (which is my biggest criticism of the OP). It’s seemingly trying to play on the fact that a bunch of nested conditionals is really bad and complicated—which I agree with—but I almost never write code like that in imperative languages. Instead, I’d use early returns:

                      var a = getData();
                      if (a == null) {
                        return null;
                      }
                      
                      var b = getMoreData(a);
                      if (b == null) {
                        return null;
                      }
                      
                      var c = getMoreData(b);
                      if (c == null) {
                        return null;
                      }
                      
                      var d = getEvenMoreData(a, c)
                      if (d == null) {
                        return null;
                      }
                      
                      print(d);
                      

                      I’m not saying this is better than the monadic approach, but it certainly offends me a lot less than nesting everything.

                      1. 4

                        Yeah, the nested example was a bit intellectually dishonest in that case. This is what Go opts for instead, and just avoids nesting for callbacks entirely due to co-routines.

                        It is still pretty verbose, but it is simple for everyone to understand.

                        1. 1

                          I see early return as another ad-hoc solution to that case. A priori I wouldn’t necessarily expect a language to have it.

                          1. 1

                            I think it’s reasonable to expect any imperative language to allow you to return a value as soon as you know what you’d like to return.

                      2. 4

                        I definitely agree with you more than I disagree with you. This is why I’m not a fan of the idea of adding monads to Rust, and why I like our hack for error handling. (Although it’s not clear that monads in the general case would work well in Rust anyway.)

                        For example, I rarely write (or need/want) supremely generic code. Adding a type parameter to a type is a big deal and needs to be managed with care. Most uses of generics in Rust I find myself using are things like “give me any argument that can be converted to a file path” or “give me any argument that can be converted into an iterator that yields strings.”

                        With that said, I haven’t seen much Rust code that elevates to the level of genericism that you see in languages like Haskell, and I generally consider that to be a good thing.

                        1. 6

                          This is why I’m not a fan of the idea of adding monads to Rust

                          What do you mean when you say this? Monads aren’t a language feature, per se, but they are the combination of a few laws. You can express monads in a lot of ways even if the language has no concept of them. The Future’s library I saw for Rust had a bunch of and_then combinators which were basically monadic. Ocaml doesn’t “have monads” but you can define an operator called bind or >>= and implement the rules. It happens that Ocaml has a fairly pleasant way to express that which makes working with them not-terrible but that has nothing to do with monads. So I can do monads in Ocaml but they aren’t a language feature.

                          1. 5

                            When I say “monads” I mean “the ability to write code that is generic over any monad.” (Which I gather is consistent with how the OP thinks of monads too.)

                            1. 2

                              You can implement them in almost anything, but I agree with this article that to have the usefulness they have in Haskell the language needs to: “1. Support ML-style function-fu (trivial currying, single namespace). 2. Have type classes. 3. Allow polymorphism on return types.” (The linked article is about why they haven’t caught on in Common Lisp, despite being implementable.)

                          2. 4

                            Every approach to programming touts the pretty examples its creators thought up while it was being designed, but I believe the true test of such approaches is how ugly and unreadable they get at their worst.

                            Funny, this is exactly why I think monads are necessary. The ad-hoc solutions are more readable solutions to those specific cases - async/await allows a more natural/friendly way of doing async than using Futures and general-purpose monad operations, ?.-style operators are a more natural/friendly way of doing early return than using Options and general-purpose monad operations. Even in a language that does have monads, the ad-hoc solutions are valuable sugar. But when you want to do something the language creator didn’t think of, if you don’t have general-purpose monads you’re stuffed.

                            I’m just saying that any attempt to create a system that abstracts over different types of code will inevitably restrain the programmer themselves, and this can often force them to write more of their code for the sake of the language than for the functionality of the program itself.

                            I understand that’s what you’re saying. I still think you’re wrong. The only things the abstraction restrains you from doing is the things that were wrong, and the wrongness will always bite you sooner or later. I’ve written plenty of law-breaking typeclass instances out of a sense of pragmatism and I’ve always come to regret it.

                            Replacing excessive boilerplate with excessive abstractions is jumping out of the frying pan and into the fire. It’s not the job of a good programming language to avoid boilerplate at all costs, but rather to keep the programmer focused on describing the actual behavior of their program; this precludes both boilerplate and abstractions when they are in excess.

                            I suspect you’re saying this because of experience with bad abstractions. Good abstractions are zero-overhead, or at least O(1) overhead: you learn them once and can benefit from them your whole career.

                            We must not let the problems we encounter most often while writing code induce us to implement solutions that create unavoidable barriers to entry as applications scale

                            That’s exactly what implementing only the ad-hoc solutions does. When applications scale is precisely when you need the ability to define your own custom monads and reuse generic functions with them.

                            1. 1

                              Even in a language that does have monads, the ad-hoc solutions are valuable sugar. But when you want to do something the language creator didn’t think of, if you don’t have general-purpose monads you’re stuffed.

                              So clearly there’s a tradeoff between flexibility and simplicity. But given the complex systems to which monads lend themselves, that flexibility won’t benefit most people.

                              The only things the abstraction restrains you from doing is the things that were wrong, and the wrongness will always bite you sooner or later.

                              The abstraction may prevent you from doing things wrong, but you’ll never do things right if you can’t wrap your head around it.

                              I suspect you’re saying this because of experience with bad abstractions. Good abstractions are zero-overhead, or at least O(1) overhead: you learn them once and can benefit from them your whole career.

                              I was referring to cognitive, not computational, overhead. Low computational overhead; high cognitive overhead. (And by the way, even the best abstractions can leak.)

                              We must not let the problems we encounter most often while writing code induce us to implement solutions that create unavoidable barriers to entry as applications scale.

                              That’s exactly what implementing only the ad-hoc solutions does. When applications scale is precisely when you need the ability to define your own custom monads and reuse generic functions with them.

                              The key phrase here is “barriers to entry”. A scaling application necessitates a simple, not a flexible, interface. Writing more “low-level” code is less work than writing less “high-level” code. You shouldn’t have to work around the interface in any application; all the more so for one that is scaling.

                              1. 2

                                So clearly there’s a tradeoff between flexibility and simplicity.

                                No, not at all. ?. or await implemented as a native language operation is no simpler than ?. or await implemented as a monad. Indeed using a monad makes it harder to overcomplicate it with special cases (e.g. Java’s Option would never have made the mistake of erroring on null if they’d implemented it in a “monad-first” way).

                                given the complex systems to which monads lend themselves, that flexibility won’t benefit most people.

                                If a user is happy using ?. and await and understands how they work, it makes no difference to them whether there’s an underlying abstraction that can be generalised or not. The flexibility can wait for them until they need it, and if they never get to the point of solving a problem so complex that they need that power then good for them.

                                In practice, back when I worked in Java every nontrivial codebase ended up needing a bunch of annotations/reflection/agents that were always a disproportionate source of bugs - not because developers were stupid but because they needed to do something the language couldn’t, so they had to step outside the language. In a language with monads that wouldn’t have happened.

                                I was referring to cognitive, not computational, overhead.

                                So was I. Good abstractions save you cognition; instead of having to understand the particular sequencing rules for this new kind of context, you just know it’s a monad and can think about it as such.

                                And by the way, even the best abstractions can leak.

                                No, this is a myth, and in fact monads are a good example; they don’t leak.

                                A scaling application necessitates a simple, not a flexible, interface.

                                The two dovetail, and the monad interface is remarkably simple.

                                Writing more “low-level” code is less work than writing less “high-level” code.

                                Maybe on the initial write, but code is read more than it’s written, so the high-level approach pays dividends for maintainability. Sometimes I’ll write code out longhand to start with and then realise I can simplify it by using State or Writer or some such.

                                You shouldn’t have to work around the interface in any application; all the more so for one that is scaling.

                                100% agreed. Monad is the opposite of that though; it’s such an elegant and simple interface that it’s very easy to conform to. (Indeed one sometimes does so accidentally, and only notices that a given type forms a monad once it’s pointed out)

                                1. 1

                                  So clearly there’s a tradeoff between flexibility and simplicity.

                                  No, not at all. ?. or await implemented as a native language operation is no simpler than ?. or await implemented as a monad. Indeed using a monad makes it harder to overcomplicate it with special cases (e.g. Java’s Option would never have made the mistake of erroring on null if they’d implemented it in a “monad-first” way).

                                  A scaling application necessitates a simple, not a flexible, interface.

                                  The two dovetail, and the monad interface is remarkably simple.

                                  We have different understandings of “simplicity”. I argue that having monads be deeply ingrained in a language’s design can actually make things more complicated. It does matter whether there’s an underlying abstraction, because that abstraction will have to be propagated to all dependent code.

                                  Sidenote: I’m not aware of any monadic implementations of ?. and await and would love to see them! I need to do more research on this front.

                                  I was referring to cognitive, not computational, overhead.

                                  So was I. Good abstractions save you cognition; instead of having to understand the particular sequencing rules for this new kind of context, you just know it’s a monad and can think about it as such.

                                  It is pattern recognition, not inbuilt abstraction, that saves cognitive waste. Abstractions are a good learning aid, but nothing need be forced into the language itself in order to make this learning happen. All the foundational precepts of functional programming can be implemented in straight-up C.

                                  And by the way, even the best abstractions can leak.

                                  No, this is a myth, and in fact monads are a good example; they don’t leak.

                                  In general, one shouldn’t get too comfortable with liberal use of abstraction.

                                  Writing more “low-level” code is less work than writing less “high-level” code.

                                  Maybe on the initial write, but code is read more than it’s written, so the high-level approach pays dividends for maintainability. Sometimes I’ll write code out longhand to start with and then realise I can simplify it by using State or Writer or some such.

                                  You shouldn’t have to work around the interface in any application; all the more so for one that is scaling.

                                  100% agreed. Monad is the opposite of that though; it’s such an elegant and simple interface that it’s very easy to conform to. (Indeed one sometimes does so accidentally, and only notices that a given type forms a monad once it’s pointed out)

                                  Again, committing to an abstraction is a decision that mustn’t be taken lightly. Monad is an elegant and simple mathematical notion; implementation is inevitably hairier. That’s not to say OO is any better with respect to implementation of theory, just that no abstraction is perfect in practice.

                            2. 4

                              liftM et al are usually code smell, but they’re usually less obnoxious than the stuff I end up doing without monads, like checking for error codes or null pointers after every function call, or using .then() or whatever if I’m using some hip java(script) framework that emulates the Either or Maybe monad.

                              You can usually get rid of them as well, if you use MTL-style monad transformers. A lot of libraries define things in terms of MonadState, MonadIO, etc. constraints so you don’t ever have to call lift<whatever>. I don’t actually remember the last time I used a lift function besides liftIO, which is used for running an arbitrary IO action inside some arbitrary IO-capable monad.

                              In good monadic code, you stick all the “lift”s and “flip”s and stuff in some file that handles the low-level behavior of your monad, and you can do a really good job of making the “business logic” or whatever you want to call it free of clutter.

                              1. 1

                                In good monadic code, you stick all the “lift”s and “flip”s and stuff in some file that handles the low-level behavior of your monad, and you can do a really good job of making the “business logic” or whatever you want to call it free of clutter.

                                But isn’t that just replacing one form of “low-level” with another? I thought the entire point of monads was to absolve the developer from having to do things the tedious, “low-level” way in the first place; after all, they are a “high-level” construct.

                                1. 1

                                  The difference is that the join between the low level and high level is more continuous. Writing code that works with a State monad and writing code that works with a hidden variable looks very similar, and in both cases you can pretty easily understand what’s going on at the low level or at the high level. But the monad makes it much clearer how the high-level sequencing interacts with the low-level variable manipulation, and you can easily tell how changing one will affect the other.

                                  1. 1

                                    …the monad makes it much clearer…

                                    Whose job is it to make code clear and concise?

                                    As we all know, there’s only so much automated systems can do before they’re out of their depth. Trust me, I’d love to wholeheartedly commit to monads as much as the next guy, but their simplicity comes at the cost of long-term ease of use.

                                    1. 1

                                      It’s also really nice in the sense that how the hidden variable can change is consistent. There is only one bind and return in there and the distinction between what is done and performing it in the monad is clear. In ad-hoc solutions, anything can happen anywhere. So even the nastiest monadic code is significantly more “learnable”, IME, than the nastiest imperative code because one still is constrained on where the nastiness can happen.

                                2. 3

                                  But does that really mean that every language would be better off with monads?

                                  I think this question is meaningless since every Turing-complete language already has monads. Don’t believe me? Monads in C: https://gist.github.com/enobayram/4c9ba6e7723a1622530e56884fc97357

                                  The only thing that makes monads special in Haskell is the do notation, which is a syntactic sugar for monads. without it, the example would look like the following in plain Haskell:

                                  program =
                                    getData             >>= \a ->
                                    getMoreData a       >>= \b ->
                                    getMoreData b       >>= \c ->
                                    getEvenMoreData a c >>= \d ->
                                    print d
                                  

                                  Which is probably better than most other languages.

                                  So the question should be, “should every language have an expressive enough type system to express monads and should it have a flexible enough syntax that monadic code doesn’t look terrible in it?”

                                  1. 3

                                    How would you implement more interesting monads, say, streams and delimited continuations, in C?

                                    1. 3

                                      The procedure is quite simple; whenever you see a type class constraint, replace it with an explicit argument accepting a method dictionary. Whenever you need to express polymorphism, replace it with a void * and hope the user won’t mess up the arguments. If you were serious about this, you’d also make all functions accept an extra void * that carries “user data”, so that you can pass around closures for your functions. You’d also implement some form of garbage collection/some architecture to allow for managing lifetimes. In the end, monads would be barely recognizable, but they would still be there, I mean, you could write a function that works on all monads.

                                      Obviously, monads will also be much harder to use without lambdas, so you’d have to define a lot of top level functions that are called step_1_of_x, but my point isn’t to demonstrate monads are a good way to program in C anyway.

                                      1. 3

                                        I see, you’re looking at things operationally. Of course, any sufficiently powerful language can emulate the mechanics of type class dispatch (or any other implementable language feature).

                                        But, for those of us who care about abstractions (like monads or any other algebraic structure), that is kind of missing the point. The point to using abstractions is to have a clearly defined boundary between implementors and users, so that users don’t need to worry about implementation specifics, and implementors don’t need to worry about users’ concrete use cases. The only shared concern between implementors and users should be the abstraction’s semantics. This, I’m afraid, you can’t easily replicate in C.

                                        1. 1

                                          Yeah, it does degenerate to untyped void * goo when you attempt this in C, but it’s still architecturally the same. You can still express monads in the category of monads. If you were an alien with a flawless mind, you could just as easily express and use your abstractions in C as you would in Haskell.

                                          On a more practical note, you can actually do useful stuff with monads using C++. C++‘s templates are flexible enough to express (something like) typeclass dispatch, and in some ways you can even go beyond Haskell, since you have a tight control over what gets statically specialized. You could, for instance, have deep monad transformer stacks that get compiled down to overhead-free assembly. I’m not saying you should do that, but thinking “C++ doesn’t have monads” will unnecessarily narrow your vision.

                                          1. 2

                                            you have a tight control over what gets statically specialized

                                            It’s not clear to me whether you are talking about the fact templates are instantiated at compile time or the fact templates can be specialized, but in either case you lose expressiveness.

                                            • Compile-time instantiation prevents you from having polymorphic recursion (e.g., a Tree<T> containing subtrees of type Tree<List<T>>) or first-class existential quantification (e.g., Java’s infamous wildcards: List<? extends Animal>, although other languages do this more sensibly).

                                            • Template specialization reduces the amount of static analysis that can be carried out in a modular fashion, because, well, templates can be specialized anytime, anywhere. With bona fide parametric polymorphism, you can say “my generic definition is guaranteed to have such and such properties”. With templates, you can only say “assuming nobody else specializes my templates or anything else they depend on in ways that contradict my wishes, the resulting specialized code will have such and such properties”. Assuming nobody will specialize your templates is a very big if.

                                            1. 2

                                              It’s not clear to me whether you are talking about the fact templates are instantiated at compile time…

                                              Yeah, that’s what I meant, but I used the word “specialize” because that’s what haskell uses for something similar to what C++ calls template instantiation. So, in haskell if you have a function f.x a -> [a], you can specialize it for Int -> [Int] with compiler pragmas, and GHC will see it as a possible optimization. In theory this breaks parametricity, since you can easily violate it this way, but you have to be very careful with those pragmas. Which brings us to your second point, in C++, you’re basically always in this “you have to be careful” mode. So, please, for the sake of this discussion forget about how much the compiler helps you avoid shooting yourself in the foot, we’re talking about what can be expressed.

                                              So, for instance, if you have a template in C++, and you’re using it in contexts where all of its specializations need to respect parametricity, you write a comment at the top of its declaration

                                              /* If you intend to specialize this template, please respect parametricity, 
                                               * if you don't know what it is, go func* yourself. (* educate yourself in the 
                                               * ways of functional programming) 
                                               */
                                              

                                              Coming back to your first point, you can very well express polymorphic recursion with C++, if you declare (via comments) List<T> to be parametric, so you can use List<shared_ptr<void *>> to stand for an existential a. You can even wrap this in a type-safe manner within the context of Tree<T>, so, you can for instance define a type-safe Traversible instance for Tree<T>. I would like to implement this for you, but I doubt I’ll find the time to do so anytime soon.

                                    2. 2

                                      So the question should be, “should every language have an expressive enough type system to express monads and should it have a flexible enough syntax that monadic code doesn’t look terrible in it?”

                                      You act as though there aren’t far-reaching consequences within a codebase for initial committal to a monadic interface. Different interfaces are best suited to different applications.

                                      1. 0

                                        I don’t see where you got the impression that there aren’t far-reaching consequences. Monads are too powerful an interface to expose to the library user under most circumstances, and the art of software architecture is to find the balance between the interface consumer and implementer.

                                        The point still stands though, if your language’s type system and syntax isn’t powerful enough to make monads practical, the chances are you’ll have trouble expressing profunctors from your application domain’s category to the category of endofunctors in your programming language (or whatever abstraction it takes to express your architecture)…

                                        1. 1

                                          You act as though there aren’t far-reaching consequences…

                                          I don’t see where you got the impression that there aren’t far-reaching consequences.

                                          I was implying there are far-reaching consequences.

                                          1. 1

                                            Sorry, I meant where you got the impression that I implied there weren’t any.

                                            1. 1

                                              Oh okay. In that case I think we agree 100% 😁

                                              Though I didn’t fully understand this part, and would like to:

                                              …you’ll have trouble expressing profunctors from your application domain’s category to the category of endofunctors in your programming language…

                                              1. 2

                                                I strongly believe that beneath the hot dark crust of functional programming, there’s a pressure buildup of what people might one day call “categorical programming” once it erupts. When the dust settles, people will probably call Conal Eliott’s Compiling to Categories work one of the early milestones. You can already see the early signs of this upcoming paradigm applied to real world problems in the Haskell community.

                                                The part you haven’t understood may or may not be meaningful for a real world application domain, but the point is, you can model the relationships in your domain abstractly as a number of categories and functors between them a la OLOGS, then your software architecture can be reduced to functors from those categories to some categories you construct using your programming language(s) (plural, as in for example, your back-end, database and front-end might all be part of the model, so you have your entire system along with the users and the world around it modelled). These are all big words, but the surprising thing is some of that mumbo-jumbo is directly expressible in Haskell. We’re actually using some of this stuff at my day job, and we intend to write about it when we have the time.

                                                1. 1

                                                  The part you haven’t understood may or may not be meaningful for a real world application domain…

                                                  I sincerely appreciate your saying this. I think the middle ground between our respective positions could be stated in short as follows: “The tenets of FP have amazing application-dependent benefits.”

                                                  When the dust settles, people will probably call Conal Eliott’s Compiling to Categories work one of the early milestones.

                                                  [If] you can model the relationships in your domain abstractly as a number of categories and functors between them a la OLOGS, then your software architecture can be reduced to functors from those categories to some categories you construct using your programming language(s)…

                                                  This all sounds fascinating. Do you know of any interesting papers / talks / blog posts that further what Conal and Spivak & Kent discussed, i.e., preëmpt a move toward real-world application of o-logs to software development?

                                      2. 2

                                        You could say that about every language feature - it’s always possible to greenspun a given feature into a language that doesn’t have it. I think you can draw a line between languages that let you implement useful monad-generic code /in the language/ and languages that don’t.

                                        1. 3

                                          I understand what you mean, but I honestly think it doesn’t apply to monads. do notation is a language feature, but “monad” is a concept from abstract math. C is an extreme example, but you could easily find C++, Java or Python projects that would greatly benefit from expressing some core architectural elements through monads.

                                          1. 2

                                            Monads are a mathematical concept defined in terms of arrows and objects, sure, but the usual sense of “monad” in a programming context comes from identifying those with functions and types, and you can only really say that you have monads “in” the language if you can use them with ordinary functions and types in the language. You can’t really write a monad-generic function in Java because the language won’t let you write the type signature that function should have, and while you technically can work with monads in Python, not having a type checker means you lose most of the benefits. (AIUI this is substantially true in C++ as well; C++ does have type checking but only after template expansion, which makes development of generic code difficult).

                                      3. 2

                                        It seems to me that the problems described in this article are more about syntax than semantics. A good macro system could probably bring the same expressivity benefits as monads in this case.

                                        1. 4

                                          Well, macros can do anything; almost any programming language can be viewed as a named, standardized bundle of macros. I think there’s a lot of value in standardizing on the concept of a monad and a single syntax for it; that allows for reuse both at the syntactic pattern level and for library functions like whileM described above.

                                      1. 0

                                        If you are doing something somebody will pay for, then that means that whatever you are doing is good for that somebody, otherwise why would he pay for it. So the more money you make, the more meaningful your activity is.

                                        So the more money you make, the more meaningful your life is. Don’t trust your brain internal measure of meaningfulness, it was evolved when we were hunter-gatherers and it is incapable of correctly measuring meaningfulness of your activities in the modern world. Trust your bank accounts or crypto-wallets.

                                        Some people think that giving food to random starving children around the world is ‘meaningful’, but it’s not. You are just doing genetic socialism and propping up bad reproductive strategies that are proven to not work. In continuing to propagate the information embedded in the DNA of those starving children, you are actually allowing the bad strategy to be more widely implemented, and thus making the problem you are trying to solve worse. And what does your bank account say? It says you have less money. Brain: 0, Bank account: 1

                                        But that’s just one way of defining ‘meaningful’.

                                        In reality life in inherently meaningless. You have been lucky (or unlucky) to be born into a time and place of plenty that allows you to ask yourself a question with no answer. If you had been born in a pre-industrial farming community, then you only care about surviving the next winter. You have no time for such pointless thought processes as asking yourself what is a ‘meaningful’ life.

                                        You can try reading philosophies but those are just the rambling non-answers of those who came before you who asked the same question.

                                        You are just a robot who was built to replicate information embedded in DNA. You by accident was given a nervous system capable of asking questions like “What is the meaning of life?” and “How do I live a meaningful life?”. Those questions are just syntactically correct enough to convince you that they are meaningful questions, but they are not.

                                        Don’t worry though, sooner or later your children will come home from school and your neural “let’s make sure the children are well so they will propagate my genes” system will fire and you will forget about all these silly questions.

                                        Life is without meaning, and any attempt to find one is just your mind incapable of accepting the fact that you are mortal and small, and wanting to be large and forever.

                                        1. 10

                                          This perspective is vulgar:

                                          Some people think that giving food to random starving children around the world is ‘meaningful’, but it’s not. You are just doing genetic socialism and propping up bad reproductive strategies that are proven to not work.

                                          Social Darwinism is a sickness.

                                          1. -3

                                            Social Darwinism is a sickness.

                                            That is strange, when it is essentially impossible for natural selection to not apply to humans. If an all pervasive and always applicable by definition effect is a sickness, then the word sickness has such weak boundaries on its definition as to render it pointless as a word.

                                            1. 3

                                              What you might call a “sickness” is the tendency to over-simplify important and complex issues in the real world into a few convenient logical predicates and them arrive at serious conclusions, which if taken seriously, would result in actual people actually suffering.

                                              I also once were a robot like you, but then I realized that the real world is many orders of magnitude orders of magnitude more complicated than I could ever hope to analyze or even observe, so I’ve learned to trust my hard-evolved feelings to take care of the complexity, and I only use my logic to choose between the alternatives that feel right relying on the predicates that feel right. As a matter of fact, anything that involves people suffering has a very little chance of feeling right.

                                              1. 0

                                                Does it feel right to chase away a predator in order to save a cute prey?

                                                1. 1

                                                  If I witnessed a wolf chasing a cute rabbit, I’d probably save the rabbit if I had the means. But if I had the means to save all rabbits from being eaten by all predators, I’d definitely not do it since it’d have a terrible impact on the environment. But then, if you came to me and convinced me, through logical arguments, that saving that one rabbit from that wolf will have a significant negative impact on anything I care about, my feelings about the former issue could change and I could let the wolf eat the rabbit.

                                                  Now, hypotheticals aside, there’s no universe in which I could be convinced that children dying from starvation could be the solution to anything. Even if you made very good arguments about why them not dying from starvation would cause something very bad, I’d still try infinitely many ways to find other means of avoiding that very bad thing. But children dying from starvation is off the table. In general, convincing me to support the suffering of people would take far more that some juvenile arguments coming from an extremely simplified and naive interpretation of the very complex phenomenon that is evolution.

                                                  1. 1

                                                    Why is the wolf starving to death preferable to the rabbit being killed by the wolf?

                                                    1. 2

                                                      You don’t get the point, I’m not pushing that wolf to starvation by stopping it from eating that rabbit. It has a whole forest to hunt. If the circumstances were such that me saving that rabbit means certain starvation for that wolf, I’d feel differently about the issue. To save you the trouble, you really should stop wasting your energy trying to come up with simplified dilemmas to draw logical arguments about complicated situations. And that’s actually my whole point. Logic is an illusion, it’s a tool our pathetic brains use to overcome our inability to conceive even a tiny fraction of the world around us.

                                                      1. 1

                                                        Logic is an illusion,

                                                        well if you reject logic, then what tool do I have to argue against you? My feelings?

                                                  2. 1

                                                    Since we’re really talking in metaphor, I wouldn’t just chase it away, I’d kill it. You have failed to understand the role and nature of social interaction. You will be discarded, just as you have discarded others unless you change.

                                                    1. -1

                                                      So it’s okay for predator to starve to death because they are not cute?

                                                      1. 2

                                                        Survival of the cutest my friend.

                                                2. 2

                                                  It’s funny given your ideas on genetics if you were right you’d be the defective one because failing to realize social implications is a pretty obviously material defect. Thank goodness you’re wrong because you’re totally uninformed about modern science. You can improve!

                                              2. 9

                                                I used to engage in this sort of nihilism and it was a sad and depressing way to live, so I sympathise, fellow robot. That’s the trouble with too much logic and not enough context (indeed, how robotic!). Once I learned that my conclusions hinged on blatantly false unexamined assumptions, I was able to shift my views to something more constructive.

                                                Having children doesn’t stop questions about meaning, by the way.

                                                1. 1

                                                  Once I learned that my conclusions hinged on blatantly false unexamined assumptions,

                                                  Now if only you would be so kind as to state those false assumptions and why they are false, I would be enlightened.

                                                  But you chose not to.

                                                  1. 6

                                                    I thought it rather unlikely that you would be enlightened by a stranger on the internet. It was far more likely to result in a pointless argument.

                                                    Anyway, for me there were two primary false assumptions:

                                                    • That it’s all about me - my individual fulfilment, freedom etc. This is plainly against where the human evolutionary path led us - we’re a social animal, not a solitary one. Caring about others is essential to us.
                                                    • That the meaning is to be found somehow. Clearly, the universe just is, as you also point out, so there’s nothing to be found, but that’s beside the point because we have the capacity to make up the meaning. When we have this capacity and the alternatives are so depressing, what’s the point of refusing to make something up?

                                                    Once I got rid of these assumptions, it turned out that contributing to the sustainable future of the human race or ensuring that I personally see a continuation of my family is actually pretty meaningful if I let it be meaningful. Even better, it aligns well with what it means to be a human robot, as you suggested regarding DNA propagation.

                                                2. 4

                                                  You are just doing genetic socialism and propping up bad reproductive strategies that are proven to not work.

                                                  There’s something odd about someone calling themselves libertarian but espousing racial collectivism. Or is your username meant to be ironic or something?

                                                  Life is without meaning, and any attempt to find one is just your mind incapable of accepting the fact that you are mortal and small, and wanting to be large and forever.

                                                  This may be true.

                                                  Don’t worry though, sooner or later your children will come home from school and your neural “let’s make sure the children are well so they will propagate my genes” system will fire and you will forget about all these silly questions.

                                                  This is completely false.

                                                  1. 2

                                                    They aren’t a libertarian just like the nazis weren’t national socialists. It’s just a way for them to spout bullshit and hope naive libertarians will buy in to it without questioning the line of reasoning. While I do have reservations about libertarian ideology, this person is just a classist racist bigot and frankly has no place on lobsters. I’ve yet to see anything they’ve spouted to actually be libertarian anyway.

                                                    1. -1

                                                      There’s something odd about someone calling themselves libertarian but espousing racial collectivism.

                                                      You are clearly projecting here because there’s nothing racial about my comments.

                                                      1. 4

                                                        You claim that starving children are starving because they are genetically inferior.

                                                        1. 6

                                                          This user probably isn’t worth replying to. Expect to be sealioned to hell.

                                                          1. -3

                                                            I never said they are inferior, but that the reproductive strategy embedded within their DNA has proven to fail by the very fact that they are starving.

                                                            You really are projecting.

                                                            1. 10

                                                              I intended to stay out of this but there’s nothing genetic about any of:

                                                              • being born into an unstable, grossly unfair, or failed nation-state.
                                                              • experiencing a famine or a natural disaster.
                                                              • being surrounded by a civil war.
                                                              • having your ethnic group despised and persecuted.
                                                              • not acquiring a useful education when basic needs are unmet.
                                                              • having children when birth control is unavailable or proscribed.
                                                              • being unable to emigrate or prevented from emigrating.

                                                              These are exactly the sorts of situations that produce the kind of human suffering that people respond to with generosity. You might argue that in some cases aid perversely subsidizes and supports corrupt regimes and allows the situations to fester that prevent these people from having a reasonable life longer than if there were no aid and the society/state collapsed (with an even greater degree of short-term misery) but it’s not “embedded within their DNA”.

                                                              Restating OP’s argument, “Fuck them, they’re unlucky. Let them die out of my sight and don’t you help them because they’re undeserving by virtue of being unlucky. Now go tend to your lucky off-spring.”

                                                          2. 2

                                                            Said the horrible racist. Get banned already please.

                                                        2. 2

                                                          Your ideas around genetics are outdated and wrong.

                                                        1. 8

                                                          Single-page-apps are one reason the Web is such a terrible place. They do not belong on the Web.

                                                          I have a few side-projects I’m releasing soon that have zero JavaScript, just to show people that it can still be done. Not only that, it’s faster and more accessible.

                                                          1. 1

                                                            Just to drill down here; so there is no type of application you feel can benefit from spa approach? For example the “one page with many possible views” like an email client? You are saying the best way to view emails in such an app is on page per email, in your estimation?

                                                            1. 2

                                                              If it doesn’t run nicely without JavaScript, it doesn’t belong on the Web. It’s like trying to write a book with oil paint. Use the right medium.

                                                              1. 2

                                                                And how do you back that claim?

                                                                1. 1

                                                                  Have you been on the Internet lately? It’s a wasteland. Our computers have got much faster, but the Web has only got slower and more bloated. This is why.

                                                                  1.  

                                                                    If you see this solely from the performance or accessibility point of view, then yes, the web as it is today is bloated.

                                                                    On the other end, if you see this in term of evolution (what you can do nowadays on the web) then I don’t mind.

                                                                    1.  

                                                                      It’s a devolution, one that you note is at the the expense of performance and accessibility. The Web and JavaScript have set back the field by 20 years.

                                                                2. 1

                                                                  I’m pretty sad to disagree with you on this one.

                                                                  The web solves distribution in a way that no other platform does. If it’s for-profit, the returns are much better when you ‘write a book with oil paint’ instead of trying to convince people to download and install software (see eg patio11’s writeup of doing SAAS vs a native app).

                                                                  It certainly sucks that there’s no better way.

                                                            1. 2

                                                              At around 4:30pm this friday afternoon, before I left work, I’ve decided to improve our scheduler, so that a certain number of activities would be performed over a given time window, so without writing much new code I’ve achieved it with the following pseudocode:

                                                              timePassed now =
                                                              let issueImportantActions = ... -- a possibly very long list of important things to do
                                                                  issueUnimportantActions = ... -- a possibly very long list of less important things to do
                                                                  numOfRecentActions = length $ takeWhile (> now - timeWindow) [everything that ever happened]
                                                               in sequence 
                                                                    $ take (allowedActionsPerWindow - numOfRecentActions)
                                                                    $ filter canDoNow
                                                                    $ issueImportantActions ++ issueUnimportantActions
                                                              

                                                              Got the code to compile and committed it without trying, then left for the weekend on time. I got curious and checked, it works flawlessly on my personal development deployment. Try to see how many places I take advantage of laziness!

                                                              1. 3

                                                                Wow, that must be the worst monad tutorial I’ve seen to this date, and that’s simply because it’s terribly wrong! What he describes has nothing to do with monads in Haskell, and I’ve tried really hard to imagine an interpretation where this is somewhat like a monad, but it’s impossible, simply due to the fact that the monad laws dictate that bind(x, ret) is supposed to be equal to x. The only monad example he gives that sort of satisfies this law is the Lazy monad.

                                                                In any case the following is utter non-sense:

                                                                We can think of bind as a function that takes:
                                                                
                                                                * A value of type B
                                                                * A function that maps items of type A to items of type A 
                                                                … and produces an item of type B.
                                                                

                                                                One could imagine that what he’s describing here could be the fmap operation of a Functor, though it’s quite pointless to talk about things like Functors and Monads without properly defining what category they operate on, especially when the subject is a dynamically typed (i.e. a unityped) language.

                                                                I really am not nitpicking, this tutorial is wrong on so many levels, it would probably do nothing but harm to one’s understanding of monads.

                                                                1. 1

                                                                  This kind of feedback is exactly why I shared it here. The responses on these Monad-related write-ups are all over the place in agreement, disagreement, and alternative links suggested. Eventually, enough rounds of iterating and filtering will get the right set of resources for beginners from various backgrounds. I’ll make a note about this one.

                                                                  Far as the style, how do you link the idea of doing it incrementally building the functionality in a language like Python? Is that feasible or already been done for a monad tutorial whose teachings will actually be useful?

                                                                1. 3

                                                                  Good read, very stirring, rather toxic.

                                                                  EDIT: More than just toxic.

                                                                  1. 3

                                                                    What is toxic about it?

                                                                    1. 12

                                                                      (To make clear: I think it was well written. I myself am a huge fan of writing in the second person. That said, I think this sort of thing is ultimately counterproductive as we find our way.)

                                                                      I think that articles like this, spreading agreeable fiction based on small kernels of truth in the name of cautionary tales, serve to further polarize workers and worsen relations and in general further retard the evolution and equalization of peoples in tech.

                                                                      I don’t particularly care for the portrayal of women (or men, for that matter) in this, I don’t particularly care for the normalization of backchanneling and backbiting and subterfuge, I don’t particularly care for the caricatures of different pathologies of our industry. I particularly do not care for the implication of common issues in engineering (student loans, unfriendly coworkers, the path from contributor to manager, office politics) as somehow being uniquely gendered.

                                                                      Further, I think that this article kinda reinforces the popular simple assumptions about our industry: software startups have infinite funding, that software orgs start at 50 people and go from there, that titles matter at all, that having sufficient diversity can be approximated by a process like farming pokemons, that successful businesses have to have a million daily users or they aren’t worth anything, that startups are somehow competing against each other instead of external apathy and internal incompetence, that women of color in tech must speak weird English and are necessarily steeped in progressive politics–those and a score of odd little throwaway lines here and there that serve to paint the One True Picture of the Valley and attempt to deconstruct/critique it and in so doing erase the lived experience of thousands of workers in healthier (or sicker!) companies in the Valley, in places like Europe or Southeast Asia or Latin America or Africa or even the American Midwest, in smaller companies that are just starting out or in software units of banks or insurance companies or oil & gas or other non-startup businesses.

                                                                      My concern is that things like this further cement a simplified and inaccurate view of ourselves in our own mythology. I say that this is toxic because the things we’re doing and going to do to exorcise this specter are probably going to be also terrible and costly to workers.

                                                                      1. 8

                                                                        If you’ve read the piece and haven’t seen any toxicity, then we must be living in two parallel universes that have touched each other right here in the comments section of this post. To me the post seems like the output from an ML exercise, where they’ve input samples of contempt, snark and narcissism to a text generation system.

                                                                        1. 2

                                                                          What’s not? The author follows up a glowing paragraph about how great X is as a boss with “so why don’t I have your job” It’s like she’s not even self-aware.

                                                                      1. 1

                                                                        This one smells terribly like an artificial arithmetician: http://lesswrong.com/lw/l9/artificial_addition

                                                                        1. 12

                                                                          I don’t understand what the author’s problem with Haskell is, I bet Haskell is more widely used in the industry compared to Rust (I for one am working in a Haskell-first shop). Haskell has recently also gained an impressive momentum to the point that we have a shortage of Haskell talent (despite the influx of new folks) and not Haskell jobs, which was quite the opposite just a couple of years ago.

                                                                          1. 5

                                                                            Your anecdotal experience is directly countered by mine. It is nearly impossible for me to find work doing Haskell.

                                                                            Comparing Haskell to Rust industry usage is comparing items in the bottom % of languages. The relative numbers may be impressive but it says nothing about the likelihood of adoption.

                                                                            1. 3

                                                                              My point is, “why use Haskell as a negative example?”. Haskell is a language that rose to its position purely based on its own merits and not a multi million dollar marketing budget backed by a mega corporation, nor its similarity to a popular language. And it’s also a fairly good position. So I don’t get the author’s point.

                                                                              1. 4

                                                                                Regardless of popularity contest/whatever else, I do agree that I find these kinds of comparisons to be in bad taste.

                                                                                1. 3

                                                                                  Rust would be lucky to become Haskell. It should be aspired to.

                                                                                2. 2

                                                                                  BTW, since it’s relevant to the discussion, I’ll use this opportunity to plug this here… we’re hiring :) https://www.picussecurity.com/careers/backend-developer.html Remote is OK, but we’re a fast growing Turkish company so we can currently probably offer, say, southern-europe kind of a salary. But that’ll probably change soon.

                                                                              1. 2

                                                                                man, sometimes I just feel like wanting to write a much-used npm package, just so that I can delete it and cause chaos. As a non-js dev, and a minimal user JavaScript in general, seeming this always gives me Schadenfreude.

                                                                                1. 1

                                                                                  After left-pad it’s not possible to just remove a popular package, such request needs to go through the support first.

                                                                                  https://docs.npmjs.com/cli/unpublish

                                                                                  1. 4

                                                                                    I don’t understand why it’s possible to delete it in the first place. If you release a piece of code with a permissive enough license you’re accepting the fact that others can keep using that code forever and without any further permission from you. The worst you can do is to stop improving that code. So, why doesn’t npm exercise its right to keep using that piece of code?

                                                                                    1. 3

                                                                                      This is the stance on Rust’s crates.io:

                                                                                      Take care when publishing a crate, because a publish is permanent. The version can never be overwritten, and the code cannot be deleted.

                                                                                      I’m sure crates/cargo will encounter its own issues over time but it’s nice that this at least shouldn’t be one of them.

                                                                                    2. 4
                                                                                      1. write a package and spice it up with non-free and/or patent-encumbered code without license
                                                                                      2. publish on npm
                                                                                      3. wait (or help it) ’till your package becomes similarly important to left-pad
                                                                                      4. tip off / file a DMCA / etc. with npm
                                                                                      5. ???
                                                                                      6. Profit!1
                                                                                  1. 4

                                                                                    During my stint in government, I kept a link to the OSS Sabotage Manual in my email footer, since it bore a striking resemblance to what a lot of folks thought was a best practice.

                                                                                    Would be fascinating for someone to an anthropological study of how the advice morphed from sabotage to “best practice”. I suspect it looks like, “In an effort to stamp out failure-case outliers, we developed a methodology which also prevented success-case outliers, and as we attempted to prevent more and more failure cases, we prevented more and more success cases, until all we had left was the middle, but we kept applying these same norms which eventually became ‘accountability for accountability’s sake, with no consideration of overall performance’”, but someone should really do the actual research :-)

                                                                                    1. 4

                                                                                      Would be fascinating for someone to an anthropological study of how the advice morphed from sabotage to “best practice”.

                                                                                      Probably a case of “too much of a good thing”. Most of these are tolerable or even beneficial if done in moderation. It’s only when you go to the extremes and stay there that this becomes sabotage.

                                                                                      1. 2

                                                                                        Exactly, if any of these behaviors were bad under all circumstances, then it would be in our collective consciousness that it is destructive behavior. So what makes this sabotage here deadly effective is the fact that you hide your malicious intentions between many meta layers. Like “yeah, we all want to make some progress here, but we also want to do things the proper way, so the question is where we draw the line”, so while giving the appearance of cooperation, you’re introducing yet another discussion!

                                                                                    1. 3

                                                                                      I never understand how people suggest microservices for improving the software architecture! To me it seems that the performance argument is all there is to microservices, and in all other aspects it’s a negative trade-off. And it’s a very negative trade-off especially for software architecture!

                                                                                      You write a series of services that take in one value and output another, ideally this would be done with no outside influence, i.e. you pass in ‘x’ and you will always get ‘y’.

                                                                                      But these are just pure functions, you don’t need to separate the callee from the caller with your operating system’s network stack and all the hardware and the wiring in order to achieve separation of concerns! Even if you want a multi-lingual architecture, you’re still better off just going through the C FFI. Think about it, if you’re willing to serialize your entire interface (which you must be, since you’re considering microservices), you can just define a generic C function that takes a buffer of bytes and returns another buffer of bytes, then you should be able to hide any function that works on, say, JSON values from any language behind this C function, and you won’t be any worse off (architecturally) compared to microservices. Your architecture is the same, but at least you don’t have to account for network failures down to the FINEST GRANULARITY LEVEL!

                                                                                      1. 0

                                                                                        You don’t want to manually write makefiles. Use Autotools instead: https://autotools.io/index.html

                                                                                        1. 14

                                                                                          Why not, its completely fine to write “simple” makefiles for “simple” projects. I think the musl makefile is a good example for a not so simple but still simple makefile.

                                                                                          To me autotools generated makefiles are a hell to debug, just slightly less hellish than debugging cmake.

                                                                                          1. 5

                                                                                            The musl makefile is one of the cleanest production makefiles I’ve ever seen. But I note even its opening comment says, “This is how simple every makefile should be… No, I take that back - actually most should be less than half this size.”

                                                                                            I count, at least, 3 languages used:

                                                                                            1. GNU dialect of make
                                                                                            2. shell
                                                                                            3. sed

                                                                                            And hacks like this:

                                                                                            obj/musl-gcc: config.mak
                                                                                            	printf '#!/bin/sh\nexec "$${REALGCC:-$(WRAPCC_GCC)}" "$$@" -specs "%s/musl-gcc.specs"\n' "$(libdir)" > $@
                                                                                            	chmod +x $@
                                                                                            
                                                                                            obj/%-clang: $(srcdir)/tools/%-clang.in config.mak
                                                                                            	sed -e 's!@CC@!$(WRAPCC_CLANG)!g' -e 's!@PREFIX@!$(prefix)!g' -e 's!@INCDIR@!$(includedir)!g' -e 's!@LIBDIR@!$(libdir)!g' -e 's!@LDSO@!$(LDSO_PATHNAME)!g' $< > $@
                                                                                            	chmod +x $@
                                                                                            

                                                                                            Local legend @andyc of Oil Shell fame pushes the idea that Shell, Awk, and Make Should Be Combined. IMHO, the musl example is persuasive empirical evidence for his position.

                                                                                            (I’m hoping @stefantalpalaru is being sarcastic about Autotools and we’re all falling to Poe’s Law.)

                                                                                            1. 2

                                                                                              (I’m hoping @stefantalpalaru is being sarcastic about Autotools and we’re all falling to Poe’s Law.)

                                                                                              No, I’m not. I’ve worked with hand written Makefiles, Autotools and CMake on complex projects and I honestly think that Autotools is the lesser of all evils.

                                                                                              Local legend @andyc of Oil Shell fame

                                                                                              Now I hope you’re the one being sarcastic. Who exactly uses the Oil Shell?

                                                                                              1. 3

                                                                                                Now I hope you’re the one being sarcastic.

                                                                                                I was not being sarcastic. @andyc’s Oil Shell posts consistently do well in voting here.

                                                                                                Who exactly uses the Oil Shell?

                                                                                                Who uses a less than a year old shell that explicitly isn’t for public use yet? I’m hoping very few people.

                                                                                                What does the number of Oil Shell users have to do with his argument?

                                                                                          2. 7

                                                                                            Err. Last time I touched autotools it was a crawling horror.

                                                                                            Makefiles are fine. Just don’t write ones that call other makefiles (recursive make considered harmful and all that).

                                                                                            1. 3

                                                                                              Just don’t write ones that call other makefiles (recursive make considered harmful and all that).

                                                                                              Clearly someone needs to write “Make: The Good Parts” 😂

                                                                                              1. 2

                                                                                                Isn’t non-recursive make also considered harmful?

                                                                                                1. 2

                                                                                                  I think the ideal is a makefile that includes parts from all over your source tree, so that there’s one virtual Makefile (no recursive make invocation O(n^2) issues) but changes can be made locally. Best of both worlds!

                                                                                              2. 5

                                                                                                I’m no expert on Make or Autotools, but my response to building automation on top of an automation tool is: “Please, god, no!”

                                                                                                If your automation tool lacks the expressiveness to automate the problem your solving, the solution should never be to bolt another automation tool on top of it. It’s time to start over.

                                                                                                1. 2

                                                                                                  I’m going to take a guess that you’re not a DevOps engineer.

                                                                                                  1. 1

                                                                                                    “Lets just use another layer of automation!” is the DevOps version of solving every problem with another layer of indirection clearly! :)

                                                                                                  2. 1

                                                                                                    But why not? One tool (cmake, meson) checks dependencies and works on high-level concepts such as “binary”, “library”. Other tool (make, ninja) is low-level and operates on building individual files. It’s sane separation of concerns.

                                                                                                    Make, however, tries to be high-level (at least GNU make, it even has built-in Scheme), but not enough high-level and it might be better at low level (that’s why ninja was invented).

                                                                                                    Monolith build tools like Bazel might better handle invalidation but this class of tools is not explored enough (existing tools are designed for specific Google/Facebook’s use cases).

                                                                                                  3. [Comment removed by author]

                                                                                                    1. 3

                                                                                                      Autotools is terrible.

                                                                                                      Yes, but all the alternatives are worse.

                                                                                                    2. 1

                                                                                                      Disagree

                                                                                                      https://varnish-cache.org/docs/2.1/phk/autocrap.html

                                                                                                      And look how complicated this configure script is which doesn’t take 60 seconds to run:

                                                                                                      https://github.com/bsdphk/Ntimed/blob/master/configure

                                                                                                    1. 3

                                                                                                      I think I’m missing something here. A lot of the deficiencies for the simple examples he gives are pretty easily fixable. And his simple example is… not very simple.

                                                                                                      If you cargo cult a Makefile from a rando Internet page, and you have a big hairy project, then, yeah, it will be ugly.

                                                                                                      The only build system that has impressed me so far is Stack and Cargo, and they are confined to single language ecosystems. Perhaps a language agnostic build system is a better idea in theory than in practice?

                                                                                                      1. 1

                                                                                                        The only build system that has impressed me so far is Stack and Cargo, and they are confined to single language ecosystems. Perhaps a language agnostic build system is a better idea in theory than in practice?

                                                                                                        Have you tried nix?

                                                                                                        1. 1

                                                                                                          I’m interested in what impressed you about Cargo and stack. If you have time to elaborate (details please!), I’d appreciate it.

                                                                                                          I ask as a Pony core team member who is quite satisfied with make but very interested in what people like and dislike in the single language tools they use.

                                                                                                          1. 1

                                                                                                            One good lesson is to have two files for dependencies, unlike Python pip for example.

                                                                                                            One file should be a compact list of direct dependencies. Version numbers are optional. Use that to specify. Should be in version control with your code.

                                                                                                            Another file contains all (transitive hull) dependencies with exactly the version numbers which are used. Use that to make builds repeatable. You may or may not check this file into version control.

                                                                                                            (Technically, It is not necessary to use two files, but it seems pragmatic)

                                                                                                        1. 2

                                                                                                          Imma let you finish, but I feel like until there is a stable, well-supported(*), aesthetic Linux laptop, lists like this are sort of like pointing to a car with square wheels and asking, “Why won’t anyone use the stereo?”

                                                                                                          There are many reasons why the Linux world never got a laptop better than the old Thinkpads – most of them out the control of kernel hackers, system programmers, and web developers (the people I assume are reading this article) – but without solving that problem, it doesn’t really matter which desktop window manager is the best. Sorry to be a downer.

                                                                                                          (*) meaning, at bare minimum, that wifi & sleep modes work without a single line of config file tweaking

                                                                                                          1. 3

                                                                                                            To be fair, I never needed to tweak a single line of config in order to get wifi working since I switched to Mint a few years ago (and I’ve used multiple versions on multiple computers). But you’re absolutely right that there are all these minor things like headphones working strangely, webcams showing upside down, random crashes at boot time, even rare screen freezes at daily use. For a programmer, these minor annoyances aren’t enough to counter the value you get out of developing on Linux, but for a home user who just wants to browse Facebook, they’d be show stoppers from day 1.

                                                                                                          1. 3

                                                                                                            Nice share thank you. I want to get started already! And rewrite our main API ;)

                                                                                                            1. 3

                                                                                                              The parser was my favorite. I could be misreading it since I dont know the language. The time example did look really easy to express and/or follow.

                                                                                                              1. 2

                                                                                                                It is indeed a nice design.

                                                                                                                You can read more about Parsec in this paper: https://web.archive.org/web/20140528151730/http://legacy.cs.uu.nl/daan/download/parsec/parsec.pdf

                                                                                                                If you plan to give a try, you should directly start with MegaParsec: https://hackage.haskell.org/package/megaparsec

                                                                                                                1. 2

                                                                                                                  IMHO, MegaParsec has a terrible roadblock for a Haskell beginner. The first thing you’ll try to do with it will be something like (if you’re lucky enough to get the imports right):

                                                                                                                  import Text.Megaparsec
                                                                                                                  import Text.Megaparsec.Char.Lexer
                                                                                                                  
                                                                                                                  main = parseTest decimal "123"
                                                                                                                  

                                                                                                                  Then you’ll immediately be greeted by a compiler error:

                                                                                                                   error:
                                                                                                                      • Ambiguous type variable ‘e0’ arising from a use of ‘parseTest’
                                                                                                                        prevents the constraint ‘(ShowErrorComponent
                                                                                                                                                    e0)’ from being solved.
                                                                                                                  

                                                                                                                  For a Haskell beginner, it would be almost impossible to guess what to do next. Well, I’ll give spoilers here:

                                                                                                                  ...
                                                                                                                  import Data.Void
                                                                                                                  type Parser = Parsec Void String
                                                                                                                  
                                                                                                                  main = parseTest (decimal :: Parser Integer) "123"
                                                                                                                  

                                                                                                                  Normally, you’d rely on tutorials around the net to get you covered, but megaparsec had a recent major release which broke all the tutorials you get by googling “Megaparsec getting started”.

                                                                                                                2. 1

                                                                                                                  Indeed!

                                                                                                              1. 17

                                                                                                                I love the smell of outrage in the morning. Or afternoon. Whichever.

                                                                                                                I like Firefox. I’m not terribly concerned about this. A sure way to get them to stop is to donate monthly.

                                                                                                                1. 15

                                                                                                                  How much? How much would it cost to stop this, over and above Mozilla’s existing income? Why doesn’t Mozilla, as a user first organization, tell its users “we need this much money or we’re going to add the looking glass extension”?

                                                                                                                  1. 6

                                                                                                                    Oh, yes, a 1000 times this! I’d happily pay for Firefox more than I pay for every single web service I use.

                                                                                                                    1. 5

                                                                                                                      It would cost an infinite amount, because that’s the amount companies need to aim to earn in a capitalist economy.

                                                                                                                      1. 5

                                                                                                                        It’s a non-profit.

                                                                                                                        1. 3

                                                                                                                          Even non-profits have expenses to cover. Over infinite time these approach infinity as well.

                                                                                                                          The point still stands that them having a transparent budget would make it easier for us the users to “pay off” these kinds of threats.

                                                                                                                          1. 3

                                                                                                                            The mozilla corporation (a branch of the mozilla non-profit Foundation) is for-profit.

                                                                                                                            1. 3

                                                                                                                              Only legally. It’s “keep the lights on”.

                                                                                                                              The problem is that software development and the services the corp provides is not considered non-profit under most jurisdictions.

                                                                                                                              This setup (a foundation and a corporation) is straight from the playbook for non-profits that have substantial non-eligible parts.

                                                                                                                      2. 4

                                                                                                                        A sure way to get them to stop is to donate monthly.

                                                                                                                        They made $360,000,000 last year: https://www.ghacks.net/2017/12/02/mozillas-revenue-increased-significantly-in-2016/

                                                                                                                        Why would you want to throw more money at the corporation who’s pissing on you while telling you that it’s raining?

                                                                                                                        1. 8

                                                                                                                          When you are donating to Mozilla, you are donating to the Foundation, which is not involved much in Firefox, but in a lot of other tech and policy advocacy things. This includes net neutrality lobbying, discussing the copyright reform in Europe and support many many tech teaching projects all over the globe.

                                                                                                                          You’d be hurting all those projects instead of Firefox development over your anger with the product.

                                                                                                                          Making your anger known in a different fashion will have more impact.

                                                                                                                          (FWIW: I don’t want to keep you from stopping to donate if you don’t feel like Mozilla Foundation is not following their mission anymore)

                                                                                                                          1. 4

                                                                                                                            Regrettably, the net neutrality thing didn’t pan out, I’m not sure about the copyright work, and the educational stuff is probably better left to local efforts (if my own experience is to be believed).

                                                                                                                            I’d rather they focus on Firefox, Thunderbird, and documentation and free up people and resources to go do other things.

                                                                                                                            1. 6

                                                                                                                              Regrettably, the net neutrality thing didn’t pan out, I’m not sure about the copyright work, and the educational stuff is probably better left to local efforts (if my own experience is to be believed).

                                                                                                                              Policy is no “put enough money here, it’ll work” game. The debate about net neutrality has been going back and forth in the recent years and Mozilla has always been involved. Losing Mozilla as a campaigner there would not be helpful in any way.

                                                                                                                              The educational stuff is probably better left to local efforts (if my own experience is to be believed).

                                                                                                                              This is obviously very personal, but in my experience, Mozilla has reach to a lot of people and other groups that other tech groups can only dream of. I would highly recommend looking at who’s around at MozFest. Also, the Foundation does a lot of these things through co-operations like with the Ford Foundation, which are usually quite productive and the output brings a lot of worthwhile reading.

                                                                                                                              I’d rather they focus on Firefox, Thunderbird, and documentation and free up people and resources to go do other things.

                                                                                                                              Thunderbird obviously left out, Mozilla Corporation has most employees on precisely these products. It is their focus.

                                                                                                                              The Corp is just not the Foundation and merging them also makes no sense, IMHO.

                                                                                                                        2. 2

                                                                                                                          Or use a fork if all else fails. Sad day if it comes to that, after all the good work otherwise gone into Firefox.

                                                                                                                        1. 1

                                                                                                                          I appreciate the effort the author has put into the book, but I think the contents don’t align with the initial goal of telling a toddler what a programmer does. In a book about firefighters, you see firefighters fighting fire, in other books you see doctors treating patients or constructors constructing a bridge. So, what does a programmer do? Do we queue up in ice cream parlors, or talk to meowing dogs?

                                                                                                                          1. 1

                                                                                                                            I’m not an algorithms guy, nor do I claim to be. This paper(? or whatever you want to call it) makes some interesting claims

                                                                                                                            • Sorting in O(n) time sequentially, O(log(n)) in parallel. That’s fast!
                                                                                                                            • “O(m) space where m is the size of: { min, min + 1, min + 2, … , max - 1, max }”
                                                                                                                              • Directly quoted from the article - I’m not entirely sure what it means for the size to be a set of numbers
                                                                                                                            • “…both the parallel and sequential versions sort the array A with a collision probability of 0.00001%.”
                                                                                                                              • This may seem small, but it’s 1/100000. That’s pretty significant if you’re sorting, say, a million items. Correct me if I’m wrong, but I think that means there’s actually a 10 to 1 chance that there isn’t a collision with a million item sort.

                                                                                                                            Also, doing a ctrl-F for “stable” does result in anything - so there’s no indication if it’s stable or not. I’d lean on the assumption that it’s unstable, because it’s being done in parallel? But again, I’m not an algorithms guy.

                                                                                                                            1. 4

                                                                                                                              Well… it depends on what you mean by stable. All the numbers in the result will be, by definition, in order… but you may get new numbers that weren’t in the original array. The rate of those new numbers is 1/100000.

                                                                                                                              From what I can tell, this is kinda how the algorithm works:

                                                                                                                                  lookup = bloomfilter(numbers)
                                                                                                                                  for i in range(min(numbers), max(numbers)):
                                                                                                                                      if i in lookup:
                                                                                                                                          yield i
                                                                                                                              

                                                                                                                              It’s important to note that because we’re using bloom filters, this scheme does not handle arrays with duplicate entries. That’s why they mention “unique elements” in the first statement.

                                                                                                                              It’s the i in lookup that has the 0.00001% error rate. The O(m) comes from the fact that we do range(min(numbers), max(numbers))…. the author has a really strange way of stating that with that set notation.

                                                                                                                              One last thing to note is that the rate of O(log(n)) is theoretical assuming an infinite number of available cores.

                                                                                                                              1. 1

                                                                                                                                From what I can tell, this is kinda how the algorithm works:

                                                                                                                                Thanks for this. I skimmed through the whole thing several times without figuring out what the actual algorithm was.

                                                                                                                              2. 3

                                                                                                                                As this is a probabilistic sorting algorithm, you will have a small chance that the given array is not sorted after executing the algorithm. Therefore this algorithm shouldn’t be used critical operations.

                                                                                                                                I’m going to guess it isn’t stable :P

                                                                                                                                1. 1

                                                                                                                                  Hah, I definitely missed that. Out of curiosity, do you (or anyone else) know some possible applications of a “mostly sorting” algorithm?

                                                                                                                                  1. 4

                                                                                                                                    In data science for instance, you rarely need any operation to be perfect, since everything you calculate is statistical anyway.

                                                                                                                                    1. 3

                                                                                                                                      This is particularly useful for approximate percentiles. If I have a dataset with 239487283572934 numbers, it’d be hard to store in memory and constantly keep updated and sorted. With this algorithm, all you need to do is maintain: the bloom filter (which is small), the min/max numbers and the total number of records that have been added. This scheme would have O(1) insertion and O(M) query where M is the size of the interval the data is on (ie: how spread apart the min and max are).

                                                                                                                                      The thing that makes this kinda useless though is that it only supports sorting unique items.

                                                                                                                                      1. 2

                                                                                                                                        Perhaps as a first pass, ahead of a proper sorting algorithm?