Hacker Newsnew | past | comments | ask | show | jobs | submit | taylorallred's commentslogin

Meanwhile:

    not     eax
    and     eax, 1

I see people waxing poetic over Ruby a lot saying that it's a language "built for the human". The thing is, every language is built for humans (or at least should be) but we tend to have different definitions for what "built for humans" means. Ruby certainly has some clean and expressive syntax, but I personally find it difficult to use because of its dynamic typing (which makes it hard to know what the types are while I'm writing it) and the heavy use of macros and other magic (which does unknown operations without my knowledge and introduces symbols into the scope mysteriously). That said, it clearly works great for some humans, just not for this human (me).


Obviously ruby is bigger than just rails, but rails definitely popularized the idea of magical objects that are automatically syncing state and doing things on your behalf. This is presented by fans as surprising and delightful, rather than surprising and terrifying.

Popular python projects like requests and flask also lean into the idea of providing a programmer interface that is expressive but also maximally brief on the happy path—see especially the context local proxies in Flask (request, session); these look like global module imports, but they're actually request specific despite not being passed into your handlers... eek.

On the other side of things, languages like zig and go feel like a bit of a backlash to this, that no, magic is bad and everything should be explicit, even if it costs us a bit of code to do so.

Rust I think sits at an interesting place in this, because it's all pretty strict and explicit, but all the macro and type system stuff does re-open the door to offering some DSL-like things in a way that's perhaps a bit cleaner than what other languages would have to do to get to the same place programmer interface-wise.


Funny that you mentioned Flask, which literally started as an April Fool's joke [0], but that hasn't stopped it from becoming the 10th [1] or 11th [2] most popular web framework, with over double the number of devs compared to Rails, so "seriousness" likely has nothing to do with making people want to use it.

[0] https://lucumr.pocoo.org/2010/4/3/april-1st-post-mortem/

[1] https://www.statista.com/statistics/1124699/worldwide-develo...

[2] https://survey.stackoverflow.co/2025/technology#most-popular...


> see especially the context local proxies in Flask (request, session); these look like global module imports, but they're actually request specific despite not being passed into your handlers... eek

I guess that was a Bottle thing that Armin Ronacher borrowed: https://bottlepy.org/docs/dev/api.html#request-context

A bad idea in retrospect, but hard to change now: https://github.com/bottlepy/bottle/issues/761


I have admired many parts of Zig and its philosophy but I've never seen it as a language that I want to use. What I've noticed is that Zig users care most about explicitness, simplicity, and minimal indirection. This leads to a lot of syntax that is cumbersome to read (albeit unambiguous) like casting and a lack of "convenience" features. I can't help but think that maybe they're right and that this philosophy probably leads to better software because nothing is "hidden". But, I also think that there's a level of abstraction/indirection that makes code clearer and less error-prone. It's a tricky balance to achieve, and past languages have succeeded and failed at it to different degrees. Either way, I echo the OP's sentiment: if Zig is your jam, great, go make some awesome stuff with it. It's just not my go-to today.


Design choices that are appropriate for low-level programming may be less appropriate for high-level programming and vice versa. In low level programming, you may want to see "on the page" anything that could translate to some machine work, because in low-level programming, such details may be essential to the algorithm. In high-level programming, the same details are likely not essential to the algorithm, and so you don't want to see them.


I think, but I may be wrong, Zig wants to be high level assembly that could replace C. If people are viewing it from Python, Ruby, JS, and then C++ and Java POV, Zig may be a little too "raw". But then I don't think Zig intends to compete with C++ or Java. May be there will be a Zig ++ or Objective-Zig someday that will do that.


It really comes down to a matter of opinion where the line between "nothing hidden" and convenience lies. Technically, a loop is an abstraction of convenience that hides the comparative jump underneath.


For those who are interested, I think that arena allocation is an underrated approach to managing lifetimes of interconnected objects that works well with borrow checking.


I agree, but in my experience arena allocation in Rust leaves something to be desired. I wrote something about this here: https://blog.reverberate.org/2021/12/19/arenas-and-rust.html

I was previously excited about this project which proposed to support arena allocation in the language in a more fundamental way: https://www.sophiajt.com/search-for-easier-safe-systems-prog...

That effort was focused primarily on learnability and teachability, but it seems like more fundamental arena support could help even for experienced devs if it made patterns like linked lists fundamentally easier to work with.


Thanks for those links. Have you tried using arenas that give out handles (sometimes indexes) instead of mutable references? It's less convenient and you're not leveraging borrow checking but I would imagine it supports Send well.


> works well with borrow checking.

Yes, because it defeats borrow checking.

Unsafe Rust, used directly, works too


It does not defeat borrow checking. The borrow checker will ensure that objects do not outlive the arena. It works with borrow checking.


The borrow checker knows nothing about your arena allocations.

That is if we are talking about the same thing!

All the borrow checker knows is there is a chunk of memory (the arena) in scope.

It works, no memory safety in the sense that you must manage your own garbage and you can reference uninitialized parts of the arena

I have found myself using arenas in Rust for managing circular references (networks with cycles) and if I were to do it again I think I would write that bit in C or unsafe Rust.


The popular Bumpalo only returns references with the lifetime of the allocator. Not sure what you mean by manage your own garbage, an arena allocator deallocates everything when it goes out of scope. You definitely can't reference uninitialized parts of an arena.


This. Arenas don't work when you don't know when it's okay to free. The borrow checker can help with that (or you can track it manually in C/Zig).


Piping syntax is nice for reading, but it's hard to debug. There's no clear way to "step through" each stage of the pipe to see the intermediate results.


There is usually some variant of tee that lets you do that.


I love seeing these kinds of explorations in the realm of language design. I've wondered about expanding the notion of boolean operators like this. For all its flaws, one thing I've always liked about JS is the overloaded (||) and (&&) operators. It's really slick to write something like `foo.get_that_can_fail(x) || "default value"`.


I'm less concerned about people not adopting other frameworks. I'm concerned about people not knowing/learning the fundamentals of how websites work. It's apparent in job interviews that developers from bootcamps are only learning how to make sites/apps with React and don't know the fundamentals that support it.


"So-called "natural language" is wonderful for the purposes it was created for, such as to be rude in, to tell jokes in, to cheat or to make love in (and Theorists of Literary Criticism can even be content-free in it), but it is hopelessly inadequate when we have to deal unambiguously with situations of great intricacy, situations which unavoidably arise in such activities as legislation, arbitration, mathematics or programming." -Dijkstra


I really appreciate how this article explains why certain design patterns became a thing. Usually, it was to address some very practical problem or limitation. And yet, a lot of younger programmers treat these patterns like a religious dogma that they must follow and don't question if they really make sense for the specific situation they are in.


The main motivation for the concept of design patterns is to give unique names to existing programming patterns, so that when someone says “Strategy pattern”, everyone knows what pattern that refers to, and vice versa that the same pattern isn’t called ten different things. It’s to make communication about program design efficient, by defining a vocabulary of patterns that tend to reoccur, and a common structure for describing them. Not all patterns were successful in that way, but it’s the main idea behind design patterns.

The question of when a using a given pattern is appropriate is orthogonal to that. The fact that a named pattern has been defined doesn’t imply a recommendation to use it across the board. It depends on the context and on design forces, and those change with time and circumstances. Anti-patterns are patterns as well.

It’s a pity that the idea of design patterns ended up (after the pattern language craze faded) being almost exclusively associated with the specific patterns named and described in the GoF book.


> The main motivation for the concept of design patterns is to give unique names to existing programming patterns

No, naming them is not the main purpose, preserving and transmitting knowledge of what they are and what they are useful for, so that people aren't fofced to rediscover solutions to the same problems over and over again. [0] Naming is obviously important for that purpose, but isn't the main goal, but a means of supporting it.

[0] If this sounds like a subset of the purpose of a reusable code library, it is, which is why in languages with sufficient abstraction facilities to allow the generic implementation of a pattern to be reusable, well documented (for the “where and when to use this” piece) code libraries replace documents that have the explanation paired with implementation recipes that one can modify to one’s particular use.


> No, naming them is not the main purpose, preserving and transmitting knowledge of what they are and what they are useful for, so that people aren't fofced to rediscover solutions to the same problems over and over again. [0] Naming is obviously important for that purpose, but isn't the main goal, but a means of supporting it.

Yes, this.

It's as if design patterns represents recurring patterns followed when designing something.

Wouldn't it be silly if architects spent their time shit-talking the silliness of referring to those holes added to walls to be covered by movable panes of glass as "windows"?

Somehow we're here seeing software developers do this sort of nonsense.


> It’s a pity that the idea of design patterns ended up (after the pattern language craze faded) being almost exclusively associated with the specific patterns named and described in the GoF book

That book is the closest we came to establishing a common language. I remember brushing up on the names of design patterns whenever I had an interview. Ultimately, though, it didn't yield any benefit that the industry is missing now.

Like you said, the fundamental idea behind the book was that consciously naming, cataloging, and studying design patterns would improve communication among programmers. There was also an idea that studying design patterns would give beginning programmers a richer repertoire of programming techniques faster than if they had to figure them out themselves.

Looking back with decades of hindsight, my belief is that awareness and intentional use of design patterns made no difference whatsoever. Some names stuck, and would have anyway. Others didn't, and years of status as official "design patterns" in a book widely studied across the industry couldn't make them. The younger programmers I work with who had no exposure to the GoF book, and for whom "design patterns" is something that dusty old farts used to talk about, use patterns like Flyweight, Proxy, Command, Facade, Strategy, Chain of Responsibility, Decorator, etc. without knowing or needing a name for them, and they communicate amongst themselves just as efficiently as my generation did at the height of the design pattern craze.

In the final analysis, I have never looked at the less experienced programmers around me and thought, "This situation would go faster and smoother if they had studied design patterns." The generation that learned to program after design patterns had faded as an idea learned just as quickly and communicates just as well as the generation that studied them assiduously as junior programmers like I did.


> Like you said, the fundamental idea behind the book was that consciously naming, cataloging, and studying design patterns would improve communication among programmers.

> The younger programmers I work with who had no exposure to the GoF book.....and they communicate amongst themselves just as efficiently as my generation

> The generation that learned to program after design patterns had faded as an idea learned just as quickly and communicates just as well as the generation that studied them assiduously as junior programmers like I did.

I've never read GOF so I don't know if they emphasize communication, but I have read and studied many other programming pattern books and communication is low on the list of reasons to learn them in my opinion. Their only purpose for me is to organize code in a way that has been proven to "scale" along with a codebase so that you don't end up with a plate of spaghetti.


> a lot of younger programmers treat these patterns like a religious dogma

First you learn what the pattern is. Then you learn when to use it. Then you learn when not to use it.

The gap between the first and third step can be many years.


> The gap between the first and third step can be many years.

I admire your optimism!


The explanations are great! The condescension, not so much.

> Simple: we just use the language like it was meant to be used.

> Use Default Arguments Like a Normal Human

etc


Yes, programmer is super human


Probably also a problem that exists because of how programmers are taught. Using Java and being presented with the patterns as solutions to what Java does.


> I really appreciate how this article explains why certain design patterns became a thing. Usually, it was to address some very practical problem or limitation.

I don't agree at all. I feel that those who criticise design patterns as solution to practical problems are completely missing the point of design patterns, and the whole reason they have the name the have: design patterns. I'll explain.

Design patterns are solutions to common design problems, but "problems" isn't the kind of problems you think it is. It's "problems" in the sense that there are requirements to be met. A state pattern is a way to implement a state machine, but you still have a state machine and a state pattern if your state classes don't handle state transitions.

More to the point, look at singletons. It's irrelevant if they are implemented with a class or a closure or a module. What makes a singleton a singleton is the fact that there is an assurance that there will be a single instance of an object. Does an implementation that allow multiple instances or doesn't return the same instance qualifies as a singleton? Obviously not.

Design patterns are recurring solutions to recurring problems. They are so recurring that they get their name and represent a high level concept. A message queue is a design pattern. An exception is a design pattern. Lazy loading is a design pattern. Retries and exponential backoffs are design patterns. Etc. Is anyone arguing that Python has none of it?

So many people trying to criticise the GoF but they don't even bother to be informed or form an educated opinion.


I see you’ve been downvoted.

Design patterns aren’t solutions to common design problems. They’re after the fact descriptions of solutions for design problems. That’s the issue. That’s the beef. Everyone thought of that book as a cook book instead of a naturalists’ musings on an ecosystem, which is what they are.

Those of us who designed before people discovered that stupid book were constantly asked what the differences were between this pattern and that. And the book just isn’t thick enough and Eric Gamma was just trying to complete a thesis not write a book, so despite having at least 8 years in industry before completing his masters he cocked it up. And ruined Java in the process.

We had a contemporary of Vlissades teach a class at my last company and he crystallized all of my suspicions about the GoF book and added a whole lot more.

My advice for at least fifteen years is, if you think you want to read GoF, read Refactoring instead. If you’ve read Refactoring and still want to read GoF, read Refactoring a second time because it didn’t all sink in.

Refactoring is ten times the value of GoF for teaching you how to do this trade and how to break up architectural brambles.


> Design patterns aren’t solutions to common design problems. They’re after the fact descriptions of solutions for design problems. That’s the issue.

No, they are not. They describe a way to design something. They are called design patterns. It is in the name, already. Consider instantiating an object. You can have a factory, or you can pass a parameter object, you can implement a builder. Perhaps you can use a flywheel? In testing there is also object mothers.

Did you noticed that each term describes a very specific and concrete approach to tackle a single use case? There is no "after the fact" anything. Claiming design patterns is something you do "after the fact" reflects a complete failure of understanding what design patterns are and how they are used.

No wonder people complain about design patterns. They are complaining about their own failure to understand what they are and how they are used. Of course people complain about things they don't understand.

> Those of us who designed before people discovered that stupid book were constantly asked what the differences were between this pattern and that.

The book didn't discovered anything. At best it contributed to standardize names used for popular design patterns.

Also, the telltale sign that people are shit talking design patterns out of sheer ignorance,and willful ignorance, is the fact that there are over a dozen reference books on design patterns. Reference authors such as Martin Fowler even wrote themselves two or three books worth of patterns. But GoF is the only one being attacked all the time? Why? Because of ignorance.


I also completely disagree with the builder description.

It sounds like they've not had to use it for any meaningful work, and basically described a constructor. Yeah, named parameters are great, and I miss them when I don't have them, but if you think a builder only works like this

Object.setX().setY().build()

Then it tells me that you haven't built anything meaningful. It's a way of building a state and running an operation at the end in a contained manner. If your build method doesn't run some sort of validation then it's probably a waste of time, might as well just call setters, return this and call it a day if you want to be verbose and chain commands.


I mean, people usually call those 'feature' when they're built-in. I would never call 'lazy evaluation' in Haskell a design pattern, because it's part of the language.

If I have to implement something similar myself in C++ however, I'll use a niche design pattern.


> I mean, people usually call those 'feature' when they're built-in.

No, that's specious reasoning. A message queue is still a message queue if you use one provided by the OS. An exception is still an exception even if it's provided as a standard component. A state machine is still a state machine regardless of how you choose to implement your concrete implementation.

Design patterns are all about the patterns followed when designing something. That's it.


I don't however appreciate that the author doesn't actually know about Java or C++ well enough such that they are spewing falsehoods about Java or C++. Saying things like "There’s no clean way to say 'this is private to this file' (in C++)" is just bonkers. The author is well intentioned, but coming up with the wrong reason is worse than not offering any reason.


I had that thought too, and thought I must have misunderstood something. I generally assume I’m the dummy. :)


I am an ex Java developer. Enterprise Fizz Buzz is highly entertaining. That stupid masters thesis pretending to be a design book landed right an inflection point and ruined half a generation of developers.

What isn’t entertaining is using OpenTelemetry, which takes me right back to Java for over-engineering. Moving to OTEL from StatsD cost us about 3% CPU per core, which on 32 core machines is an entire CPU lost to telemetry. Or more accurately, an entire second CPU lost to telemetry. That is not right.

Prometheus doesn’t have these problems. And isn’t trying to fix quite as many problems I’ve never had.


What's amazing to me is that often all it takes to go fast is to keep things simple. JBlow once said that software should be treated like a rocket ship: every thing you add contributes weight.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: