clojure.spec - David Nolen

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi I'm David Nolan I am a software engineer for a company called cognate echt there are software consultancy we are also the stewards of closure and clojurescript I'm the lead developer of clojurescript you might have heard of that because clojurescript was probably one of the earlier sort of communities that sort of fully embraced react it was a very short amount of time before almost everybody was using some sort of thin wrapper brand enclosure script over-reactive and it's still it's still the case today it's probably the most popular way for closure script programmers to do front-end dev because the reactor model is very it's well aligned with functional thinking so in closure script we program using functional data structures and functional techniques and react is a good fit and in fact we we spend most of our time focusing on this sort of more pure aspects of react and we don't necessarily adopt a lot of the other conventions you see in Tipperary typical reactive programs but anyways that that's that's a little bit of context I'm not going to talk about any of that today so even though this is a react and closure and JavaScript thing I'm gonna talk focusing on closure spec and also first before I get started Oh huge how to Peter Brock quits for inviting me I was actually speaking tomorrow at Euro closure and later in the week at reactive cough so if you're attending those you'll see me and speak again but he said hey you should come to Vienna because it's only an hour away so now I'm here I'm sorry if I sound a little bit strange I only slept about two hours and I have a cold so that's why I was like dying from coughs just a little miss before but so why do I want to talk about close respect to a primarily I would say in this audience I mean I hope there's some closure and closure give fans but I suspect most of you are JavaScript programmers so what are you gonna get out about on a talk what are you gonna get out of the talk on code your spec so the cool thing about closure spec is I think I'm gonna demo some stuff I think you'll see that there's some really really awesome ideas here regardless of whether you're from so the dynamic languages programming camp or sort of sort of a more typed for gaming you just can't because regardless of what you're in to actually code your spec addresses some things that aren't typically addressed from either camps it's a very sort of I think fundamentally novel way to think about the problem of the specification of programs so you may have sir if you're in JavaScript probably the most typical thing you see that people spend any time specifying is like foreign validation and there's like 500 form down validation libraries right that's just but that's really only one type of interesting validation that you might do of course if you like type programming languages one probably the most popular compiled to j/s language with types is actually probably I would say typescript right so people who are coming from Java or C sharp they like typescript because it more or less provides I'm a c-sharp or Java light sort of typing experience and people get more confidence about you know is the program going to do what they expect traditionally from a dynamic language brilliant perspective and even if you love JavaScript I actually did JavaScript professionally for ten years I still have to write JavaScript now and then and I actually don't have a problem with the fact that JavaScript is dynamically typed but but there really is a problem here which I would say is the deeper one is it like well it's one thing to say is my program correct or not correct but I would say I think one of the biggest reasons people like specifications via types is that like you have a person on your team you write something then you get shifted on to another project and when somebody else comes on that that if that's more information so you need documentation you need examples but if you have at least sort of some specification whether that's types or whether that's a document that's more information what are the things that we expect this program to do what are its inputs what are its outputs this is really important stuff and in fact I would say even even type programs and non-type Untied programs suffer from the problem that people actually aren't that clear they really aren't that clear about what their program is supposed to do and I think as programmers we often suffer from that because we're sitting there we're like scratching your heads what were they thinking and it's really hard to read people's minds so spec is a step in the direction of making something a little bit more expressive when we sit down to write a program can we be sort of have a little bit more specificity and how we do it and a lot more sort of sort of flexibility as well so here I have I'm running clojurescript this is the latest version of closure script I'm running against a node repple this is what I do all the time I fire up a node ripple and I compile closure script to it and I try stuff so there is a file where I have some examples that we're gonna we're gonna check out you don't need to know that much about closure script I'm not going to show any really interesting programs so don't don't get caught up on the syntax this is purely about how does one go about specifying interesting properties in a program and I guarantee like so I would say in the dynamic world when you do this people people talk about something called test-driven development which I'm not a fan of don't be offended that I said that I just I just don't like it but that's one way people sit around specifying their programs and describing them to each other and this is you're going to see this is a very different way to go about the sort of same activity so here we have I've you know this this is just import statements I have a namespace like I'm demoing this at Vienna j/s I'm gonna do something with something called test check generators which is something like called quick check which you don't have to know you'll get to see what it does so I don't to describe it to you just see that it does something really cool I'm using spec I'm using a namespace called closure spec test so I can test functions that respect and then I just have some pretty printing functionality so when I pretty print this stuff it's it's legible okay so I'm using inside the spec namespace I've aliased it to a shorter thing so that's easier and I have this basic thing that says I want to make a spec and it's called colon colon int and it says you know what i use this spec this is the name of the spec is it and it uses the predicate integer alright so if I'm down here and I go you know integer or what right if I go integer you know foo right false it's just it's just a it's just a boolean function it takes its input and returns true or false okay but specs compose so here I can make a spec that says only even its and so there's another as a Combinator here inside of this spec library says well it's an int and we know what that is because int is integer and it has to be even so if I evaluate this and I go s valid and I go even int and I go one should say false if I do two it's to say true so four feet so what you'll see actually a lot of the things you can do if you if you really know about like very serious like very serious functional type stuff this is the stuff that's like really requires you to go into a dependent typing to get this sort of level of specificity about what your program is supposed to do or what sort of inputs it can take I can make another one that's even even more specific I can say I'm gonna I want a sequence this is like basically the foundation of spec is actually something called regular expressions so whenever I say regular expression people are like scratching their head you're talking about strings right but actually regular expressions go back to linguistics like the mathematical theory of language and they're the far more general than than just strings and in 2011 a computer scientist named Matt might said actually if you if you go back to the 60s people realized if you just add recursion to regular expressions and you tweak a couple things you can get you actually get the full power of a context-free grammars so you can actually if you have recursion and regular expressions you can get context-free grammars and close respect supports this will get to the recursion part here in a second but the point here is I can say this is a sequence star like the cleaning star and this says it's a sequence of of even intz so it's this will match the empty list an empty sequence or only empty list so here if I go S valid and I go this first if I go and I go 1 or 2 this is this should be false if I go to true you know 8 through right so just it just works and then if it's empty it should also work right now and of course when when you talk about regular expressions you often care about you know is it at least 100 or so on and so forth so we actually have stuff for that too so so this won't this one this one won't accept this one won't accept just an empty list whoops typo right and if I go to that works now what's interesting is there are some other fascinating functions here one's called conform and what conform says if you give me the data I'm going to actually use the specification to parse it so it's not going to just not it's going to take the original data and it's going to use the specification to parse it into a effectively a parse tree in this case it's just going to return the original valuable we'll see cases where it doesn't do this so here too and if it's not true right this one's not going to work I get something called invalid of course when weird when we're sitting around specifying programs okay that's cool but the thing that's really annoying and we all know this is when when you do something wrong so even in JavaScript you have basic basic you know parse errors and so on and so forth type errors and things that you can't do that where the language actually told you something but often this is really cryptic undefined is not equal to a function right everybody knows that error right that's not that's not very helpful it doesn't doesn't tell us that much so one thing that's built into spec is because of the nature of the way that we that we parse the the data structure we actually can explain why something went wrong and then here it says you know this empty sequence fails the even earth predicate because you don't have enough of formation if I if I go explain to this is gonna succeed if I go to when I go foo that's gonna say the first value so zero indexed right the first value in that sequence which is foo fails the predicate integer right so it doesn't so you can have a very deeply nested thing and it will tell you the precise path into that structure where it failed I mean how many times have you gotten adjacent response from a server where it's wrong and you don't know where inside of that data it went wrong I guarantee if you've got any dramas could this happen to you a zillion times so this is trying to this is really not just about the program that you're writing you can see that this has implications for specifying things in the wire we're often returned returning non-trivial responses and we want to know what's wrong with the response ok so what's what's the point of doing it this way there's actually a lot of other benefits so when we make these declarative specifications none of the things that I'm writing is executable code it's really we create a object which is like has information about how to conform a value how to explain why it went wrong yadda yadda and so forth under the hood these predicates are actually hooked into what are called generators so if you've never heard of a quick check my absolutely you should this is like the talk where you should run out and watch it tonight John Hughes has a company called cubic in Sweden where they use this technology called quick check which is not just it's not just generative testing it's not just randomized testing what they actually do is they have a specification and from the specification they build what's called a tree of values a tree of values that match this back right and what happens is that you say your function does X and what they do is they say well you say it takes in this type of input and has this type of output and you say it there's a specification for an input and a specification for the output well we can generate the universe of values using a random seed to see if there are any failures right so you produce a bunch of random inputs and what will happen is that of course you screw it up and your functions wrong and because they actually generally generatively built this up the value once it fails they have this amazing tank a technique called shrinking because once you get a failed example it's not useful to get oh it took a thousand values in a list and that failed that doesn't tell you anything you want to know the minimal case right whenever you whenever you file a bug on a open source project people are like please make a minimal case right when you when you add all your libraries and all your build tools it's not minimal right it doesn't help the person that wants to fix the bug you need to know the minimal case so quick check automates the process process of minimizing the failure so they can they can work backwards and find the smallest input that triggers your function to fail the specification so this is actually something that close respect does as well because we use quick check based algorithms underneath but what this means is that you there's lots of cool tricks already we can generate examples as an amazing functions like Clojure spec what you've written is spec you can say give me ten examples of that specification so here we get ten examples of even integers sequences of even integers right that's all this that's all this is so that's pretty awesome so once you make a spec you don't even have to you don't sit around and make dummy data you can say I can just sample the spec to get test data just to try an example let's see that the thing works correctly all this stuff composes I only have 20 minutes so I can't I can't I can't get too crazy because there's other things I want to explain but it's it's extremely expressive I mean pretty much we actually use this to write grammars for the closure of the language so we now use closure spec to actually define our syntax so it's it's it's powerful enough again because we have the power of context-free grammars it's it's flexible enough to basically define the syntax and language that's we're using it for but to give you a sense of this here I can say I can take the even in spec I could and there's a thing called cat which says there's going to be a sequence and this says there's going to be a sequence of even integers and it must end with the string all right so this is this is the type of specification we need to say as many even integers you want but the last thing had better be a string so so here you can see these so here here he says negatives negative six negative two negative two get all so all these examples are just even integers and they have to end in the string so the first part here is the is the actual generated value and this is the thing that you would get if you parsed if you parsed this part zero is the even int and the string was the blank string you scroll down here you've got all these even integers you have the nth you have the a string the even integers are those first even integers and the string part has the string part right so we could keep going but it's super flexible hopefully that makes some sense and then we connect we can actually there's also it's also the whole thing is pretty reflective this is very lispy so I can always ask given some spec I can say tell me what it is so when you're sitting at the repple I mean so we just live at the repple so all these interactions is like a typical thing when I'm writing a program enclosure script I can say show me what that that spec looks like it it says it's you know this spec plus the last thing has to be a string just to give you a sense this is not this is a toy this is like a toy grammar for closure so for example functions look like this enclosure script enclosure so so this is foo a plus a B and that makes a bunch of called foo I can go call foo and it just adds two numbers but this is the syntax defin followed by the name of the function followed by an Arg list followed by any series of expressions so I can write a specification for this so the name of this spec is def em the first thing has to be the symbol defend the next thing has to be a symbol after that has to be a vector and it has to contain symbols and the body can be a sequence of anything right any value any any values can follow inside the body of that thing so I can say this is all I need to parse right to parse closure code so this is this this is legitimate closure code I say I've written the spec for it let me and here we see it's it's totally parse the symbol is right the simple part is def and the name is foo the Rab the body is a sequence which only includes one expression right so I've shown you something that's like you could you can validate wire specs you can validate the syntax of your language it's super generic you can generate example data so on and so forth so here is it here is this a program which is syntactically incorrect because that's not a symbol right you can't have one as a enclose you can't have one as an argument so I can go tell me why that's wrong right and it says go 0 this is index 0 this is 1 this index 2 and the value here 1 fails the spec right this is not a symbol so it gives you the path gives you the path into your structure that tells you what went wrong okay so I'm just one last thing before we move on to other examples so recursion is fully supported so typically if you look take a data structures course so you do like a basic thing and like type functional programming binary trees is like like the you know the foo bar hello world there so here I can say here's a binary tree it's either gonna be nil or it's going to be a tree and the tree is either a value it's a sequence in the first parts of the value it has to be a positive integer in this case the left branch of the tree has to be another tree the right the right branch of the tree has to be another tree but notice this is a self French self-referential specification if you if you're doing UI programming I guarantee that you're you eyes are recursive right you eyes are fundamentally recursive a tree list is a recursive data structure right recursion is such a huge thing people just don't I don't think people don't think about it enough that a lot of things that you do are fundamentally recursive data structures and closure spec fully supports that I'm just gonna skip these because I think that's sort of self-evident but here I'm going to conform this one to show you it parses this into again a parse tree where is the tree the value is 1 the left side is another tree so on and so forth all right so this is awesome so a lot of times like imagine you're parsing options the command line imagine some jerk decides that it's a good idea to encode some significant piece of information and array that's horrible because it's not you know you have positionality but really you want those things to be named right you want those things to be named speck gives you away when some jerk doesn't realize that you know giving you a positional thing is really not a great idea you want name stuff speck gives you a way out of that you can write a spec for that sequential thing and actually get structure back so that's another huge benefit one thing that's really crazy about this is that when Rich icky did this I was like oh this is so cool this very lispy wouldn't it be awesome if we went backwards so this is the parse tree so there's a corresponding function call unform that can reverse the whole thing and take it back to the original value so this takes it to the parse tree as a thing called unform says take the thing use this spec and run it backwards and it should just be the original thing right so this is really cool I mean there's actually a really neat versioning idea here so for example you could say here's a version one in the spec and you need to change something you need to migrate it to the second version right so conform an unformed would be the way to do this for example you could go tree version 1 and I want to I want to I want to unforce it back into tree version 2 right so there's some crazy tricks here especially if you've ever had to deal with the fact that structures change over time which is you know you can't do anything about this but you often have to write very brittle code here we're writing purely declarative code right you haven't seen me write anything that isn't just what does the data look like I've written no code that's logic there's no for loops I haven't I haven't changed any variables I haven't assigned anything this is all declarative specification ok so if you're coming from JavaScript Java and JavaScript and actually web programming general JSON is really kind of just the weight and it's the way we do things and that's fine associative data structures are powerful they're useful and closure spec has great support for this so I can make a spec called first name and then one call last name and all this stuff is designed to compose and say on I want to represent an object which has a first name a last name in an age and here I can combine all those things into a person spec right so here we say a person has to be an object like thing with properties and it better have the properties first name and that better match this spec and it has last have a last name it better match this spec has to have an age better match this back so let's evaluate this stuff and then we can go this I'd messed it up oh whoops thanks sorry cool so that worked and then if you know right so that just works as we expect it so that's that's the other neat thing is that no again this this file they have is just the specifications and this file is shareable both on back-end and front-end because close your script in closure are the same so you can write up a whole bunch of specs and it's all shareable right and there's it's all reusable like first name is something you can reuse in any part of your program there's no reason that it's tied to being inside of a map or be inside of a vector or being inside of a sequence it's just a reusable specification that could appear anywhere in your specs and then of course specs have to evolve over time right this is this is the most annoying thing about software as specifications change but really it's really it's really a problem often to change the original spec because if you if you change the original spec right then you then you break out you break your end up breaking a lot of code because other code has different expectations often what you want to do is we'll take the old thing we're gonna write some new stuff and we want the new stuff to conform to a new specification but we want to reuse the old one so here I can say now I want people to include height in inches and I can merge the person's spec and this one person plus height inches now requires it so there's a whole notion of taking these these key specs they're open and we can combine them and evolve them over time which is I think really really great okay so what about specifying functions so now that we get a sense of all the things you can do say you write starting writing functions and you want to specify functions so here I'm going to say I'm going to write one day I'm gonna write a function like this is kind of like test-driven development but you'll see it's a little bit more effective because I don't have to write any tests I just write the spec here I say I'm going to write wishful thinking I'm gonna write a thing called get value which takes a tree and then returns a positive integer so so then I decide to write this function and I'm not I'm just gonna just blast it out and that's here we're gonna go when there's a tree I'll call the first thing on the tree because we know tree is just three things and the first thing is gonna be the positive integer then I can instrument I can say find the function that called get value and actually find the spec and then turn it on so I can write I can write a bunch of code or write a bunch of Faxon i gonna be well let me let me double check that my code is doing the thing it should be doing and I can say instrument this one and then I can call it and it works and then I can call this one and this shouldn't work because trees that should have positive ends is the first thing and when I invoke that we're gonna get a failure we go up here sorry we're gonna see that if we look at 0 0 here it's gonna say foo nil nil it's gonna say that first thing is not a positive integer and then it gets here's where it gets really powerful instead of instead of doing these eggs what case-by-case things but you can actually say given the specification just check the thing and this is where we use test check to generate a bunch of random inputs and it gives us the minimal case where it fails so here we scroll up and what it says it says the minimal argument list right if you invoke this thing with nil it's gonna fail so now that you know this what's wrong with this what's wrong with this function when I wrote it it's a bit of a trick question that's right it doesn't work on efi tree but notice notice this this this thing it could have generated thousands of examples and it will always produce milk it'll always it doesn't matter what the random search finds it will always figure out that the smallest failing example is when you invoke your function with nil so this always gives you the minimal case and it even gives you the seed so the seed is all you need you can actually deterministically recreate the random sequence because it provides you the seed to start the search with which is extremely extremely important you need you need to be able to reproduce the failure so that's pretty cool so you actually have so you all you did was you I said you spent two minutes write a spec you get tests you get examples and you get generative testing and minimal failures which is all really really pretty awesome stuff ok and that's this last example I try to show you know applying getvalue it's new and that's not right that's not a positive integer so I can talk about this forever but because there's so much there's so much to talk about but I'm gonna end it there because I there's a bunch of other cool talks tonight all right thank you [Applause]
Info
Channel: React Vienna
Views: 10,073
Rating: 4.9800997 out of 5
Keywords: clojure.spec, clojure
Id: Rlu-X5AqWXw
Channel Id: undefined
Length: 28min 42sec (1722 seconds)
Published: Wed Dec 07 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.