18 ms·
Clojure Design Patterns
- marvel_boy 9y agoAwesome. All "Gang of four" patterns are just functions !
- jeremiep 9y agoWasn't that the joke when the book was first released? All design patterns merely handle the lack of anonymous and first-class functions.
- ssfak 9y ago..and closures
- virgilp 9y ago... 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.
- geezerjay 9y ago> 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.
- catnaroek 9y ago> 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.
- blain_the_train 9y agoRight, 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.
- geezerjay 9y ago> 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.
- catnaroek 9y agoNames 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.
- geezerjay 9y ago> 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.
- Scarblac 9y agoIn a strong language patterns don't exist? Everybody always solves every problem in a completely unique way?
- marcosdumay 9y agoTwo 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.
- guelo 9y agoSo no two people would ever use lists or maps?
- marcosdumay 9y agoWhat pattern is there on using those structures? It's barebones syntax and nothing else.
- catnaroek 9y agoNo 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.
- HumanDrivenDev 9y agoNot 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.
- deleted 9y ago[deleted]
- truth_seeker 9y agoComapred to any tech talk videos, This article convinced me to try Clojure almost 2 years back. Very well written and practical.
- _diyu 9y agoClojure 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.
- tejinderss 9y agoLearning 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.
- 8ytecoder 9y agoYes, as someone whose primary languages are Ruby and JS, I agree. It has made a tremendous change in the way I organise code.
- justbaker 9y agoLisp is fundamental programming knowledge IMO.
- erik_seaberg 9y agoIt's worth noting that most Lisp dialects don't really encourage immutable data, and Clojure seems to be a step forward there.
- ellyagg 9y ago"Design patterns are bug reports against your programming language." – Peter Norvig http://norvig.com/design-patterns/design-patterns.pdf http://norvig.com/design-patterns/design-patterns.pdf
- sidlls 9y agoThere 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.
- marvy 9y ago> There is a programming language which captures all patterns in its spec? No, but see https://blog.plover.com/prog/design-patterns.html https://blog.plover.com/prog/design-patterns.html and the follow-up https://blog.plover.com/prog/johnson.html 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.
- thom 9y agoI 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.
- blain_the_train 9y agoYour 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.
- thom 9y agoC++ 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. :)
- sooheon 9y ago> 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.
- catnaroek 9y agoThis 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/636105299923578088-1610436935_its%20fine.jpg https://az616578.vo.msecnd.net/files/2016/09/26/636105299923... The cure for this illness is using abstract data types, not objects.
- sooheon 9y agoCan you enlighten me as to how ADTs differ from specified contracts like spec [1]? [1]: https://clojure.org/about/spec https://clojure.org/about/spec
- catnaroek 9y agoAbstract 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.
- deleted 9y ago[deleted]
- hellofunk 9y ago
- hellofunk 9y agoThis 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.
- martin1975 9y agoI'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?
- culturedsystems 9y agoThere'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/FrederikThesis.pdf https://www.scala-lang.org/old/sites/default/files/FrederikT...
- based2 9y agocombinatations ?
- fluff-brain 9y agoClojure / 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.