This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-09-09
Channels
- # beginners (376)
- # cider (7)
- # cljs-dev (4)
- # clojure (96)
- # clojure-dev (7)
- # clojure-finland (2)
- # clojure-spec (1)
- # clojure-uk (15)
- # clojurescript (54)
- # cryogen (1)
- # defnpodcast (2)
- # docs (4)
- # emacs (1)
- # fulcro (2)
- # hoplon (15)
- # lumo (19)
- # off-topic (28)
- # om (3)
- # pedestal (2)
- # portkey (6)
- # proton (2)
- # re-frame (34)
- # reagent (4)
- # ring (3)
- # spacemacs (5)
- # unrepl (3)
While it's written in CL notation, the best book on macros I know of is Paul Graham's "On Lisp."
Clojure's semantics differ from CL's in many respects, but when it comes to macros themselves they are very similar, so "On Lisp" is essentially as useful for Clojure as for CL.
(Not about macros of course, which SICP doesn't even touch on- I mean that most of what SICP teaches is transferrable to Clojure)
What is the purpose of a docstring? What are we trying to convey beyond what the code does already? In Dynamic languages i feel compelled to mention the function paramaters types and its return type, which seems like an admission that I should be using a static language. Beyond that, i generally try describe what a function does at a Domain Level. However i notice a lot of reputable Clojure Devs dont bother with them at all. Is there a way to objectively look at this, or is it all context specific?
Re the types, I think spec is a better way to say those things now and if you have them, doc automatically includes them
@drewverlee code doesn’t always convey its intent at first glance. For example, if I look at the code of clojure.core/map
, I am glad it has a docstring 😄
I'm trying to do something somewhat related to chess, where I'm generating all possible moves a piece can make. For example, if I have a king at position [2 2], that king can move to positions [1 2], [1, 1], [2, 1], [3 2], [2 3] [3 3], [1 3], [3 1]. I can describe this easily logically (the set of all moves where y2 - y1 <= 1 and x2 - x1 <= 1), but I'm having trouble executing in clojure. I'm trying to come up with some way to do this generation for various pieces (king being the simplest), does anyone have any ideas how I might go about it? Right now I'm messing with iterate but I just can't seem to get this to work.
@nimblerabit why not express the moves by distances and calculate the positions based on the start position?
@hmaurer I think it would abstract better if you left the math to the "mover" function, that way the moves themselves only differ y the precise thing that makes them different (the distances) and the mover can do the actual calculation instead of having the same logic in every one
this could get complicated with other pieces where you’ll have to take “blocking” into account though
@noisesmith yep; ideally you would have some sort of composable mover functions, right?
if the pieces moves are just relative numbers, both the "threat / block" function and the "move" function can reuse the same data
if the pieces moves were a function, you can't reuse the inside, so you end up copy/pasting it into the threat / block code
(or doing redundant calculations I guess)
@noisesmith how would you abstract the movement of a bishop, which can move diagonally until it reaches an enemy piece?
So that solution makes sense to me, but the reason I didn't go in that direction is I was unsure how to do something like the queen that can move different number of spaces
@hmaurer as I said, a "distances" data to get all the possible distances (if they don't leave the board or pass through a piece) and then a "block / threat" function which tells you where there's an intersection (if any)
@nimblerabit well, it's possible to iterate them completely - since the board is only N tiles
@noisesmith how does that constrain motion along a particular path, e.g. diagonals only?
@hmaurer by only including the diagonal steps in the comprehension
a for, like yours, that generates moves where the absolute value of the x distance and y distance are always equal
so, the lazy way (logic wise) is (for [x (range -11 12) y (range -11 12) :when (= (Math/abs x) (Math/abs y))] [x y])
of course there's a more efficient way to calculate that, but that's concise
and since that's all the moves for the bishop, it only needs to be calculated once
and the queen moves can be calculated by concatenating bishop moves and rook moves
Alright I think I follow what you're saying here, I'm going to give it a shot. Thanks for the help.
@hmaurer (concat rook-moves bishop-moves)
or (distinct ...)
if you really can't repeat the [0 0]
union on lazy-seqs isn't good
@noisesmith ah, why so? doesn’t work?
clojure.set functions silently generate garbage for inputs that are not sets
oh, I guess union actually works here
but I consider that an accident, not something I can count on
I guess sets make sense
Calculating chess moves is a fun problem though; I tried to do that a while back in javascript and it’s non-trivial to do cleanly
(but none of the code so far, including yours, returned sets)
Actually, I wonder what the cleanest way would be to write a “line of sight” function for a 2d grid like a chess board
right, and there's the one piece that doesn't have a line of sight constraint
My actual task is creating a program that determines reachability (every spot a piece can reach in one move) on a 3d board, for any arbitrary piece (can have user defined movement capabilities). It's a fun problem so far.
Ahh that's what my professor calls it, it's a 3d grid of x, y, z positions
Nah it actually has nothing to do with chess
just a useful jumping off point for modeling this
@drewverlee How much code should be commented is a subject on which opinions vary widely.
I think there's some truth to the idea that too much commenting is a bit of a code smell- ideally the code would be self-explanatory.
I see a lot of code written by people who internalized that idea, but then didn't really work very hard at making the code clear...
The problem with comments/docstrings/non-executable documentation in general. is that they can go out of sync with code pretty easily if people aren't diligent about maintaining them. And an incorrect documentation is worse than no documentation at all.
I try to always document protocols, other things mostly just as needed
We butt heads about this occasionally- one of them was reviewing some code I wrote and said "I'm never going to read all that... I find comments like that painful" about a comment I'd made.
I looked at it and was like... it's a four line comment, each about 60 characters of actual text.
Even though I think that's kind of weird, if he's not going to read my comments they aren't going to be very useful to him if he has to work on that bit of code.
there's nothing inherently stateful about protocols, but I like the way component uses a protocol
protocols let us reuse code with better separation of concerns than you would have with inheritance (usually) - by thinking about the actions you define alone, as an abstraction, and encouraging you to write code in terms of only those actions
and not implementation details of the things you are using to fill them
protocols are why we can map or reduce over just about anything
So, before I was using (def state (atom {})), and then I read their code and Riemann, so I changed to protocol and record, and pass through arg (the record) to execute functions
that's definitely true - you can of course do the same thing by passing the stateful things as args
but having a protocol and record helps clarify what the abstraction boundaries are (and how to properly extend, etc.)
Guys, I’d like to have some advice here. I’m experimenting some other things alongside with learning Clojure. Among them is Continuous Integration (using Jenkins) and automated acceptance testing. I would like to build a pipeline like this to automate : unit test (lein test) -> build (lein ring uberwar) and checkstyle (any style checking tool for Clojure you’d recommend?) -> deploy to staging environment (with database and everything setup) -> acceptance tests (using gradle and Java with RESTAssured framework) -> deploy to production environment What do you think about this? Am I missing something? Is this approach correct for automating the acceptance tests? Thanks!
@lvbarbosa I have a task defined in project.clj that runs clean, cljfmt fix, check, test, eastwood (in that order, failing if any of them fail)
eastwood is the style checker I recommend
so you think it’s better to collapse together all the lein tasks?
in one step
I mean, in one build task
I do that because I like to run it regularly (usually each morning) locally while developing
:aliases {"morning" ["do"
["cljfmt" "fix"]
["clean"]
["check"]
["test"]
["eastwood"]
["repl"]]}
so I can just run lein morning
, get my repl, and start working
or fix things before I go further if I discover my work from the night before (or whatever merge I might have done) put something in a bad state
got it
you could absolutely just run lein do check, test, eastwood, uberjar
from the build task
it will fail if any of the steps fail
What do you think about the rest of the pipeline? Does it sound nice? I’m thinking about REST Assured because I know how to use it
maybe using a similar clojure framework would be a better learning experience
or maybe it’s too much information
I don't know that deployment framework / acceptance test framework and I don't know much about the alternatives either
I do know that CircleCI is implemented in clojure, so I would be surprised if their support for clojure deployment wasn't top notch
well no, I did use jenkins, but it could have been a shell script as far as I was concerned (it tested, built a jar, scp'd the jar to a server, sent a rest command to make the container reload) - I assume it has actual features we weren't leveraging properly
Interesting
That’s the situation here on my thoughts. Jenkins is just doing what I could do in a shell script
I’m doing it just for fun/learning
when you try doing it with a function and it doesn't work, or you need some sugar around a particularly verbose api
IMHO macros are for two kinds of programmers: people who are just starting (so you get some intuition of their uses and limits, helping you understand what goes on when you use other people's macros) and those who are very experienced (needing to make a new syntax to simplify a codebase)
if you don't need a new syntax, or compile time evaluation, you don't need to write a macro
and most people who think they need those things still don't need them
Well, at least for now I'm using functions only.. if I get to its limits I expand to start learn about macro
I've had the painful experience that using a powerful feature just because tends to lead to less than satisfactory results
@noisesmith I agree with the general thrust of what you're saying, but...
I do think that you probably shouldn;t be writing macros in production code unless you already know when to write them though 😉.
OTOH, you'll never really learn when they are a good idea if you don'y write some that you shouldn't have, and learn how and why they can bite you.
I've found that I rarely find macros provided by libraries useful, usually the get in the way
The main thing about macros, I think, is that you shouldn't reach for them unless there's no really good alternative.
As a data point, our 65K line code base has just 23 macros (compared with about 3,000 functions).
And those macros are nearly all with-*
syntactic sugar for an underlying function.
A friend said that macros are just a simple "replace"... I think it will take time that I understand where to use it... for now functions, records and protocols are being enough
And higher order functions can often do what you want a macro to do while still being first-class citizens at run-time (which is valuable.)
(defmacro alias-macro [new-name old-name]
(defmacro new-name ['& 'body] '`(old-name @body)))` what am i doing wrong here? (just an academic exercise)
I see, I think I understand a little more... but just writing it I will understand better... I will start to write more macros to reach its limits
@rcustodio Probably worth abusing macros in order to discover their downsides 😉. I think everyone who has written a lot of Lisp has done that at some point.
One of the very nice things about Lisps, and Lisp-like languages is that they make many things first-class at runtime that are not in most languages.
To pass around functions in C you have to go through gyrations that make it hardly worthwhile in siple cases.
In a Lisp (and I'll broadly include languages like Python and Javascript as basically Lisps, if not very good Lisps) functions are first-class. You can pass them around just like anything else. You can have functions that return functions.
So you need to understand that when you write a macro you break one of the fundamental "nice things" about Lisp.
It's worth it in some cases- especially when you need to control when forms are evaluated, the most common place I write macros for.
Or when you want to abstract certain types of cleanup away, even in the face of exceptions (what @seancorfield was referring to, I think.)
You could do the same thing with higher order functions, but what a pain... with-* is so much nicer.
And I'm inclined to think it is the most comprehensive loop construct I've ever seen....
(loop for i from 1 to 100 if (evenp i) minimize i into min-even and maximize i into max-even and unless (zerop (mod i 4)) sum i into even-not-fours-total end and sum i into even-total else minimize i into min-odd and maximize i into max-odd and when (zerop (mod i 5)) sum i into fives-total end and sum i into odd-total do (update-analysis min-even max-even min-odd max-odd even-total odd-total fives-total even-not-fours-total))
The important thing to note here is that this is, past the first paren, not Lisp syntax.
It would be very ugly to modify the reader to understand loop- which is why it's a macro.
The only time I've ever used macros is when generating interop glue code and slurping files for CLJS builds~
@tagore I’ve seen a few Clojure DSLs being based around keywords (instead of an approach like loop which really embeds a language). Is that a philosophical difference in clojure?
I can't tell you what the Clojure philosophy is (I can tell you what I think it looks like.)
@seancorfield might be a better guy for a definitive answer to that question.
also, since you seem to be familiar with common lisp: is there any interest for a new lisper/clojurist to learn CL?
Yes, absolutely, just as a new Clojurian should learn basic Scheme (which takes about five minutes.)
You need to be able to read what the people who established that tradition wrote, because many of them were brilliant, and Clojure is a step in that tradition.
Hmm.... ES6 probably can't get pass the clojure reader, since there are no reader macros in clj I doubt you can do that without wraping it in a string
For instance, if I talk about the differences between the CL Loop macro, and the later Series macro (not part of the spec...)
@tagore it’s quite funny; I have been “aware” of lisp for many years now, but never got into it because I felt the absence of infix operators and the abudance of parentheses would bother me. Clojure, and to a lesser extent parinfer convinced me to make the jump, and I’ve been surprised how natural it feels
If you understand Clojure you already understand every construct used in SICP, for instance, and did from about the first hour you spent learning Clojure.
I actually like Clojure's data DSLs since you can build/manipulate them using the rich built-in functions instead of string concat and regexes.
gives me nightmares just thinking about the builder and factory classes in traditional OOP code...
34. The string is a stark data structure and everywhere it is passed there is much duplication of process. It is a perfect vehicle for hiding information.
106. It's difficult to extract sense from strings, but they're the only communication coin we can count on.
The first step here is to write programs that are functions of programs, and that return programs.
If your program is just a very natural data structure in the language you program in this becomes trivial. Thus Lisp.
To be a Lisp programmer is to be a programmer who writes programs that write programs, until they hit the base case, whatever that might be.
51. Bringing computers into the home won't change either one, but may revitalize the corner saloon.
OK then... I've got a computer in my pocket and that is going to kill the corner saloon.
56. Software is under a constant tension. Being symbolic it is arbitrarily perfectible; but also it is arbitrarily changeable.
49. Giving up on assembly language was the apple in our Garden of Eden: Languages whose use squanders machine cycles are sinful. The LISP machine now permits LISP programmers to abandon bra and fig-leaf.
The poor Lisp machine... turns out that the machine is now so fast that the Lisp machine is irrelevant.
Are there any good resources about TDD in Clojure? In Java, I can inject mocked dependencies in an object. In Clojure, I don’t feel like doing this in a function. If I always pass the dependencies as function arguments, I’ll end up with a lot of extra arguments. I’m looking for guidance, examples of beautifully designed code that has a nice unit testing code coverage
Because I don’t “declare dependencies” in the function arguments, my code is not testable and I don’t write unit tests
Indeed I should be writing the tests first, but I was just learning and would like to add the tests to my project
The problem I have with TDD is that I wind up with hundreds of tests that have to be deleted or maintained, but are not actually important past a certain point.
Have you tried just opening a REPL and using it as you would use tests in a TDD scenario?
There are state management management micro frameworks that handles dependency injection in Clojure, take a look at stuartsierra/component
and weavejester/integrant
I do develop with a REPL open on Atom (forgot the plugin name), but I don’t feel like that is enough, you know… I feel like there’s something missing
@tagore TDD gives you reproduciblity though, which might be useful when refactoring. Do you not not miss that part?
especially because TDD helps me a lot with the class design
My issue with TDD (well, one of my issues with TDD) is that it looks to me like a harness for running code... not something anyone with a REPL would have bothered with. But it leave cruft behind.
I wrote a large and comprehensive computational geometry library a few years ago, in C.
It is definitely an overkill to test what I am doing right now
I am building a very simple RESTful API
there’s no complex business logic, it’s basically a CRUD with authentication and authorization
But I’m trying to do it with unit tests for learning purposes
The thing is.. how do I test a function that invokes a database module?
Well- unit tests are worth writing (though not as many as TDD would have you write, IMHO)
I’d normally mock that invocation, but the function is choosing which function to call
I thought about putting the dependency in an argument
and that looks very ugly
@akiroz pointed me to some management libraries
I would love to see examples of what people consider good practice
But the main question is, if your endpoint is exposed to the world, how does it handle input you didn;t expect?
librairies @akiroz pointed out essentially boils down to putting the dependencies in an argument
Are your unit tests going to handle that? Only if you have thought very hard about them.
:thinking_face:
Because your tests are likely to recapitulate your assumptions about what you've written.
@tagore I feel one area where unit tests are useful is when working on someone else’s code. It gives some degree of confidence that you didn’t break the first guy’s expectations about how the code should behave
@lvbarbosa you should take a look at with-redefs
https://clojuredocs.org/clojure.core/with-redefs
I don't think there's anyway around putting deps in arguments, if your function has too many deps maybe it's possible to split it up...
I would like to show you guys the code I wrote before, but I’ve been rewriting this application from scratch and I am on the start of a new cycle. This might sound dumb, but I like to learn this way hehe. I always learn something new or at least ways of how not to do things. On this turn, I would like to introduce TDD from the beginning, to influence the way I design my functions
and even integration tests that basically repeat what unit tests checked, but on a higher level
But what do you guys think about “system tests” then? I am thinking about doing this too
like testing the RESTful API
deploying on a staging environment and running a test suite that issues requests and checks the expected responses
There’s a book… let me try to find its title
Growing Object-Oriented Software: Guided by Tests Book by Nat Pryce
The message on that book is on my head all the time
It’s basically: “Start writing the use case system test. Then, implement the functionality writing unit tests."
Does that apply to FP? Looks like.. but I am not feeling comfortable with unit testing yet here. @tagore is driving me away from them 😁
But the fact is that we rely more on manual testing than on automated tests before we push to production.
@tagore doesn’t that take you a lot of time?
isn’t there a way to automate it?
But we always push to staging and have a junior developer bang on it before we push to production.
We have far less stringent uptime SLAs. Even so we do all unit tests on most libraries (but we're definitely not TDD). We also have a test harness that automatically calls all REST functionality on every endpoint and that runs at least after every push to staging. devs can trigger that harness to run whenever they want. We have jmeter testing on some of those end points after the functional validation. And we have human and automated application testing on the end user UI. Unit tests take seconds to run. API testing is minutes. Automated (Selenium) UI testing is minutes. And the manual UI testing takes days.
But the reality of working in a venture-backed startup is that you inherit the CEO's code...
I hear you. We rewrote the testing frameworks and boosted the coverage over the course of roughly a year with offshore assistance, but that was after the investment was in the bank.
Yeah- on some level just getting the features out in order to get customers is what matters.
My strategy for that would be to start setting aside a little energy in each sprint, and apply it to pay down some of that tech debt. If your CEO/CTO will allow it. Depends how tight the money is. But arguably the debt is hurting you now by making feature development more trouble than it ought to be.
@gonewest818 Yep, that might be a reasonable approach, but it's not a good one here.
I'm not sure this would be a generally good idea, but it's a chance to reset and enforce some standrads.
Honestly, the most efficient path would have been to continue with AngularJS, but the CTO got a hair up his ass about React so I took the opportunity.
Far easier than trying to convince him of what he already knows, which is that the codebase is shit.
Well, I'm just putting money in the bank in order to do my own (probably CLojure-based) thing.
(with my admin hat on: we're pretty relaxed about discussions at weekends but a lot of this really belongs in #off-topic rather than #beginners -- thank you, for consideration with future discussions!)
It doesn't mater much though- one you've programmed enough you start to understand that languages are just notation + platform.
Ok, fair. Then getting back to what @lvbarbosa originally asked: "how do I unit test a function that calls a database?" then my suggestion is, wrap the test with a with-redefs
to temporarily substitute whatever calls the database with a lambda. The lambda returns test data without any external dependencies. Do as many cases as you feel would be necessary.
with-redefs comes with a lot of problems
If possible, separate out the database interaction to a separate component, perhaps defined with a protocol, and then it's easier to mock, or point to a testing database.
Then your function-under-test would be passed that component and call a function on it (to read/write on the "database") and you can test it with a mocked component of some sort.
Now, if you really want functions that cause side-effects to have unit tests there are ways to do that.
You can, for instance, make them emit data that describes the side-effects they want to cause.
right, the interpreter pattern
as long as the interpreter part is simple, it works great
There are some real advantages to doing that, but it does make things more complicated.
@tagore completely tangential question, but how would you deal with functions that “do some writes, do some reads, do some writes” with that approach?
And then, based on the data you got back from the read, emit data that requested a write.
@tagore that sounds like an interesting approach (both modelling side-effects explicitly and what you just said); I’ll try it out
Instead of having to mock a database, etc, you just test that your code emits the requests you expect it to.