Hacker News new | past | comments | ask | show | jobs | submit login
Clojure Design Patterns (mishadoff.com)
315 points by simonpure on Nov 24, 2017 | hide | past | favorite | 126 comments



Clojure is fantastic for its simplicity, and I worked on a Clojure code base full time for 5 years, coming up with ways of translating Java patterns into Clojure. But I've noticed it has not been gaining traction in the job market, and now I feel like that 5 years has been a waste of valuable career building time, which I wish I had spent gaining more experience in (sigh) C# and .NET, so that I could get the more local jobs which all seem to use the Windows ecosystem, so we don't have to uproot our family and move to the city. Not that I don't know C# and .NET, but I definitely don't have 3+ years experience in it and I definitely don't have any experience MS SQL. So being able to do really cool things in Clojure, and especially having excellent rapid development skills with REPL-driven development, has done me no good. The one remote job that I found that uses Clojure turned me down because they used zippers in the code test, and that's literally the one Clojure construct I just can't wrap my head around, which is ironic because idiomatic Clojure really doesn't use recursion in the first place, favoring streams and transducers instead. My career future doesn't really seem to have a lot of Clojure in it unfortunately. Plus most of modern JavaScript has most of the same benefits as Clojure anyway, especially in terms of FP.


As Evan Czaplicki (creator of Elm) said:

“If functional programming is so great, why is it still niche? We have a product that can practically eliminate runtime errors, make refactoring much easier, lighten the testing burden, all while being quite delightful to use. What’s the hold up?”

- http://www.elmbark.com/2016/03/16/mainstream-elm-user-focuse...

I'm just getting into Clojure and enjoy working with it so much that I don't care if there are job opportunities at the end of it to justify the time investment and mind-reboot. It's the first language that I didn't feel like I was fighting, and Parinfer has made all those “weird parentheses“ a joy: https://shaunlebron.github.io/parinfer/

That said, there do seem to be more opportunities than last time I looked at Clojure/Scala/Haskell (Functional Works, mentions in HN Who's Hiring) – it feels like people are waking up to FP ideas after React stormed the front-end scene.


> “If functional programming is so great, why is it still niche? We have a product that can practically eliminate runtime errors, make refactoring much easier, lighten the testing burden, all while being quite delightful to use. What’s the hold up?”

I think they are over-estimating how much people care about runtime errors.


I agree. I've worked in both Elm and ClojureScript. In one, I have to constantly deal with compiler errors. In the other, about as much runtime errors. The net time for error handling is the same. But the net time in actually writing code is in favor of ClojureScript, which requires at least half as many lines as Elm (and often much less than half).

Error handling is somewhat over-emphasized in comparison to other things that affect productivity (and maintainability).


Especially on the JVM where most exceptions need to be explicitly handled and the ones that aren't can be handled in a way that doesn't impact users.


elm-lang is a front-end only language compiled to JS(at the moment).

JVM doesn’t apply hence.


> “If functional programming is so great, why is it still niche?

It's niche because learning a language is the exact opposite of fast iterative process with immediate feedback. The feedback cycle of learning and evaluating a language is 6th months to multiple years, which means it takes a lot to really evaluate one. Then the added issue of network effects (ie needing others to know the language in a team).


I am not sure it is niche anymore. Java 8 added many functional features to Java. :)


Functional 'concepts' are not niche, but functional languages still are. If you asked your average Java 8 programmer or JS programmer to write an app in Haskell or Elm, they'd struggle.


I'd consider myself an average JS programmer and would love to try writing web apps in Haskell. I've spent some time on Haskell books, fell in love with the type system, got a basic understanding of monads but found it difficult to "move forward".

I think the issue for me is I predominantly build web apps. Can you recommend any resources for building modern web apps in Haskell or at least fitting it into my day to day at work?


Try PureScript! [1]

Haskell-like (but taking away some of the pain points), for the frontend, compiles to very readable javascript.

[1]: http://www.purescript.org/


That looks really cool :) does it still depend on Bower?


There's no "dependency" per se, but in practice most of the community still uses bower.

There's an effort to make something better and on the same vibe as Haskell's `stack`, which is `psc-package` [1].

I switched to it for all new projects, and while it still has some rough edges, I don't really miss bower.

[1]: https://github.com/purescript/psc-package


Unfortunately, does not use persistent data structures.


Yes it does.


So did C++. But you can't program C++ or Java in a functional manner the way you can an actual FP language. Largely due to lack of proper data structures for FP.


why do we need Parinfer, why not dropping parentheses altogether in favour of itendantion


If I type () I have every reason to expect you'll see them, because nobody foolishly writes tools that mangle them.


Learning lisp is never in vain. You can almost apply your functional programming paradims learnt in clojure to most of the dynamic languages out there. Plus you will be thinking in the immutable way of doing things.


It's worth noting that most Lisp dialects don't really encourage immutable data, and Clojure seems to be a step forward there.


Yes, as someone whose primary languages are Ruby and JS, I agree. It has made a tremendous change in the way I organise code.


Lisp is fundamental programming knowledge IMO.


But "immutable" way of doing things have been encouraged, suggested, marked-in-stone as best-practices in most languages since 2005... am I missing something?

People have been saying that:

- Global Object is bad

- Stateless is better than Stateful

- Singleton becomes an anti-pattern

- Methods/Functions without side-effect (avoid mutation)

Nobody really mentioned to do things the Functional programming way per-se but the characteristics are there.


Immutable programming with proper immutable data structures (i.e. persistent) is very different than immutable programming in a language with lots of constructs for mutation.

You can throw "const" on things but that isn't really the same kind of immutable programming that exists in Clojure.

Because immutable programming is not just about data not changing, it's about the transformations you can do on that data without concern for the costs that would arise if you did those same transformations in a language without immutable data structures.


> which I wish I had spent gaining more experience in (sigh) C# and .NET

I am sort of afraid that I might end up in similar situation if I would need to change jobs. At my current company I worked 1/2y in Java, 1y in Clojure, 1y in Python, 1/2y in C#, 2y in mix of javascript, groovy, ansible and chef-scripts. There seems to be GO on a horizon.

This means that all the well earning "Senior Developer - requires 5 years experience with swing" will probably be out of reach.

But as they say, you shouldn't call yourself $LANGUAGE-programmer anyway, so I hope I will be able to sell myself as the "7 years of devops/process-automation", rather than "2-year Node.js experience" guy :-)


Doesn’t the Clojure way of thinking/programming help you with writing better JavaScript though? I’m a JS Dev and I’ve been looking into Clojurescript to broaden my horizon but I’m also hoping to learn some FP techniques that I can use in my Node/React projects.


I'm a JavaScript developer, and (much to my delight) my team recently switched to a much more FP-heavy style (for example, switching from Flux to Redux for our React app... we even used PureScript for a bit). The differences were night and day; even just prioritizing immutability has transformed our codebase. The project is about ~100,000 LOC, so the benefits we get in maintainability and readability are huge; also, after we switched to Redux, our application's performance jumped tremendously (for several reasons). So, to answer your question more directly, I can emphatically say: Yes!


I wonder how many people feel the same out of real life experience.

Imperative and mutable objects are still seen as the only way for serious products .. there needs to be a large body of evidence to at least make people consider other options (and I'm not trying to sell my church here, just avoid blindness)


What do you mean by serious products? There are plenty of massive projects written in purely functional languages (e.g. Facebook's Sigma) and while adoption isn't as fast as it could be, things seem to be shifting towards functional/immutable, which makes sense since reasoning about highly parallel code without RT and immutability is pretty much impossible.


> The project is about ~100,000 LOC

And I'd bet money that if that same project were translated into ClojureScript, it would be less than one-third that size for the same benefits.


I've considered pitching it, I'll be honest... We stumbled upon a pretty nice architecture via trial-and-error, but when I read about re-frame recently, I realized that it was the exact same thing except in a cohesive framework and years older than I'd have imagined (IMHO ahead of its time)!


Hi, I'm a Redux maintainer. I'd love to see a writeup on how your team has been using Redux, what maintainability benefits you've seen, and how the app's performance has improved. If you do write something, please ping me @acemarke and let me know!


It helps a lot. My C and Python code have improved significantly since I've started learning Clojure.


> Plus most of modern JavaScript has most of the same benefits as Clojure anyway

Except for the very elegant syntax. Your Clojure code will be at least half the size of equivalent JS code, probably much less than that. And without pulling in explicit dependencies on ImmutableJS, React and others.

Projects with less code have less bugs and are more fun to think about, in general. That's something extra Clojure brings to the table.


Also no macros, no parallelism


It's a bit sad how network effects rule. If businesses weren't sold so much .net maybe there would be more jobs for other, arguably better solutions.

Now, as a side note, there were recent news about clojure CLR. Maybe some will accept having clojure code on top of C# ? (clojure is often used as a better lifestyle on top of Java legacy)


I read a blog post a few days ago about a Clojure compiler from the CLR which is being actively maintained to produce bytecode for Unity. It was posted here a few days ago but didn't seem to gain much traction, perhaps there's more interest in this thread: http://nas.sr/magic/


I wish @ra had built an RSS feed for that. I never remember to go and read that blog.


That was what I was thinking about. Let's see if people flock here


ClojureCLR is definitely cool, and a few years ago I wrote a simplistic window manager [1] using ClojureCLR for scripting. But local jobs that want a C# person aren't probably the same kind of people who will be open minded about CLR languages, they probably just want someone who can maintain their plain-jane .NET apps that were written by someone fresh out of community college (which is ironically where I learned C++ and VB.NET).


your [1] was too lazy, please force


oops, enabling eager loading of [1]

[1] https://github.com/sdegutis/ZephSharp


I wrote a few lines of powershell recently, but you make me realize I could just go clojure ...


> Plus most of modern JavaScript has most of the same benefits as Clojure anyway, especially in terms of FP.

This is technically an accurate statement, the JavaScript ecosystem is massive and has excellent equivalents to just about every piece of useful Clojure FP construct out there.

But from a practical standpoint, when you start stitching these FP pieces together, you'll notice that the FP model in JS suffers immensely from the mutable-by-default design in its core data structures.

This means FP libraries have to accept and output these mutable-by-default data structures to gain any non-trivial adoption, which in turn often means they can't afford to use persistent data structures internally either, because recursively translating to and from the default mutable data structures, even just on the edges of the system, will often prove to be prohibitively expensive for most libraries. The entire JS ecosystem thus overwhelmingly assumes the use of mutable data structures, and in a program that tries to do FP in JS, any performance wins resulting from the use of structural sharing in persistent data structures (instead of naively cloning the default mutable data structures) get mostly nullified, if not outright negated by the need for recursive translation every time it needs to interact with third-party libraries or core browser APIs.

Even in systems that uses Redux (which as an architecture is about as functional as you can get, and outright forbids direct state mutation) overwhelmingly end up using built-in mutable data structures to represent state. Its Recipe page on "Using Immutable.JS with Redux" (https://redux.js.org/docs/recipes/UsingImmutableJS.html) is littered with a long list of caveats precisely because there exists far too many not-immediately-obvious performance footguns available for one to shoot themselves with when taking up the task of carefully micro-optimizing all the expensive toJS and fromJS calls they'd have to make to build anything non-trivial. This is of course not to throw ImmutableJS under the bus, because it provides an excellent set of persistent data structures by any measure. It does have an uphill battle to fight to justify its adoption though, because it exists in an ecosystem that compels users to reject it for no fault of its own.

I haven't even gotten started on the developer ergonomics of using non-native data-structures, which since ES6 has taken a (relative) nosedive, because of all the syntactic sugar that was introduced for the built-in data structures.

Contrast this with the ClojureScript ecosystem, in which the use of efficient persistent data structures is rarely ever a question, because that's the default, and every third party library and application written in CLJS can just take the associated performance benefits for granted.

P.S. Apologies for the rant. I've been switching back and forth between CLJS projects and JS projects for the past year, and this has always been my biggest pet peeve with the state of functional JS. I'm actually quite happy with just about every other aspect of functional JS, to be honest, but I fear JS may never reach its full potential as a functional language because of this core defect.


...yes, but that comes with burden of complexity and (usually) bad design decisions (like using core async).

Its not just night & day, closurescript > js; a lot of very good stuff exists there, but immutable by design isn’t a silver bullet that magically makes problems go away, and it (cljs that is) does introduce its own problems.

Practical examples of where cljs is tangibly a better choice is probably more useful to people.

For example, I personally have fought a cljs modal that kept an open channel waiting on user input; but when the modal closed, the channel was still there waiting and when it reopened there were now two channels, both getting input events, doing twice the work. Bad design, and not fp at all.

How did immutable structures help? Not at all. The author just used a global state atom to store everything anyway.

I’m just saying; yes, in clojure immutable is on by default, and that is good... but I don’t think I’ve observed, particularly, better code & lower bug rates in the cljs code I’ve worked on as a result...


Oh yes, definitely there are plenty of other tradeoffs involved with CLJS vs JS that are much more nuanced, and as you said, immutable by default is by no means a silver bullet. There's a reason why I still by choice use JS for certain projects when CLJS exists.

I was only lamenting what I consider to be the only major deficiency in JS when it comes to writing functional code, one that I haven't really found any viable way to work around, despite being quite happy with most other aspects of the overall experience of writing functional JS.


There are remote Clojure jobs. Some guidance here https://purelyfunctional.tv/


Thanks but I'm highly skeptical of the wording, it sounds suspiciously like a pyramid scheme. If they really were in contact with remote Clojure jobs, I don't know why they would hide them behind a free email course. That doesn't seem to benefit the employers or employee candidates, only the people behind this website.


The site's run by a well-respected Clojure developer and educator called Eric Normand. This is not a pyramid scheme, and Eric makes no guarantees of finding Clojure-related work – only that the content will be useful if working in Clojure and FP is of interest to you.

I've found the free drip-fed email course helpful. The free video content is also well presented, as are Eric's talks at Clojure conferences on YouTube. I plan to subscribe, but the video content is also downloadable individually if you want to skip the free tips and offers in the intro emails: https://purelyfunctional.tv/courses/


It might not be a pyramid scheme but the phrasing is certainly very fishy and scammy:

> It can be the first step in a more fun and creative career.

This phrasing is everywhere in the ad. To me, it's just someone trying to make money from teaching a language. Nothing wrong with the teaching part but the hidden-yet-never-spelled-out-promises-because-of-legal-exposure feels very disingenuous and scammy to me.


well-respected Clojure developer

With no offence, but what quality code/library/framework has he shared or produced?


I respect him as a developer for his enthusiasm and ability to convey complex concepts simply:

Building composable abstractions https://www.youtube.com/watch?v=jJIUoaIvD20

Category Theory From the Universe Up https://purelyfunctional.tv/courses/category-theory/

Data modelling in Clojure https://purelyfunctional.tv/courses/modeling-solitaire-in-cl...

To me instruction like this is worth more than a library with a few thousand stars on GitHub.

The FP industry could benefit from more programmer-educators that don't actively obfuscate concepts in mathspeak. (That sometimes has its place too, though, and there are other resources that do a good job of deciphering monads etc. without heavy metaphor, like Haskell Programming From First Principles: http://haskellbook.com/.)


FWIW, this answer sets off the scam warning bells in my head.

There are two main reasons I think. First, you originally call the developer well-respected and then when pressed reveal that you really meant "personally like". This comes off as double speak and feels like you just lied in the first comment.

Second and what seals the deal for me, is that you double down on the double speak and argue that your stance is "more valuable". This comes off as highly defensive.

I certainly can't speak for your intentions or the actual content of your messages, but I'm assuming the charitable thing and guess that you might be unwittingly speaking in a way that's putting people off.

That said, these are just my personal gut reactions, so YMMV.


Sorry if it came across that way!

I recognise that it's easy online to mistake enthusiasm for overselling, and that wasn't my intention at all.

I have no stake in this other than to encourage people to give Clojure a try (I just enjoy the language and want to see it grow). I shared my perception that the site owner is well-respected (based on the community's reactions to blog posts, forum posts, and talks), and gave my own reasons (the education style works for me and he speaks with clarity and authority on a topic that can often be mired in academic concerns).

The good thing is that others teach Clojure actively if you're looking for a less job-oriented marketing pitch. For example, https://lambdaisland.com/ is worth learning from (and run by a developer with a popular Clojure project called Chestnut, if that matters to you), http://www.4clojure.com/ and http://clojurescriptkoans.com/ are free practise sites, and the https://www.braveclojure.com/ and Living Clojure books were helpful to me when getting started.


Are you saying it might be a scam because the commentary might be affiliated with the site?


The sad news for Elm/Clojure/Haskell developers is that most of the dev managers are old java/c# folks -- not the sharpest or the most curious folks and they are unlikely to try out functional languages or any new languages for that matter.


I feel your pain but from a different angle, I am trying to find a job right now that is clojure and either its on site in SFO (No thanks) or in London. Breaking in seems hard enough and then hearing stories like this don't instill confidence. I really hate it because going back to dealing with OO is actually painful, it just seems like it's building up a whole big skeleton for little benefit.


I feel the same with not having Clojure around at work anymore after I quit my last job.

That said, at the new place that uses Rails we instilled a culture of avoiding stateful updates, preferring hash structures to mountains of object definitions, and use of functional transforms as much as possible.

Then we needed to ramp up to the next level and chose the JVM for writing concurrent code. But we started with Scala as something that has functional concepts baked in since it's "easier to hire for". Not the same, but there are other paths to dealing with lack of Clojure.

Oh, and the Scala only makes up for part of losing Clojure because we actually use it in a similar way to Clojure plus a bajillion type declarations. With the occasional workaround for a compiler bug (I've encountered three in the past 6 months).


How you deal with two separate tech stacks in single product? I try to shift from Ruby (on Rails) to to Clojure. But I feel hard to rewrite mountains of RoR convieniece and habits into Clojure (1.day.ago, named routes, ActiveMailer, encrypted cookie etc). As I am also partially Java guy, I came to conclusion that migration of project into JRuby and then embedding Clojure parts gradually might ease the transition.


I try to shift from Ruby (on Rails) to to Clojure. But I feel hard to rewrite mountains of RoR convieniece and habits into Clojure (1.day.ago, named routes, ActiveMailer, encrypted cookie etc).

This seems like a bad idea from a business value perspective. What value is delivered by translating mountains of code? Probably none, being honest.

As I am also partially Java guy, I came to conclusion that migration of project into JRuby and then embedding Clojure parts gradually might ease the transition.

Don't transition everything, giant waste of time. Run ruby/rails on jruby, then package the core Clojure logic up as a library, and call into it from rails where needed. Clojure is your core logic, ruby/rails is the web front end to that core.


Dealing with JRuby will just be that much more to manage, but will introduce the JVM in a single app. You don't have to do everything at once if you break into separate apps/boxes/services.

We're growing to the point of needing a few distinct components after building a Rails monolith that already had very strong internal boundaries. As we split out different parts to run on different machines, they will either get an immediate re-write, or eventual re-write from behind the service interface.


It can’t be literally true learning Clojure did you no good... You do need to be conscious in your interviewing, and make sure you have some talking points ready to explain how clojure sharpens your thinking and applies to other languages besides. At that point if the recruiter doesn’t see the fit, you probably want to avoid that employer anyway.


Plus most of modern JavaScript has most of the same benefits as Clojure anyway, especially in terms of FP.

"Modern Javascript ES2020" + lodash + immutablejs

But lodash and immutablejs don't mix ;) and still, with either two, it won't be as consistent.

But nodejs and its ecosystem is just to hard to ignore for web apps, it really has too much good stuff (and bad too).


I am surprised that there are more jobs in Windows and .NET at your place. Java platform is more popular than .NET, and your knowledge of JVM is very valuable. I think you are much better off trying for Java/Scala/Clojure jobs.


Go work for a Java shop, and slowly start sprinkling some Clojure into it.

I mean, maybe you can even do so in a C# shop, ClojureCLR is a real thing.


If you did that you would likely be fired. And for good reason.

Clojure is a language that needs a lot of careful thought before being dropped into a Java shop. It's the complete opposite of Java in many respects and at some point that code will need to be maintained.


This kind of sneaky sneaky subversion is how Linux gained a foothold in corporate IT. And we know how that turned out. This is definitely a method smart underlings can employ to change things for the better.

It is not without some career risks, but it can also open new doors.


I've known more than one developer who successfully did this in their Java job. They were not fired. Some of them ended up speaking at Clojure conferences about it.


ClojureCLR still exists, although it's not as popular as the JVM implementation. Perhaps that could give you a leg up on transitioning.


My gripe with Clojure is readability. Its like the PERL of FP to me. Why is there so much syntactic sugar to achieve the same thing? Like this line from the article: "Eve: Or if you want - no-hash solution." This shit makes me cringe.

Just pick one way to to do something, and make that the default in the language. This is why Python is one of the more popular languages today, you can go from 0 to relatively proficient in no time. No FP lang can claim the same thing. And people wonder why after 50 years FP hasn't completely taken off (unless you count javascript).

I can read 10 programs solving the same problem in clojure and they can look almost completely different. That is bug, not a feature, I'm sorry. Having "freedom" to do things in different ways just adds cognitive load. We already deal with enough option fatigue in our daily lives, why make it a core part of a language?


Readability might be a fair criticism but syntactic sugar is a weird one, there's not a lot of syntax at all.

Multiple ways to do something is a feature, and there's definitely multiple ways to do things in python: metaclass vs class decorators lambdas vs explicit functions (basically the same thing as your no hash example) map/reduce/filter vs list/generator comprehensions


I hate these deliberately obtuse articles about design patterns every time they bubble up each year. Patterns are about naming and communicating design choices. Just shouting 'function' over and over again isn't really relevant.

Like, it's true you can implement a Strategy with a function. And yet the majority of libraries on my current Clojure project don't let you supply a function as a strategy even when it'd make sense. Because none of the authors have made that design decision. Also your commands don't support undo. That'd take _two_ functions. And you know how you might communicate what those _two_ functions taken together do? You could use patterns! So somehow, just having a language feature doesn't MAGICALLY lead one to make one design decision over another. It didn't in the 90s, it didn't in the 00s, and it doesn't now.

Looking forward to 2025's version of this snarky article in Julia or whatever though.


Your right, having a to tool doesn't mean you use it correctly. However, the harder it is to apply a tool the less likely you are to do so. I think the authors point isn't to demonstrate that the design is bad, but rather how it's done in clojure.


C++ or Java or whatever not matching someone's aesthetics doesn't change the fact that providing an interface that accepts a Strategy or works with Commands is a design choice, not a language feature. It doesn't matter how it's implemented. The snippets of code in the GoF book aren't the point of design patterns, they're in no way canonical, and people pretending for _decades_ that they are really grinds my gears.

But not as much as Clojure having no good implementation of the age old 'Readable Stacktrace' design pattern. :)


> It doesn't matter how it's implemented

Well it does, a little bit. If you implement them by aligning rocks on a sunny beach, it might take a tad longer and more prone to bit rot. Java may as well be that for some people.


This article might appeal to some out of curiousity but it is not of much practical value. Design patterns are not a thing in Clojure. The whole idea behind the flexibility of the language is that you don't need a pre-existing pattern to force on your problem; instead, the language makes it possible for each problem to build its own pattern. (And that is the point, I think, in this article.)

I've worked with and around Clojure developers for years now, and no one talks about traditional design patterns. Design patterns add complexity, not simplicity, to a language. By contrast, Clojure solutions are relatively simple. Design patterns often evolve in languages where you struggle against the language's design to express a solution. When a language strips away those obstacles, pre-existing patterns become less necessary.


"Design patterns are bug reports against your programming language."

– Peter Norvig

http://norvig.com/design-patterns/design-patterns.pdf


I guess programming languages then are a bug report against your context free grammar? I think it's safe to say thinking of any particular language as a silver bullet amounts to hubris.


There is a programming language which captures all patterns in its spec? Fascinating.

Alternatively, even if one agreed with the quote, it isn't very useful: it is simply another way to state that no programming language does everything.


No, the idea is that your language should be able to express patterns in the language. Then they're not patterns any more—they're libraries! Working with an explicit abstraction from a library is far more pleasant than working with an implicit abstraction from a book.

The way to achieve this is emphatically not adding patterns to the language spec. Instead, you want small and simple languages that can grow—languages flexible enough to add new abstractions that let you write code the way you want.

"Growing a Language"[1] by Guy Steele expounds on this and, as a bonus, is the single best technical talk I've ever watched. Highly recommend watching it[1] or, if you're pressed for time, reading the transcript[2].

[1]: https://www.youtube.com/watch?v=_ahvzDzKdB0

[2]: https://www.cs.virginia.edu/~evans/cs655/readings/steele.pdf


> There is a programming language which captures all patterns in its spec?

No, but see https://blog.plover.com/prog/design-patterns.html and the follow-up https://blog.plover.com/prog/johnson.html

They're both a bit long, so here's what I think is the key quote (from the follow-up):

[W]hen pattern P applies to language L, then, to the extent that some programmer on some project finds themselves needing to use P in their project, the use of P indicates a deficiency in language L for that project.

The absence of a convenient and simple way to do P in language L is not always a problem. You might do a project in language L that does not require the use of pattern P. Then the problem does not manifest, and, whatever L's deficiencies might be for other projects, it is not deficient in that way for your project.

This should not be difficult for anyone to understand. Perl might be a very nice language for writing a program to compile a bioinformatic data file into a more reasonable form; it might be a terrible language for writing a real-time missile guidance system. Its deficiencies operate in the missile guidance project in a way that they may not in the data munging project.

But to the extent that some deficiency does come up in your project, it is a problem, because you are implementing the same design over and over, the same arrangement of objects and classes, to accomplish the same purpose. If the language provided more support for solving this recurring design problem, you wouldn't need to use a "pattern". Consider again the example of the "subroutine" pattern in assembly language: don't you have anything better to do than redesign and re-implement the process of saving the register values in a stack frame, over and over? Well, yes, you do. And that is why you use a language that has that built in. Consider again the example of the "object-oriented class" pattern in C: don't you have anything better to do than redesign and re-implement object-oriented method dispatch with inheritance, over and over? Yes, you do. And that is why you use a language that has that built in, if that is what you need.

By Gamma, Helm, Johnson, and Vlissides' own definition, the problems solved by patterns are recurring problems, and programmers must address them recurringly.

If these problems recurred in every language, we might conclude that they were endemic to programming itself. We might not, but it's hard to say, since if there are any such problems, they have not yet been brought to my attention. Every pattern discovered so far seems to be specific to only a small subset of the world's languages.

So it seems a small step to conclude that these recurring, language-specific problems are actually problems with the languages themselves. No problem is a problem in every language, but rather each problem is a red arrow, pointing at a design flaw in the language in which it appears.


+1 on Peter Norvig's remark on design patterns.


[flagged]


Norving [sic] has no idea what he's talking about.

There's a sentence I literally never thought I'd hear anyone ever say.


I think most Clojure devs would definitely agree with Norvig on this one (and on most things -- Norvig does actually know what he is talking about.)

Design patterns are indeed common and necessary in some languages that are not as flexible. But few languages are as flexible as a lisp, with all the pros and cons that brings. Focusing on re-usable patterns to force on very different problem domains is counterproductive in a language that gives you much better (and more creative) ways of solving problems.


Clojure / ClojureScript is fantastic for its simplicity.

It takes a while to overcome education and job conditioning and take hold. At first, you're like, ha ha, this is not real. Then, you're like, well, this isn't real but it can inspire some changes in the way I program. Then, you notice yourself doing stupid busy-work in Java or Perl and think, hmm. Hmm. Then, it's like, ya know, this entire project I'm working on would have been sooo much simpler in Clojure. Then, you're like, screw it, I'll just do this minor JDBC data migration or little process-simulation webpage in Clojure. whee! And finally: there is just no other way. Bring it on! Any task, it comes out better and sooner and much, much smaller in Clojure.

But those stages may take years.


Awesome. All "Gang of four" patterns are just functions !


Wasn't that the joke when the book was first released? All design patterns merely handle the lack of anonymous and first-class functions.


..and closures


... and pattern-matching. But yeh, patterns are a sign of a weakness in the language. And it's not infrequent that patterns really turn out to be anti-patterns.


> But yeh, patterns are a sign of a weakness in the language.

That line of reasoning never ceases to be amusing by how silly and self-defeating,particularly as those who make those claims try to pin ignorance on others while manifesting their own ignorance. They seem to be entirely oblivious to the fact that the main goal and usefulness of patterns is to communicate intent and provide semantics and use a common language to describe common problems. A function is a function but a strategy pattern isn't a state pattern. Those who miss this fundamental difference are totally oblivious to what design patterns actually are.


The point is that patterns shouldn't be patterns in books—they should be abstractions in libraries. You know what's better than having a shared vocabulary you expect everyone to know from a book? Having a shared vocabulary defined in the language and accessible not only to programmers but to the compiler and tooling as well.


> The point is that patterns shouldn't be patterns in books—they should be abstractions in libraries.

And how you go about developing those "libraries"?

By writing code using the programming language, isn't it?

Just because C++ and Java and Python and many other programming languages added support for iterators and generators it doesn't make them out to be less of a design pattern. Heck, supporting emcapsulation and composition and information hiding doesn't make a facade pattern, as well as its concept and the semantics of implementing one, magically disappear.

This fundamental fact regarding design patterns is what these self-important fools miss. While they are too busy grandstanding with their criticism, they are actually showing off their ignorance and demonstrating they don't even understand the basic problems solved by design patterns, which are orthogonal to programming languages and their features.


> A function is a function but a strategy pattern isn't a state pattern.

Funny you should mention that. What does "state pattern" communicate about the design, that "state machine" does not? Because state machine is a well-established term, applicable across paradigms.

And what can you communicate with "strategy pattern"? I mean, pick a design for solving a problem (any problem), and explain the design in writing using the words "strategy pattern". I bet I can rephrase it to be at least as simple, and use common-language terms that predate the "strategy pattern".

I've heard people try to take this stance before, that "design patterns are a way to communicate your designs", but to me, it doesn't hold water. How do you communicate your designs simpler, with them?


Right, a function isn't a pattern. But a pattern in the common usage is some functionality that needs to be communicated outside the core language. In languages that offer that functionaliry in the core, I would argue there no longer "patterns". I don't think many of the gof patterns are remarkable in a modern Language like clojure, because the options are obvious.


It should be clarified that the whole thing is about functional patterns in Clojure that are expressing same functionality as well known OO patterns in Java.

Adding "it's just..." in front of functional patterns doesn't make them non-patterns.

Patterns are named ideas on how to approach/solve similar problems.

They are not tied to OO programming, Java, they are not good or bad per-se; it's just a cookbook with recipes that have names.

Otherwise nice format, I like it.


Presumably the point is that most functional programmers wouldn't have bothered giving dedicated names to, say, “strategies” or “factories”, more or less the same way nobody would bother calling “(a + b) / 2” the “average pattern”.


> nobody would bother calling “(a + b) / 2” the “average pattern”.

don't you mean.... the arithmetic mean?

https://en.wikipedia.org/wiki/Arithmetic_mean

Oh my god, and people bother themselves calling the addition o sequences of numbers as summation.

https://en.wikipedia.org/wiki/Summation

Where does this madness end? These morons even bothered themselves forming whole fields in mathematics by studying adding numbers

https://en.wikipedia.org/wiki/Series_(mathematics)

Why is humanity so wrong about such a simple concept? Why is everyone bothered to give dedicated names to concepts you fail to understand?


The mean is an precisely defined operation in mathematics, not a vaguely defined “pattern” in software engineering.

I insist: You only need “patterns” when you can't articulate your ideas precisely in a formal language, such as a programming language or mathematics.


Maybe they would call it a monoid or something much clearer like that.


Fortunately you have about an hour to edit your comment into something that, at least, is not patently stupid.


> But a pattern in the common usage is some functionality that needs to be communicated outside the core language.

What a truism. Programming languages exist to implement functionalities outside of the core language. So what? Does this mean that software projects aren't designed, and parts of the design may not be shared and integrated in other projects? Those working on software projects still need to discuss design issues, and it's easier and more efficient to assign names to recurring patterns. Those who don't understand this issue and opt to manifest their ignorance by criticizing the existence of patterns are simply fools who try to feign competence by ridiculing the consequences of their own ignorance.


Names are useless unless they convey a precise meaning. And, if you can't write down that meaning in a formal system (such as a programming language or mathematics), then it can't be that precise after all.


> Names are useless unless they convey a precise meaning.

They do convey a precise meaning. You simply fail to understand it, and even make it your point to complain about something you systematically fail to understand where you stand on your dunning-kruger corner.


> They do convey a precise meaning.

Then formalize it. Mathematically.


You are aware you're asking to "mathematically formalize" algorithm constructs, right? Either you know nothing about the subject or are trolling this thread in spite of being completely removed from the field.


Algorithms are mathematical objects, and they sure as hell can be formalized. Alas, software design “patterns” aren't algorithms. And, so long as they resist formalization, they are non-ideas.

Accusations of trolling are completely unwarranted.


> the main goal and usefulness of patterns is to communicate intent and provide semantics and use a common language to describe common problems

No, that's the role of programming languages. If you can't do it in your programming language of choice, you aren't using a high-level enough one.


In a strong language patterns don't exist? Everybody always solves every problem in a completely unique way?


Two people shouldn't be solving the same problem. So, yes, in a perfect language no two people would solve a problem in the same way.


So no two people would ever use lists or maps?


What pattern is there on using those structures? It's barebones syntax and nothing else.


No idea what you mean by “strong language”, but a high-level programming language is one in which patterns are expressible directly as libraries or frameworks.


Not in the slightest. Their strategy pattern example handles the case where you're passing in a strategy object using an interface with a single method - which in almost all mainstream OO and pseudo-OO languages today you could accomplish with lambda syntax.


Comapred to any tech talk videos, This article convinced me to try Clojure almost 2 years back. Very well written and practical.


This is a restatement of the well-known equivalence between so-called “objects” and “functions”. Both are idiosyncratic names for the same thing: procedural values.

The condescending tone of the post is completely unwarranted, especially since it glosses over the real limitations of procedural values as abstraction building blocks, which don't magically go away when you rename them from “objects” to “functions”. In no particular order:

(0) There is no modular way to distinguish procedures that meet a nontrivial specification from all other procedures. Guaranteeing that a procedural argument never takes a silly value requires whole-program analysis, which doesn't scale.

(1) There is no modular way to communicate the fact that two or more procedures manipulate similar or related data structures. Try implementing abstract data types with binary operations (e.g. mergeable heaps) as objects.

(2) There is no modular way to control which procedures exchange information with one another. Say Foo is designed to communicate with Bar. I can replace Bar with a type-compatible but ill-behaved impostor Qux. As far as Foo can tell: https://az616578.vo.msecnd.net/files/2016/09/26/636105299923...

The cure for this illness is using abstract data types, not objects.


Can you enlighten me as to how ADTs differ from specified contracts like spec [1]?

[1]: https://clojure.org/about/spec


Abstract data types guarantee that nobody besides the implementor can violate the contract. They compartmentalize what you have to verify.

Without abstraction enforcement mechanisms, an abstraction you have correctly implemented can still misbehave, because someone else has tampered with its internal representation.


And here I thought ADT almost always meant "algebraic data type."

Regardless, Rich Hickey's last talk (last month at Clojure Conj) offered a counter argument, why ADTs are usually not the best way to organize software (as part of his larger discussion against static typing).


> And here I thought ADT almost always meant "algebraic data type."

It depends on context

> why ADTs are usually not the best way to organize software

He clearly hasn't proven anything about his code.


> He clearly hasn't proven anything about his code.

Is that a bad thing? It seems like many people are able to write software that works well and gets the job done without "proving anything" about their code in the way you're describing. Personally, I'm fine with not proving anything if I can deliver quickly and everything works, but I'd like to be convinced otherwise if there's real value there.


Formal verification of code has been the elusive Graal seeked by many for now a few decades.

It’s a mirage to which many have succumb but like in the desert most died of thirst trying to catch it.


For basic infrastructure such as compilers and standard libraries (at least of data structures and algorithms), not providing proofs of correctness is outright criminal.


It's not though is it... You know, because there aren't actual laws about it.

Let's try not to make inflammatory statements.


I'd be curious to see if the Scala version would be just as terse as the Clojure one, of course following the FP paradigm as well as possible .. any resident Scala gurus?


There's a master's thesis by Fredrik Skeel Lokke which is an extensive discussion of GoF design patterns in Scala: https://www.scala-lang.org/old/sites/default/files/FrederikT...


combinatations ?




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

Search: