Sessions is temporarily moving to YouTube, check out all our new videos here.

.NET Blub Frameworks Beyond Microsoft

Joe Stead speaking at dotnetsheff in August, 2017
Great talks, fired to your inbox 👌
No junk, no spam, just great talks. Unsubscribe any time.

About this talk

The majority of web projects in .NET are written with ASP.NET MVC/Core and EntityFramework with SQL Server. Let’s check out some alternatives. Exploring some common problems, we’ll take a look at NancyFX, Dapper, and Postgres, to help us solve them. We’ll be looking at these frameworks with a slightly twisted take on “The Blub Paradox”.


Hello everybody, quite a small crowd, I like this. So my my name is Joe Stead, and we're going to be talking about something called, .NET Blub, Paradox and frameworks beyond Microsoft, or more, kind of easier to say, I guess is, finding the best tool for the job. So, I know the title of the talk sounds quite provocative, and quite anti-Microsoft, trust me, if I wanted to make fun of Microsoft, there are much easier ways to do that, than spend an hour talking about that, such as the Windows thing. But I don't want to do that, I want to talk about how actually, we can, explore other ways of solving our problems without Microsoft holding our hands the whole way, and saying, this is the best way of doing it, because it's not. So let's talk actually about one of these things, that's a silver bullet, in case you're completely unaware, and all the way through my, kind of school career, college career, university, and then 2D developer, to where I am now, I've always been told that one of these doesn't exist. And I'm sure all you have too, right? Audience participation, right? Thank you,, so why do we always get stuck on the same things, over and over again? And I've kind of noticed a trend, especially, kind of looking for new jobs, and kind of what's out there, in terms of technology we use, you see it on Stack Overflow, you see it on, people on Twister, you see it, on recruit for emails. And this is something I, I think I searched this back in January, I'd say for a month, and I started spotting a trend, in these recruit emails. And, feel free to spot a pattern, I've kind of highlighted it to make it easier, if you haven't. And again this isn't like this is in space for literal months, of all of these things that are the same everywhere. And it leaves you feeling like this, it leaves you feeling enraged, and annoyed. And that's simply because, how can every businesses own problems, going from talking about science to line of business, to kind of, anything you think of in between. Security, banking, everything, that all varied in problems. So how can we solve them with the same three or four technology choices, that are arranged by Microsoft. Probably can't if we're jumping through hoops here and there. But that kind of got me thinking, why does this happen? How was it able to get to this state? And the answer isn't kind having a cheating move in a karate film, so the wrong the person wins. That's what happened by the way. The answer is something called the Blub Paradox, and that is our secret weapon. Does anybody know what the Blub Paradox is, before I go on? Yes, if I get this wrong, it doesn't matter, excellent, I can make it up. Okay, cool. So, the Blub Paradox kind of started in the mid-90s, I guess, when I was four or five, so excuse me if I get some of this wrong, I was a child. It started with this guy called Paul Graham, and you can see the actual post, kind of at the bottom there. And he, in the mid-90s, with his pal, his name I've forgotten, he created a product which was an online web store, so you could create our own shop on the internet, and sell things. Now, in 2017, that sounds like, well, he doesn't do that, I can do that with five minutes, I can get some node tool or something like that, but in 1995, this is really, really new, and innovative. Nothing like that existed, we barely had a web browser, at this time, right? But they did it, and it was first to market, and they made a load of money. But of course, once they launched, there were other issues, and that they had competitors, so how did they stay relevant? And the answer is LISP, LISP is a programming language. Do we have any LISP programmers in? We have somebody shaking their hand, and we'll take that as a no. And at this point, you may be thinking, what the hell are you on about? And I'm not a LISP programmer, you may tell, because I've got the brackets wrong, they don't match. So LISP gave these people the competitive advantage, that their competitors quite simply didn't have. They were using Java and Pascal, and, whatever else was around in the mid-90s. And they couldn't compete with this company, I want to say Viaweb they couldn't compete with them, and the reason they couldn't compete, was because of LISP. Can anybody take a guess as to why? Cool, good. So they found their competitive advantage with LISP, through macros. So in LISP, you could write some macros that did semantic stuff, again, I'm not a LISP programmer, so I'm paraphrasing here, you can use macros, and you can leverage the power of the language, do things quicker, and deliver it market quicker than what you could in Java, Python, Pascal, or Delphi, Visual Basic, things like that. You could do more quickly, with LISP, you would have to be a very, very good programmer to use LISP, because it's an absolutely mental language, but you could do more, quickly. So can deliver it to market quicker, so, you get to market, you launch, people say, that's a good idea, we're going to do that, and they launch their own version in Java, Python, whatever, and they can't compete with you. And if they do have a new feature, you'll have it a week later, because you've got the edge. LISP gives you that edge, or in this case, macros in LISP, gave them that edge. So they were able to beat the competitors to market, and stay on the ball. Okay, so this is what software development is all about, right, it's about doing better than your competitors. Nobody goes out there to try and do a worse job than their competitors are doing, and hold on to their dying customers, and, that's not what we do, we try to be competitive, right. And by choosing a tool their competitors weren't using, they were able to, Viaweb was able to, in actually, I think '99, 2000, Yahoo ended up buying Viaweb, and it became Yahoo Market Places, which was the most profitable part of Yahoo, for five years or so. They should have cashed in on that, because Yahoo doesn't make any profit anymore. But at the time, it was really profitable for Yahoo. So how do you identify what tool you should use, to give yourself a competitive advantage? It's easy for me to say, use LISP, it's going to be great, but also, it's 2017, don't use LISP, it practically mental, right. So, I want to kind of take a step back, I've been talking about LISP and Python, really briefly. I don't want to talk about those too much, we will do later, but right now, I want to focus on frameworks. Okay, so, languages that are less powerful are obvious, so are there any C# developers in the house, just a quick raise of hand. Okay, pretty much everybody, and you were developing, primarily? Sorry, SQL, okay. So if you look at, if I'm going to use C#, if you look at C# 7, of example, where we've got true pulls, expression bodies, things like that, and you look at C# 1, where we don't have generics, it's easy to see, C# 7 is much more powerful than C# 1, I'm sure everybody will agree with that, right. You can use generics in later versions of C#, you can't in the earlier versions, which means you can do more cool things. But you can also translate that to be across languages, so I can say, I if want to use generics, which is I have, a poorly defined business, I don't want to use Go, because Go, is a really nice compiler platform, but it doesn't have generics, because it's not a very good language. But, you can't use Go for it, if you want to leverage generics, go with your tool of choice. So, if you look back at the LISP example, if you want to leverage macros, use LISP, don't use Pascal in the mid-90s, whatever. Okay, so there are advantages to using C# over, Go, for example, or maybe if you wanted to do some really heavy pattern matching, you'd use a functional language, lik Elixir, or maybe F# over C#. So, languages that are less powerful are really obvious, so you can say, I can do all this pattern matching in F#, I'm the best, which is what F# users say, by the way, because they love starting arguments on Twitter. Do we have any F# users here, by the way? Great. That's not the end of this. And then languages that are more powerful, are strange, weird and do things I don't understand. So what do I mean by this? So, as we're all C# developers, slash, SQL developers, and we look at F#, and we see, curried functions, we see, pattern matching, we see monods, and we see, other functional concepts, and we look at this, and we think, what the, this is recorded, what the hell? Right, what is going on? I don't understand anything that's happening here. And you kind of say, I'm just going to setup C#, and do my own thing, I know how that works. Is that something that anybody's felt, when trying to learn that new language? You look at something thinking, oh my god, I have no idea, I'm going to stick with what I know, because I can be productive. Familiar story? But actually, in the mid-90s, these competitors, the Viaweb, took the time to learn something such as LISP, and they were able to leverage macros, maybe they could have done better. Okay, so when we're, what's essentially, looking up a language that we don't understand, be more accepting, and be more willing to try and learn these concepts, because they could actually be really powerful, it's just that you don't understand them, and you can't leverage them to their full capabilities. But also be aware, when you're looking down at languages, such as, C# 7, C# 1, and saying, I am at the top of this pile, and you can't get any better than this. That's a kind of dangerous situation to be on, if you think you're using the best tool for the job, you're probably wrong, there's something better out there, you just haven't found it. And that's okay. There are exceptions to this, don't spend all your time learning Brainfuck, the clue's in the name, it's going to screw with your brain, hey, it rhymed. So, there are languages that are out there, just to be challenges, CodesGold, things like that, don't spend, has anybody looked at Shakespeare lang? Where you define your variables, like, Romeo entered the station left, and that's like a pointer, and then, Juliet entered the station from the right, and that's like a reference, it was crazy. Don't go learn all those, it's interesting, but don't spend too much time learning those, because they're not going to give you a competitive advantage. They're to be, fun, right. With that said, just because it's like an esoteric language, and it is a bit mental, that isn't to say there isn't value in learning the constructs around it. It may be hard to read, but actually getting your head imparted in that language, could potentially be beneficial in, kind of imparting more complex parts of other languages. Just don't use it in production, please, ever. So, the same, why is the list of lines behind this? The same applies to frameworks, so frameworks of less, of lesser power, a really obviously at fault, when you're at the top list things like, I'm using the best framework, all of these are terrible. Really, really easy to do, yeah. Just like languages, a version of a framework is more powerful than an old version of framework, unless you break everything. Which happens. And then again, frameworks that are more, are more powerful, are strange, weird, and do things you don't understand, you stay away from them. Yeah. So, you look at something and think, I don't really get what this doing, I'm used to doing it this way, and this way, and this way, why would I do it any other way? And there are actually reasons for that, take time and go learn them, is what I'd say. And we'll explore some other frameworks that you may not be familiar with, you know, throughout the evening. So, essentially, the Blub Paradox is, you can't know everything, and you're always, you're never going to be at the top of that pile, you need to be aware that you're never going to be on the top of that pile, you're always going to be looking down, and always going to be looking up, you're always in the middle somewhere. I'm a Blub programmer, I don't know everything, I don't really know much, and you're going to learn that as the talk goes on, that I'm just saying what I think is interesting. Okay, I'm not an expert, most of the technology that I'm going to talk about, and nobody really is, we're just learning these things, that's that point of this, okay. So with that in mind, I'm going to give you a quote, which is a slide I didn't remember was there. So, essentially, this is the crux of the Blub Paradox, when you're satisfied with where you're at, you're not going to choose anything else. Because that's the way you think, but what you should be doing, is essentially, never being satisfied. Do we have any JavaScript developers in the house, by the way, like, people who really love Node and MPM, things like that. So, what the JavaScript developer community has done, has take this to the extreme, and reinvent the wheel every five minutes. Don't do that either, okay, there's a balance here. But more seriously, do, you know, the point of this, is to think outside of the box, to change the way you're thinking about things, just because you know something, and you're comfortable with it, it doesn't mean that's the be all and end all. There are alternatives. Don't let that dictate the way you think. Hey, quaint, huh. So, what I'm going to do now, is I'm going to kind of delve into a few technology choices, I guess, and talk about different ways of doing things. Now, a traditional application has a database, it has a way of communicating with that database, and then it has some front end of some kind, right. So we're start at the bottom, and we're going to work our way up, and we're going to end up in a web framework land, because, you know, WPF, and things like that, are boring. So I'm going to start with databases, and I'm sorry for the stock images, they get worse, okay. It's all down hill from here, guys. Just prepare yourself. So, more specifically, we're going to talk about relational databases, now the reason I want to talk about document databases, and not SQL databases, is because they're there to solve very different problems. And we will touch on a few of them, but I really want to focus on relational databases, such as SQL Server, such as MySQL, Oracle, anybody use Oracle? Your company has got too much money. But, any PostgreSQL users? Yeah, one person. And that's it. So, what I'm really going to focus on, is not so much Oracle, because, although I've had experience with it, actually, my first job out of university, was converting Oracle forms app, which is a thing, apparently. This is from the early '90s to, Silverlight, which is, you know, from the late 2000s, and that's now dead. So we went from one technology to another, and I was converting logic from Oracle forms, Oracle, SQL into C#, and, we don't talk about that anymore. That's all I can say about that. And again, I don't talk about MySQL too much, so one thing I will say on MySQL is, if you use it, it's cross-platform, except it relies on a file system, so be careful, because it's going to screw you over, if you run it on Windows and Linux differently, and things like that. Be careful with MySQL on that front. So what I do want to talk about in more detail, is SQL Server and PostgreSQL, because those are two things that I use, day to day in my job. Again, I'm not an expert in either of these, I'm not a DBA, because DBAs shouldn't exist anymore, silos of knowledge, ooh, no, don't do that. Have shared knowledge across your team, it's better that way. Unfortunately DBAs still exist at this time. So yeah, I'm going to talk about SQL Server and PostgreSQL a little bit more. So which one should you use for your application? Well, the simple answer is, I don't know, the more detailed answer is, ANSI SQL is ANSI SQL. So, I'm aware there's a SQL developer in the room, and I'm not, so I'm at risk of looking like an idiot now. No, okay, whew, I'm not a very good developer at all, so whew. So, does everybody know what ANSI SQL actually means? Cool, excellent. I can teach you something. So this is an example of ANSI SQL, I think, it ought to be ANSI, so anyway, there's this standard kind of super set of a language, that exists across all SQL languages, so if you think MySQL, you think SQL Server, you think PostgreSQL, you can write that, that line there, in any of those platforms, on any of those languages, it's going to run it, and it's going to do the same thing. It's going to select these columns, from this table, and it's going to order it by that one. Okay, so if you gone out in C#, if you were an MS SQL Server kind of person, if you want to limit that by 10, you'd type 10 in there somewhere, right. That's not ANSI SQL, okay, if you want to do that in PostgreSQL or MySQL, you'll do limit, 10, so they're different. But what there is, is a super set, that kind of covers them all. And for the most part, the super set covers all of your bases, it covers kind of, most of the joints, in fact, it covers most of your query syntax, updating, inserting, things like that. For the most part, it looks exactly the same. There are differences, but those are differences you can learn, fairly quickly, okay. Don't get wrapped up in those differences, you've already got the knowledge, if you're SQL developer, SQL Server developer, you can go us PostgreSQL and be productive, instantly. You'll be doing a little bit of Googling, but everybody does that anyway, right. So it's okay, you'll go use MySQL, and you'll be productive instantly. You'll be doing a bit of Googling, but you'll be up and running quickly. But there's caveat, that, these do run differently in production, dig it out, before you go live, please. Like, they write the same, but they are different platforms, okay, it's a cross-platform, so SQL Server, actually, SQL Server is now running on Linux, right, they've just done the release candidate for that, which is not much anything to go by, in the next four or five years, we should have the first stable release. So, whoo! Do we have anybody using SQL Server on Linux at the moment? I do. Just me? Hey, I'm a hipster. So PostgreSQL is cross-platform, it has been for a long, long time, and it's a stable cross-platform, so if you do want to run on Linux, because you don't have to worry about ridiculous licencing issues, you can. If you want to run it in Docker, you can. Containerization, so there's a bit there, there has been, a bit of a stigma around running your databases in Docker containers, or containers of any kind. Has anybody heard of this kind of, anti, don't put your database a container kind of thing? Does anybody know why, you shouldn't do that? The reason is, because volumes never used to exist, so your data would be temporary, which means that container stops existing, your data would stop existing, right. But now with containerization, we have these things called volumes, where you can mount essentially, part of your file system into the container, and persist data. So if you want to do it, it's fine, it's okay, there's blog posts from a few years ago, saying you're not. It's okay, alright. Easily versioned. I know for containerization, is our first candidate for hits the point, there are hits the points throughout this presentation, if you count them all, and get the correct number at the end, you do win a prize. You laugh, I'm not joking. So, yeah, that's pretty much all I want to say, so, I mean, SQL 7, PostgreSQL, you kind of do all of these things in both, now, you can make SQL Server run cross-platform, and you can put SQL Server in a container if you want to. I will run PostgreSQL on Linux in production, it's going to be a long time before I run SQL Server on Linux in production. And I'm part of a team that runs .NET core preview, last year sometime, in production. So, you know, we're a pretty mental team, I'm not touching SQL Server for production, our data is too, too sacred, if you like, to go there. So yeah, for the most part, they're pretty similar. But what I'm going to do now, is talk some PostgreSQL a little bit more, and kind of show you where it differs a little bit, I guess. So, we know it's cross-platform, so is everything these days, it's 2017, you can put everything in containers, this is kind of a moot point, and these are old slides, I'm sorry. JavaScript, so we have somebody who uses JavaScript here, that's great. Why would you use JavaScript in a database? Any guesses, anyone? Go. Because developers already know it, or, because you're mad, one of the two. So yeah, you can run JavaScript in your database, and we will go into more detail on this, in the next few slides, so I don't want to touch on it too much. And by, kind of extension, you can use JSON in your database, so, I remember a job, four or five years ago, I don't know, I was working on a system that was essentially, a ASP.NET web forms application, with a SQL Server 2005 database, were all the logic was in the database. And they had x constructs inside that database, so your SQL would contain x paths to query that out, and at the time, they felt it was a great idea, it's not, alright, that's not right, but, don't do that. Okay, but, by having JSON in there, you can do similar things, again, not a good idea. But there are uses for it, and I'm also aware that SQL Server 2016, has a JSON column type too, this is a little bit different, but you can use JavaScript and JSON, in the same database, and you can do some crazy stuff, which we'll get to. A key value store, so I said we're going to talk about relational databases, we talked about PostgreSQL, which is, a traditional relational database. Key value stores aren't traditionally relational, you know, they are, key value stores are a different type of database altogether, than a SQL database. So think, Redis, think React, think, if there's anything I can even think of, there are different kinds, yeah. So, you can do that in PostgreSQL, why would you? Again, I'll tell you, but not now. And you can build on top of this as well, some really cool features here. So we've got something that runs cross-platform, that can do some crazy jobs and stuff on the database, against JSON com types, and use key value store things, and other things too. Maybe some crazy indexing stuff, right. So you can build on top of that, you can do some really, really, really cool stuff, and really interesting stuff. And again, I'll tell you what now, but soon. So, PostgreSQL PL/V8, does anybody know what I mean by any of those words, other than PostgreSQL? I'll give you a clue, V8 is an engine, it's not a car engine. Okay, what JavaScript engine does Chromium use? The V8 engine. So Chrome, and Chromium use the V8 JavaScript engine, which is quite quick. And now what PostgreSQL has done, is they've made that a, they put that into a database essentially, through a procedural language. So JavaScript is, object oriented, it's functional, it's everything, except a good language. And what they've done is, they made a procedural version of that, and stuck it into PostgreSQL, through procedural language V8, okay. And that's, that's pretty cool. So, you can do some really, really interesting things like that. So you can run JavaScript as part of your query, okay, so remember when I said you could use x path in SQL 2005 to query some x amount of your database already, you can kind of do that with PostgreSQL, with JSON already, using JavaScript, as part of your queries. But also, what you can do here, is not just queries, on your insert, if you use some JavaScript to transform a blob of JSON, because JavaScript object notation, it kind of tucks it quite nicely, transforms from JSON on the way in too. Which again, I would say, steer away from, until I show you something later, in which case, I'll basically do it, but right now, I'm going to say steer away from it. You can also run it as part of your indexes, so one of the really cool things about PostgreSQL, is something called functional indexes, so consider an official index, you say, right, this column here, index it, I'm going to query on that column name, there, quite a lot, I want it to be quick, right. I don't want to do a table scan. Fair enough. In PostgreSQL, you say, alright, this column here, run a transformation on it, of some kind, and query that, so PostgreSQL out of the box is, case sensitive. Okay, where SQL Server isn't. So what you may do is create a functional index, and make an uppercase and lowercase version of that field, so you can query on it. Don't use JavaScript for that, use PostgreSQL, it's quicker. But you extend that to go much, much further, and again, if you've got a JSON column of some kind, and want to query on that with some kind of index of some kind, create a functional index, that's kind of written at right times, so there's no need, kind of degradation of format there, it's all right, the index is there, with JavaScript involved, and things like that. You can have that functional index, really cool. So, we've got to talk about the key values still, we have to, I think, just said, we're talking about relational databases, and I'm going off-script. It gets so much worse, don't worry, I'll make it up at dinner later. So, yeah, it's really, really not relational, but, you can't stray further from relational, you've got, well, I think, well, you've got to key in your value. There's no relation there, other than the key and the value. If you talk about C#, it's a dictionary, yeah. If you talk about any other language, it's a hash map, okay. So they're pretty much the same thing. Why am I mentioning it? And the reason is, because, I need to use it to know my job, so I have to justify it, no. And the reason is because, we, we we come here a workforce, BQ communications, I'll be talking about them a little bit more in a bit. We don't run in the cloud, we, don't run on our own servers, we sell our product, and companies run it on their own hardware. So, we're kind of restricted of what we can produce, as an example. We can say, right, okay, if I was working in the cloud, I guess, I could say right, I'm going to spin up a new, a new server, I'm going to use terra form to code my structure out, and it's the only server I'm going to talk to instantly, right. I'm sure, you guys do that regularly, if you worked in the cloud, just spin up a new server, you can use it. We can't do that, we're stuck with, hardware restraints that exist on, year old, years old, kind of data centres, if you like, that we have no control over, from big, corporate companies. Not allowed to name. So, if we want to do something like use Redis, or React, but we can't, because of hardware constraints, because of change, control, and lots of other ridiculous things that you have to jump through in the enterprise world. What we count is, well, we've got a database, we've got key value store, that's easy enough. So it gives you that option, it gives you that flexibility to kind bend the rules a little bit, without anybody actually knowing what you're doing. Now, I feel like I should tell you now, that, everything I just told you there is completely accurate, but also a load of shit, because we use red, we've said that we've wanted Redis, so we just used Redis, and we just told our customers they're going to have to do it. But if you can't, there's the option there, we were looking at this quite a long time. And we thought, well, yeah, it'll do the job, and it's quick, and it's performing, and it works fine. But we wanted actually, Redis, and that's what we did. And we had one customer who said, well, we don't want to instal Redis, and we said, don't upgrade, and we won't support you. They upgraded, by the way. Spoiler. And their indexes, as I said, really, really quick to look up. So one of the good things about Redis, it it's really, really, really quick, to read from, right. Stack Exchange, or Stack O Freeze, Redis is, for a lot of that stuff, it really, really quick. But because this is index in PostgreSQL, it's pretty quick too. I didn't have metrics to give you, because it depends on hardware, network latency, and, you know, I didn't bother looking at any metrics. So, that's all I really want to talk about key values, all there, because, although that's interesting, it's not nearly as interesting as what I want to talk about now. That's something called Marten, and, has anybody heard of this before? One person has, cool. Version 2 dropped yesterday, and I've not seen what's in it. So if these are massively out of date, well, they will be, this is Version 1.x, so Version 2 dropped yesterday, I have no idea, anything about it. Because it's not something I use very often, but it's really, really cool. So Marten is something that sits on top of PostgreSQL, and it acts as a document database, on top of PostgreSQL, so, I said key value store was kind of going out there, this is really going out there, okay. So, what I mean by document database is, you have a blob of JSON if you like, and you sort your database, and that's your record. So think Raven DB, think Mongo, and you know, without the security flaws, of not putting a password on it, so think, that sort of thing. So yeah, PostgreSQL can act as a document database, and Marten is a .NET library, primarily using C#, yes, you could use it in Visual Basic and F#, a little bit. To talk to that, and kind of treat it as a document database, because it's JSON column types underneath, because you can do JavaScript in your indexes, you can do JavaScript in your queries. It's actually quite productive, but what Marten does is, abstract all that away from you, and you talk to it as it's some, any old document database, with some magic happening underneath it, PostgreSQL facilitates. It's also an event store. Has anybody done any event source thing, ever? Does anybody know what event sourcing is? Cool, I'm going to talk a little bit more about event sourcing, in a little while, because it's something I really, really like. So think of stream of events, think of a bank statement, okay, if you open up your bank account, come to the bottom event, and your initial balance is zero, yeah. You make a transaction, and spend 10 pounds in, a shop, I was going to think of a specific shop, but I'm not going to, spend 10 pounds in a shop, you buy something, your bank balance is now minus 10, yeah. Because you went and you overdraft, you haven't got any money, oh no. Speak to me, I'll get you a job. Right. And then you think, actually, this thing that I've just bought isn't very good, I'm going to get a refund. Okay, so you take it back, you get your refund, and then you get a refund of plus 10. So your bank balance is still zero again, right, but you can see full history there of how that came to be. You started at zero, you went to minus 10, then you went back to zero again. Okay, you didn't delete that transaction, you had a refund of plus 10 there. And that's essentially what event sourcing is, ish, you have the string of events, every time that builds up the bigger picture. Each event in itself, is just a state change, if you like, that you record. It'll be easier to explain when there's code on the screen, which is the next slide, I think. So yeah, it's still PostgreSQL underneath, so you've still got PostgreSQL there, it's fine. And I'm aware that, database is kind of dull subject, I'm nearly done with this. My pencil's a hipster too. So, let's look at Marten as a document store real quick, and we're going to see some C# code. That's it. So has anybody used Raven DB? Has anybody ever used Mongo DB? Okay, well basically, the code looks like that, sort of Raven, certainly for Raven, I don't know about Mongo. But it's actually kind of, open up a connection to your store, if you like, and then you have a C# object, in this case, it's a user, of Han Solo. And then we store that user, in our database, and we save it, that's all we do, okay. And what that's going to do is it's probably, though I don't know, well, I do know, though it doesn't matter, it's going to zero it out as a JavaScript object, JSON, it's going to show us that it's JSON, and save it into a PostgreSQL database underneath. It's going to worry about the tables, it's going to worry about the columns, it's going to worry about the indexes, it doesn't matter. And that's pretty much it, so I can save a blob of information, into my database, just like that, there's no magic going on there, there's no mapping, there's no, no first name and last name, they aren't different columns in a database. That could be anything I want, it will still work, okay. So, yeah, that's pretty much all there is to it, that's the document database, one on one. And, there's a lot more to document databases than that, just, go read about them in more detail, that's not what I'm talking about here. But the fact that it can get up and running really, really quickly, just like that, and that will save into your database, and you can query that back out. And you're up and running in, five lines of code, four if you get rid of the brackets. Use F#. I mentioned Marten is an even store, so, probably explain events a little bit more here. So there's more code here, but that's because there's more going on, and if there are any Lord of the Rings fans, in here, I'm sorry that I got the names and locations wrong. I stole this from the documentation, I noticed it when I was doing this, two months ago now, I haven't updated it. But it wasn't Merry who joined Frodo in Hobbiton, it was Samwise Gamgee, I'm sorry. But essentially, what happens is, we have an event, quest started, and that's what kicks off our stream, okay. So quest started, destroyed the one ring, yeah, it's not an event in itself, but it's something that exists in itself, yeah. Then we have an event of members joining the quest, in Hobbiton, of Frodo and Merry. And then we start, we start this stream, I don't know if you can, don't worry about the comments, it's fine. Can everybody read the code, by the way? Yeah, good, because it doesn't get any lighter. So yeah, we saw our quest stream, we have the quest ID, being whatever, and these two have actually started the quest, and others joined the quest instantly. And that's our streams, these individual records in our database at this point, all tying up to one stream. So, the quest started, and the members joined, and then, tie up to the quest stream. So there's one quest with several events off of it. Yeah. And then later on, other things happened, and Merry and Pippen, which is spelled wrong, again, I didn't write this, joined, and Buckland, Aragon joined, and Bree, I think it was called Strider then. Any fans of the books? Then eventually, on day 15, they arrived at Rivendell, and all we're going to do is append those to our quest stream, and we'll see, over time, this is what happened, yeah. So we'll see a structure just like a bank statement, you'll see what happened to this quest over time. So on day one, Frodo, Merry joined the quest, and then, a few days later, on day three, Merry and Pippen joined, and then a week later, Aragon joined, and then five days later, they arrived at Riverdell, and you'll see all of these events one by one. Now if you are doing event sourcing, it's really, really complex, because you have to think about then versioning, and things like that, and it's not something I particularly want to get into this talk too much. But what this does, is allows you to use PostgreSQL underneath as an event store, and you store these events as individual records, and not really worry about when you query them back out, and rehydrate your attributes and things like that. It's just going to work. I guess, you may, at this point, if you are going on that event sourcing route, you may want to look up, Get Event Store, which is something Greg Young wrote, he coined the term SQRS, or an event, anything event store, that's terrible expression. Or other event stores, that are out there, and you know, Tasco did one, that exists in Java land. And some other companies have done one, so there are other event stores out there, if you do want to go down the event sourcing route. This isn't necessarily the best way of doing it, but it is something cool that exists on top of PostgreSQL. Because of what it gives you, because the JSON, because of the JavaScript engine, with the indexing, because that the in between. You can't, you can do this in SQL Server if you wanted to, it wouldn't form no where near as well. So, yeah. Anyway, that's enough about databases, that's boring. I've got something way more interesting, talking to our databases, whoo! Enthusiasm, anybody. No, just me? Okay, Okay, to data access, let's just kind of jump into it. So, we talked about different databases, they're mostly PostgreSQL, because, you know, it's an alternative to what mostly we use. So we're talk about different data access, we're going to talk about Dapper. Anyone know what Dapper is? I'm not talking about that guy who makes stupid videos. I don't totally understand that. Entity framework. Who uses entity framework? Oh. NHibernate, any NHibernate users? Okay, cool. Simple.Data? Has anyone even heard of this? Okay, so this was a dynamic library, that Mark Rindle wrote. Do you guys know who Mark Prindle is? Yeah, he's the comedian, nice guy. He wrote this dynamic library that kind of maps dynamic C# into a SQL query, and it's really cool how it works. Don't use it, And he'd probably tell you the same thing, though. It's, a really, really cool framework, or really cool library, if you like, just you know, don't. And F# Type Providers, so, get to the point, and, we don't have any F# users in here, do we? Cool. So, yeah F# type providers, we're not going to get into too much. We can talk about F# in a little while. But essentially what you do is you can point, create a kind of type writer, a database, and it will map it all into the types, and things like that. Not too dissimilar to ANSI framework, but you can use a type writer with a web service, use a type provider with, anything really. Yeah, CSV. Excel spreadsheet, whatever, and it'll map it all over for you, it's pretty cool, it's pretty interesting. But just like anything in F# land, it's very heavy on the allocations, because it sits on top of CLR, with isn't an optimised functional programming. Actually, it's a caveat with F#. So what I'm going to do really, is talk about entity framework and Dapper. Now, I have to talk about entity framework, because, it's awful. I was going to stay diplomatic, and say, oh, it's okay, it's not, it sucks, don't use it. You may think, oh it's just LINQ, and over the hood. Well yeah, it is just LINQ, but it's not really, because it's running against a SQL database, or a, there in a SQL somewhere, database. And unfortunately, for everybody here, and everybody out there, C# does not run in your SQL database, it SQL that runs. And what entity framework does is, it maps out C# with that LINQ code, into a SQL query, and it does a distinctly average job at it, at best. And has anybody come across lazy loading, in entity framework? Has anybody wasted two weeks debugging some ridiculously lazy loading issue in entity framework, and think, oh, this is a great feature? Anybody think, no, because it sucks, don't use it, alright. It's, really, honestly. And that's I have to say on entity framework. Oh not it isn't, yeah, it's doing what to my database? I've got more to say. It's doing what to my database? So, I mentioned earlier that if you've got a DBA, stop that, stop having silos of knowledge, spread that knowledge across the team, assimilate it across different team members, don't rely on any one person to be an expert on your system. Alright, a DBA is the expert on your database, and, that shouldn't exist, but expertise should be distributed across, right. So if your DBA gets hit by a bus, somebody else can say, huh, that's a shame, but, at least we've still got our database. Because we're not humans, no. You know, we want to dissimilate the information, so DBAs are quite bad, but, if you do have a DBA, or you have a database expert, who wonders why your production system has ground to a halt, and they look at what's happening, and they look at the logs in SQL Server, and they see this disgusting query. And they go up to you, and they say, what the hell have you done to my database? And you say, it wasn't me, it was entity framework. Not good enough, you'll hear, right. It's your responsibility, what that framework will ultimately generate. Own that code, yeah. It's on you. Ah, there we go. That's the last I have to say about entity framework, really, because what I want to talk about now is Dapper, which is kind of the polar opposite of entity framework. Has anyone used Dapper before? Has anybody used Stack Overflow before? Yeah, whoo, yeah. You have been a consumer of Dapper at some point, so Dapper was actually written by the United Stack Exchange, Stack Overflow, whatever they're calling themselves now, and that is what powers the MSSql database, and the C#, that's how we query it, through something called Dapper. And what's called a micro RM, because it's very lightweight, and it's actually very, very, very, very, extraordinarily quick. Okay. But the point is that it's quick. And it works with the following, SQLLite, any SQLLite users? Cool. SQL server, Oracle, MySQL, PostgreSQL, and so and so on. So it's actually an abstraction concept, on, blah, blah, blah, blah. It's actually abstraction on top of ADO.NET. So does everybody know what that is, in kind of .NET land,, IDB connection provider. All that sort of stuff. It's essentially a set of extension methods that live on top of that, so ADO.NET can talk to it, Dapper probably can too, okay. So, the really, really cool thing about Dapper, is you control your SQL, you know what's happening on your database, and your DBA won't come screaming at you, because of some absolute junk it's generated. And if your DBA does come screaming on you, it's your fault, again, but this time, more so, because you written it yourself. You can't blame the library, it's on you, okay. Just for the record, I don't have to get on anybody from any team, but you know, examples. So keep your DBAs happy, but don't have them silos, no, boo. Does anybody work with DBAs, by the way? Good, awesome. Getting rid of the silos. Well, here's the point, I was going to, okay. So, what does Dapper actually look like? And it looks like this, so we're getting back to C#, so we've got an IDB connection, which exists in, it's a .NET thing, it's not a Dapper thing. Right, that's a standard interface, you'll see that in entity framework, probably, I don't know. You're going to pass it a connection string of some kind, in this case it's default connection, and it's, you know, C++ in the mid '90s, going to prefix that with an underscore, because, you know, you've got to have keywords such as this. I've got this kind of, I shouldn't criticise it. And then, we're going to have a query string, so this is kind of, how we select our database. If you think of a query that runs in SQL, it looks exactly like that. Now in MSSql, you may have a variable of some kind, called user ID, and you can declare that as an entity, or whatever, and set that later on, right. And it would look like an @user ID. In PostgreSQL you can't do that, the point is, this is a, this is a SQL query, it's not C#, yeah, and it's existing in this string, and it's the data in the string, it's actually detected by the @ symbol. And we're going to select three columns out, ID, first name and last name from the table users. Yeah, and we're going to filter that by ID, @user ID. And that's a parametrization. Thanks for the nod of appreciation, for the pronunciation. So that will run in SQL, if we replace that @user ID with 15, that will query against that database, and pull back that user record, and we'll see it in our view of, ID, first name, last name, of 15, Han Solo, or whatever it is. Okay, and all we're doing here is, we're using our IDB connection, which exists in this, in .NET, it's nothing we're introducing. Use an extension method, which Dapper is using, called query async, because we don't want to be blocking our own I/O. There are synchronous overrides, if you do want to block, for whatever reason. We're going to put our person object, which is just a, plain old C# good object, pocket, if you like, with these properties on ID, first name, last name. And we just set the user ID, so we've got @user ID, we're going to use an anonymous object, though it doesn't have to be, it could be a typed object, if you like. And we're going to set the field user ID to 15, okay. So we're going to query that, and we're going to select single or default afterwards. So we're going to query all of them back, I know there's only one, because I'm doing it by user ID. I'm going to pick one out. Now that's a little bit wasteful, if you like, we could, if we wanted to, could have had, connection.single default async, this string, this filter, done, alright. And that's what Dapper is, it runs SQL, against a SQL database, because that's what it knows. It could be SQL Server, it could be PostgreSQL, in this instance, it is SQL Server, you can tell by the type. It could be MySQL, it could be anything, right. Dapper doesn't care, it's going to talk to it, through the IDB connection, and it's going to do some mapping magic, based what it gets back. So it's a, and if we want insert, or update, or delete, or anything like that, instead of querying, or single for async, and whatever, we can execute. So we can update, you know, our users, we can set the first name to first name, last name to be last name, user ID to be user ID. So we can update an existing record using Dapper too, and we can insert, delete, blah, blah, blah. Because all it's doing is running this SQL, against your database. No to this point, people often say, well, I'm writing C#, so I don't want to write SQL in my C#, because I'm using C#, and why should I write SQL? And my answer to that is, when you communicate through an external web service, do you write C#? You do. Do you then handle HTTP query codes? Do you then handle HTTP verbs, such as post, get delete, per, update, ah, update, delete, patch, et cetera, et cetera. And that's what you do. And that's because you talking the language of HTTP, at that point. All we're doing at this point, is talking the language of SQL, we're talking the language of our external service. And we can understand what language that external service uses, and we can leverage that. So, another argument I get against this is, well, actually if I change database providers, I have to go change my code all over the place. Who here has ever changed database providers, from MSSQL to something else? Right, it seldom happens, if ever, okay. And my other point is, if you do do that, great, I want you to feel every bit of pain that you can go through rewriting that code. You're changing that provider for a reason, make sure you understand that it's actually a benefit and not a huge waste of time. If you have 3,000, all in like this, and you have rewrite them all, feel that pain, make sure it optimised to the database you're talking to, and understand why you're doing it. Don't just do it for the sake of it. Okay, it justifies it more than anything, it puts that pressure onto you, of actually doing it for the right reason, and understanding what you're doing, and why you're doing it. And understanding the underlying platform as well. Yeah, so like is said, like, top 10 SQL Server is like the top 10 rows, and then limit by is, how to do it in SQL. And you skip rows, and things like that, PostgreSQL, sorry, you skip rows like that. So, feel that pain, because there has to be a damn good reason you're doing it, and I want to make sure you don't do it again. Okay, honestly, I'm not kidding, feel the pain of changing every single one of these, if you have to, because you should be. And that's what Dapper looks like, and with a rhyme included. And that's it on data access, because it's a really dull subject. Whoo! Has anybody used NHibernate, by the way, getting back to data access? So how did you find NHibernate, and it's ridiculous x no-ness, of everything? He said it, do I didn't have to. Yeah, so my experience with NHibernate is very, very limited, it seems to be, very, very difficult to get up and running. And then when you do, it's just like you're using entity framework essentially, in that you have methods that magically generate SQL and it works. And you have to wonder, well, is this doing the right thing or not. And the only way to look at that, is by looking at what's happening in SQL Server, so, you know, NHibernate, entity framework, in my head, for the sake of this, are equivalent. Yeah, that's all I have to say. Let's talk about webs, with another awesome stock image, before I go onwards. Does anybody, genuine question here, if you talking about, kind of, web and, you know, web searches, and things like that, and you're after a document for a background, what do you do? Seriously, like, does that make sense? I'll take that as a yes. Right, okay, let's talk about web frameworks, more specifically. Alright, so we're talk about ASP.NET MVC/WebAPI, whoo, Microsoft. We'll talk about Nancy, which is something I really like. We're going to talk about Suave. Does anybody know what Suave is, anybody heard of Suave? That's good, none of you F# people. I'm going to make a change here though, I don't want to talk about that, and the reason I don't want to talk about ASP.NET MVC/API, is because it's automatic, so I couldn't do the dramatic effect thing. That's because in 2017 when we talk about ASP.NET Core, MVC instead, if you like, okay. Now the reason for that is because, everything else is, blah. Done, as far as I'm concerned. I mean, if you're using it on your projects, eh, fine, that's life, but, let's move up going forward, because that's what we can control. So, I'm probably going to talk now, in fact, I'm not probably, I am going to talk about three of these. So Suave is an F# framework, which is pretty cool, I have a soft spot for that, it looks really, really nice. If you know what a core is, if you're not quite MVC, more specifically, is the next version of MVC/WebAPI, that Microsoft have pushed. And they're definitely not crushing any other open source projects at all, this is recorded, I need to stop. And NancyFx, so NancyFx is something that I really, really like, that I contribute to, and I help out, and things like that. So we'll go into that a little more detail in a little bit. But what we're going to do is look at ASP.NET Core MVC for a little bit, and the way I'm going to start this out is by having a massive rant. You that was, you thought that was massive we're getting worse. Now the reason I'm having a massive rant, is because every code sample you've seen so far, and every code sample you're going to see, I've been able to lift from some documents, from some documentation, with the exception of this. Because, when I went to the documentation, all I saw was screen shots of Visual Studio, screenshots of post run, and words that didn't really, kind of, hold an relevance. I couldn't find the code to get up running, which couldn't be unnecessary. But this is what the code I wrote looks like, and we have a controller base class thing. Has everybody here used MVC, I'm curious? Yeah, has anybody not, should I say? Okay, well I haven't really, so this is new to me too. So, yeah, we've got a message, we've got an index message, which if you wanted to, you know, slash a details method, which would be, slash details. We've got parameters, and things like that, and we've got our string interpolation there. And we've got our delete methods, and explicit route, you have to use that in attribute, I think it's called delete, and I, explain the route in here, to a junior developer, please. So, what this route's going to be, it's going to be, slash hello, because it's called hello controller, yeah. Slash index is going to return the 200, with hello, right. Okay, how did we get the slash hello, because it's called hello controller, well, magic. How did we get the slash, from index? Well, magic. Cool, so far, so magical. We want to get to details, with an n ID, is that a query string, is that part of the query? I can't remember at this point, I think it's a query string, so we go slash details, question mark, ID equals six, and it will return hello six, so it would be slash hello, slash details, question mark equals ID. But, what, where is this defined anywhere? It's crazy. Now if we want to be specific, we can just put the route attribute on, because that was attributes are for, right. They're not. But let's use attributes for this, because we can do it. And we change the method, we can use a HTTP delete, not this one. Sorry, that was. But we can use HTTP attribute, because that makes sense, because, you know, who needs a method? That may make sense if you've been doing this for years, but, it really kind of doesn't, if you actually look at it on what, on you know, face value. It's kind of ridiculous, and there's some magic going on. Avoid magic. Honestly, make it easier for a developer who's never touched this framework before in their entire life, to get it up and running. The framework shouldn't be what you're focused on. That was a little bit of a rant on ASP.NET Core, MVC. Let's talk about Suave real quick, now I quite like Suave. It's F#, and there's going to be some F# on the screen. I know none of you have used F# before, or if you have, you're not comfortable with it, blah, blah, blah. That's okay. I'll talk you through it, because I'm a pro. That's it, that's the entire application, so one thing I didn't show you on the ASP.NET Core MVC one, was the orchestration of setting up the start up class, the hosting, things like that. This is the entire application, I could put this in the file and run it, spin me up a web server, and it will find the web quest for me, on, default config port, whatever that is, I don't know it off the top of my head. Now, I'm not an F# sharp developer, you're not F# developers, but tell me, honestly, can you understand what's going on at a quick glance? A quick yes or no, who can't, who has no idea what's going on? The recruiters, Everybody else can kind of figure out, right. So we have out app, and we choose a get or a post method, okay, then from there, we choose a path, right. Now, this is non-standard F#, we've got some custom operators in the weird arrow thing, you know, there are some custom operators there, that's fine. The only thing is, for the path on a get method, which is an HTTP method, slash hello, return, hello get, with the get code, okay, which is a 200. Yeah, and then on the path slash goodbye, we say, goodbye get, with a set code of 200. Really, really easy right. You can see that straightaway what's going on. And then on the post for choose path to show, hello post, return okay, and, on the post, you'll probably return content created in reality. And then, path goodbye, okay, goodbye post, then what we do is, we start the web server, move it to default config, and our app. And that is our app there. And that'll work, I could put that in an F# script file, and run it, if I reference the correct assemblies and things. That's it. That's all there is to it, it's easy to explain, it's easy to see what's going on, it's easy to see how your routes work, it's easy to see what verbs you're using, it's easy to see what the say as codes are, because they're all here. Now that's great in a really, really simple example, because I'm actually not doing anything here, I'm just returning a string. Okay, I'm not doing any business logic, right. You may think, okay, that, this is where, this model really helps, I can fill out these methods with loads of business logic, it will be wonderful. Okay, do it. Dispatch that business logic off, elsewhere into a different function, into a different method, a different class, let your web framework handle the web stuff, and let your business logic handle your business logic, your domain logic, that exists outside of the web, yeah. Your business logic, if you work in banking, for example, you don't care what HTTP service code is, you care about how much money you can make. Or whatever the bank is doing. Yeah, if you're working in transport, you care about the distance between two places potentially, and like, traffic on the way, you don't care about 204 means no content, and 201 means create, you, you don't care about any of that, right. That should be handled by your web framework, which is what they're good at, and your code should be agnostic to that. So then when, you throw out a function here, and it can go do stuff, and it'll be fine, it'll work. So that there is actually you need to get up and running, with a web framework, that's as complicated as it should be. But the issue is, that's F#, and, although the F# community will tell you that everybody's using it, it's a great language, blah, blah, blah, and it is a good language, I'll agree with them on that, nobody really uses it. It's got a good user base, but not really, if your application has been around for 10 years, and it's a .NET based application, it's either going to be VB, sorry, or C# right. So want to use that logic, and you shouldn't care about the interface that's talking to you, there should be enough abstraction there to get around that. So although that is good, and F# kind of interrupts, with C# and VB, and things like that, you are kind of stuck a little bit there. Which is where I think Nancy comes into it, now before I go into a code demo of Nancy, or a code example of Nancy, I need to plug it a little bit, because I really like this framework. So, it gets out of your way, so what I mean by that is, if you don't want to use a pattern such MVC, which is a pattern, first and foremost, and a framework secondly, you don't have to. You can use whatever pattern you want, to serve up your content to your users. Okay, Nancy lets you do that, okay. This is my language all over, it's got a delightful set of tools, and testing tools. I'm not going to show these off, because testing is really, really good, and really, really relevant, but it's not really what I want to talk about here. So it really helps you kind of, with your tests. You can spin up a test that, essentially acts as a browser, and you can write, kind of, methods against that browser, and call your Nancy application, without actually spinning up a web server, so you can test your business logic from your web end to your database end, without actually any integration tests of any kind, which is really powerful. It runs on .NET Core, and, this, means it obviously runs on cross-platform, but I want to kind of take a step back here a minute, so I mentioned earlier I worked for a company called BQ Communications, and we, we work with Cisco product, and we work with a lot of enterprise applications, banks, and you know, everything really. So we deploy our own param, we started off running on mono, about five, six years ago. And we hit loads of issues with it. We were using Nancy at the time, which was, we moved to Nancy, running on mono, and yet we're hitting loads of issues with mono and Stack Vault, and other Linuxy stuff, that I won't pretend to understand. And then .NET Core came along, and it's like, this is brilliant, it solves a lot of problems, let's adopt it. The problem is, we had a lot of external dependencies, on open source projects, that weren't supporting .NET Core. So my boss said, okay, well let's pay for somebody to work full time, on open source, and get this over to .NET Core. So we paid a contractor in Sweden, or consultant in Sweden, to work full time, on the Nancy framework, to pull it over to .NET Core. And if your company uses open source, and you're thinking, well, this isn't really what I, do I want to do. But it's kind of really, really, relevant to what you're doing, support the community, and give back, by actually making it, you know, investing in it. It took a few months, we paid some money to it, and it was great, right. We paid for open source development, yeah, it happens, it works. And what we got off the back of that, was free testing. So, we wanted to run this in production, so we paid somebody to work full time on it, you know, using .NET Core. But we wanted to be confident it was going to work, so we put that full time work back into the Nancy branch, and Nancy, kind of get her repository, and people started using it, and reporting issues to us. And it was like, this is brilliant, it's free testing. It really, really worked, so yeah, honestly, support open source. It's beneficial to everyone involved, do it. Do it. It's got pipeline hooks, so kind of what you'd expect in a modern framework now, say, before a request is served, you can expect what the headers, and the body, and things like that, you can change it if you want to. And after the response is served, you can do the same thing, so post in headers and things like that. So think, authorization as authentication, say you want to check, say somebody's authenticating it, the route, but the may not be an admin, you can check their claim before it gets to your request, and things like that. That exists in pretty much everything now, because it's, kind of how the web works. Content negotiation as well, so, again content negotiation exists everywhere, in that, if I request JSON, I expect JSON back. If I request XML, I expect XML back, and, you know, if I request HTML, such as a browser, I expect HTML back. So that's out of the box, and it just kind of works, because, Nancy is actually based on a Ruby framework called Sinatra, so if you pick of the reference there, word on, there is, there is a link. And, because Ruby is a dynamic language, a lot of stuff in Nancy is dynamic too, so the content negotiation is quite flexible in that front. It's highly configurable, I feel as though I've left a few things out now. So if you don't want to use a feature that Nancy gives you, such as, it comes with a serializer built in, called Simple JSON, that I kind of wrote an awesome PR for, the other month, that's good. You can swap out for the JSON.NET if you wanted to, it comes with DI framework, if you know what a core does this now, but that's old news, Nancy's been doing this for years. If you don't want to use that DI framework, we can swap it out, you know, you can swap out the way the routeing works, you can swap out the way the caching works, things like that, you can swap it all out, it won't get in your way. So it doesn't get in your way, and it's completely configurable. It's got a really helpful community. So, it's really active on GitHub, PRs, issues, et cetera. Also it's got a Slack room, because who isn't on Slack these days? We all need more distractions, right. So, about, about this, ah, about June, July last year, I wasn't particularly happy with my job, so I handed my notice in. Without anything else lined up, I had a three month notice period, without anything else lined up, and I happened to be in the Slack community, Slack room, the Nancy Slack room, sorry, and I just kind of put my messages in, does anybody know of any interesting jobs going on? Within about five minutes, I was speaking to somebody, one of the contributors of Nancy, who I'd worked with before, saying, yeah, we're hiring. Are you interested? Yeah, I am. About two weeks later, I was hired, all while posting messages in Slack, right. So that's how helpful it is, if you get a job out of it, right. So, yeah, it's got a nice community, go talk to people and you might get hired, who knows. So, that's all I really want to say about Nancy, without showing you something. I'm going to show you some code, so again, similar to, ASP.NET MVC, we have a base class, because it's back in C# land, okay. But unlike, ASP.NET MVC, we're being very, very explicit with, one, our HTTP verbs, because they are methods, yeah, get, put, post, patch, delete, they're HTTP verbs, that then translate to C# methods, just like in the Nancy module class. And then we've been very, very explicit with our routes as well. So if I were to look at this, this dot get, slash, return hello get, that's all it's going to do. I can see that, that route is going to return that, because it's all there in front of me, on that one line. If I want to use parameters in my route, I can, I want an ID, and I want it to be an integer. Okay, and it's dynamic, so I can use it here, so I can use args as the ID, and that'll be, hello, I'm a number, because it's an integer. And it will print out whatever number I've put in that route. Really, really simple stuff, and kind of, not very interesting. But if I were to put, you know, get, slash hello, I'd get a 404, because it doesn't match any of those routes. So it's clever enough to work out what is an integer, what is a number, what is a, sorry, what is a string, what is, whatever else. And again, per, we can