We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

A farewell to soul-crushing code

00:00

Formal Metadata

Title
A farewell to soul-crushing code
Subtitle
Towards correct software that enriches our lives
Title of Series
Number of Parts
165
Author
License
CC Attribution 4.0 International:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
A major part of software development is maintenance, i.e. tinkering with software that should already be completed but still somehow does not work as it should. Software developed by tinkering is the antithesis to resilient technology, and a growing threat to our profession and our lives. Working on this kind of software crushes the soul. Yet this is exactly how most IoT devices (and computers in general) are programmed these days. We need to replace the dead technology-oriented objects of the past with supple models enriching our domains and our souls. This talk shows how it is done.
Keywords
2
Thumbnail
36:48
16
Thumbnail
1:00:12
17
Thumbnail
45:59
45
59
Thumbnail
1:01:02
83
Thumbnail
1:02:16
86
113
Thumbnail
1:01:38
132
141
154
Thumbnail
1:01:57
Musical ensembleSoftwareGroup actionEvent horizonSoftware developerComputer programRoundness (object)Independence (probability theory)Goodness of fitLecture/Conference
CodeRun time (program lifecycle phase)Core dumpView (database)Data modelObject (grammar)Presentation of a groupCodeBitFactory (trading post)Lecture/ConferenceComputer animationJSON
Context awarenessInstance (computer science)Windows RegistryCodeLibrary (computing)RecursionProjective planeOpen sourceQuery languageInterpreter (computing)Right angleLine (geometry)MereologySystem callService (economics)Object (grammar)CodeComputer programSocial classFactory (trading post)Translation (relic)QuicksortShape (magazine)Physical systemFlagSoftwareVariable (mathematics)Constructor (object-oriented programming)BitLecture/ConferenceComputer animation
GoogolFacebookAsynchronous Transfer ModeSurfaceComputer programFormal languageCodeObject-oriented programmingObject (grammar)Different (Kate Ryan album)Computer configurationFacebookCASE <Informatik>Group actionLecture/Conference
FacebookGoogolAsynchronous Transfer ModeSurfaceOpen sourceCapability Maturity ModelDivisorCategory of beingComputer configurationObject (grammar)NumberCapability Maturity ModelGame theorySocial classInheritance (object-oriented programming)Term (mathematics)Configuration spaceMultiplication signCodeReal numberBinary multiplierPoint (geometry)Function (mathematics)WordRight angleObject-oriented programmingDivisorComputer animation
Pattern languageMilitary operationComponent-based software engineeringOpen sourceDivisorCodePattern languageComponent-based software engineeringObject (grammar)Real numberSocial classComputer configurationDivisorComputer animationProgram flowchartJSON
DivisorLikelihood-ratio testCodeVoltmeterContext awarenessShift operatorAbsolute valueDivisorFigurate numberOperator (mathematics)CodecCodeRight angleLine (geometry)Universal product codeObject-oriented programmingChainMereologySlide ruleAbsolute valueProduct (business)CASE <Informatik>Different (Kate Ryan album)Computer animationSource codeJSON
Formal verificationComputer programmingFunctional (mathematics)FunktorMonad (category theory)Arrow of timeArithmetic meanRight angleLevel (video gaming)Functional programmingFormal verificationFunctional (mathematics)Sound effectMonad (category theory)MathematicsMorphismusFunktorBookmark (World Wide Web)Arrow of timeComputer animation
Disk read-and-write headAngleMereologySoftwareSystem callRight angleLecture/Conference
Open sourceUnicodeInformation managementAgile SoftwareentwicklungSoftwareDesign by contractCollaborationismDependent and independent variablesPattern languageRoboticsCircleQuicksortCodeHidden Markov modelSoftwareProcess (computing)Interactive televisionFigurate numberSoftware developerComputer animation
Agile SoftwareentwicklungSoftwareCollaborationismDesign by contractDependent and independent variablesSurface of revolutionRootSoftware engineeringSoftwareRight angleMachine codeMultiplication signComplex (psychology)Software maintenanceSoftware engineeringSource codeComputer animation
Object (grammar)Open sourceNormed vector spaceProgrammer (hardware)Hill differential equationComplex (psychology)Software maintenanceObject (grammar)Object-oriented programmingRight angleQuicksortSlide ruleState of matterResultantCodeMessage passingSpeech synthesisImperative programmingComputer simulationLecture/ConferenceComputer animation
Object (grammar)Endliche ModelltheorieFerry CorstenSequenceSystem callRight angleMessage passingGoodness of fitComputer programComputer animation
Object (grammar)Game theoryMessage passingPolygon meshState of matterEndliche ModelltheorieObject-oriented programmingState observerMathematicsField (computer science)Pattern languageComputer animation
SequenceOrder (biology)Object (grammar)QuicksortState of matterConsistencyMultiplication signRight angleEndliche ModelltheorieCodeSemiconductor memoryComputer programObject-oriented programmingLecture/ConferenceComputer animation
Data modelView (database)Game controllerPattern languageEndliche ModelltheorieGame controllerView (database)CircleDirection (geometry)MathematicsRight angleLecture/ConferenceProgram flowchart
Object-oriented programmingRevision controlComputer programObject-oriented programmingEndliche ModelltheorieComputer animationLecture/Conference
NumberStudent's t-testState of matterSocial classRadiusCircleKolmogorov complexitySystem programmingSoftware testingState of matterObject-oriented programmingStudent's t-testAttribute grammarGradientMessage passingPoint (geometry)AverageObject (grammar)Functional programmingComplex (psychology)Formal languageProduct (business)Software bugSoftware testingPower (physics)Physical systemType theoryCategory of beingLecture/ConferenceComputer animation
Kolmogorov complexitySystem programmingSoftware testingCategory of beingComputerCodecSoftware engineeringRight angleCycle (graph theory)Electronic mailing listFunctional programmingSoftware testingMonad (category theory)Computer animationMeeting/Interview
PrototypeSoftwareCodeLine (geometry)Observational studyChaos (cosmogony)Relational databaseSemiconductor memoryFormal languageFormal languageSound effectObservational studyProgramming languageDialectDifferent (Kate Ryan album)Set (mathematics)DivisorStudent's t-testComputer programExpert systemNumberRoundness (object)TelecommunicationGreatest elementSoftware developerRight angleFunctional programmingJava appletMusical ensembleCodeMultiplication signInstance (computer science)
Set (mathematics)Client (computing)Right angleDifferent (Kate Ryan album)Lecture/Conference
BitCodeCircleFactory (trading post)Projective planeVirtual machineMicroprocessorProduct (business)Different (Kate Ryan album)Right angleComputer animationLecture/Conference
Process (computing)TrailMilitary operationRepresentation (politics)Factory (trading post)Multiplication signRight angleSequenceMicroprocessorVirtual machineOperator (mathematics)Computer programCodeDigital rights managementData typeDeclarative programmingRoutingLecture/ConferenceComputer animation
TrailProcess (computing)Military operationRepresentation (politics)Process (computing)TrailVirtual machineRoutingOperator (mathematics)NumberElectronic mailing listSequencePoisson-Klammer1 (number)Computer animation
Disk read-and-write headMilitary operationFunction (mathematics)Functional (mathematics)Disk read-and-write headFactory (trading post)Data typeElectronic signatureType theoryOperator (mathematics)RoutingMereologyDifferent (Kate Ryan album)Electronic mailing listSlide ruleoutputNichtlineares GleichungssystemSocial classPattern matchingPoisson-KlammerCodeElement (mathematics)Pattern languageTelecommunicationCASE <Informatik>Roundness (object)Boolean algebraComputer animation
Computer configurationCodeOperator (mathematics)RoutingSlide ruleRow (database)Data typeExpert systemComputer configurationConstructor (object-oriented programming)Type theoryRight angleComputer programSocial classSubsetObject (grammar)Lecture/ConferenceComputer animation
Military operationComputer configurationDisk read-and-write headFunction (mathematics)Formal grammarComputer programJava appletFunctional (mathematics)Disk read-and-write headComputer configurationRoutingBitOperator (mathematics)Process (computing)TrailArrow of timeElectronic mailing listWritingType theoryLecture/ConferenceComputer animation
Military operationComputer configurationFunction (mathematics)RoutingArrow of timeoutputOperator (mathematics)Functional (mathematics)Computer configurationElectronic mailing listNumberTupleComputer animation
Military operationComputer configurationFunction (mathematics)Nichtlineares GleichungssystemCodeRoutingElectronic mailing listBoolean algebraSummierbarkeitLine (geometry)Element (mathematics)Virtual machineCASE <Informatik>Multiplication signEndliche ModelltheorieComputer animationLecture/Conference
Operations researchTime zonePhysical systemSlide ruleSet (mathematics)FrequencyEndliche ModelltheorieMultiplication signSequenceMereologyComputer animationLecture/Conference
Military operationElement (mathematics)Time zoneRepresentation (politics)RoutingOperator (mathematics)Time zoneVirtual machineElectronic mailing listElement (mathematics)System callMultiplication signSequenceRight angleComputer animation
TrailProcess (computing)Time zoneMultiplication signGoodness of fitRight angleProcess (computing)RoutingQueue (abstract data type)Trail2 (number)Lecture/ConferenceComputer animation
Time zoneElement (mathematics)Military operationTime zoneRoutingElement (mathematics)QuicksortElectronic mailing listOperator (mathematics)Point (geometry)CodeGoodness of fitRight angleType theoryInformationQueue (abstract data type)Similarity (geometry)Computer animation
TrailProcess (computing)Military operationElement (mathematics)Time zoneRoutingElement (mathematics)Time zoneQueue (abstract data type)Right angleMultiplication signElectronic mailing listOperator (mathematics)Endliche ModelltheoriePhysical systemObject-oriented programmingComputer animation
Military operationElement (mathematics)Time zoneObject (grammar)Endliche ModelltheorieComputer programCodeFunctional (mathematics)AdditionPhysical systemType theoryInformationFunctional programmingElectronic mailing listElement (mathematics)Goodness of fitRoutingLevel (video gaming)MereologyLecture/Conference
Disk read-and-write headMilitary operationComputer configurationElement (mathematics)Function (mathematics)Functional (mathematics)Multiplication signQueue (abstract data type)RoutingDisk read-and-write headElement (mathematics)Time zoneElectronic mailing list
Computer configurationMilitary operationProcess (computing)Queue (abstract data type)TrailRoutingTime zoneMultiplication signCASE <Informatik>Computer animation
Military operationElement (mathematics)Time zoneComputer configurationMultiplication signRoutingQueue (abstract data type)Point (geometry)Element (mathematics)Limit (category theory)Operator (mathematics)Time zoneProcess (computing)CodeComputer animation
Element (mathematics)Military operationTime zoneTrailProcess (computing)State of matterPublic domainRoutingOrder (biology)Electronic mailing listElement (mathematics)Time zoneQueue (abstract data type)Operator (mathematics)RandomizationLimit (category theory)CodeMultiplication signType theoryGoodness of fitLecture/ConferenceComputer animation
Element (mathematics)Military operationState of matterDialectCodeLimit (category theory)TelecommunicationType theoryPublic domainMultiplication signQueue (abstract data type)Game theoryLevel (video gaming)Point (geometry)InformationComputer programFunctional programmingComputer animation
Wave packetMereologyMusical ensembleMultiplication signLine (geometry)InternetworkingVulnerability (computing)Lecture/Conference
Point (geometry)Functional programmingDifferent (Kate Ryan album)Formal languageVulnerability (computing)Right anglePrime idealProgramming paradigmMultiplication signEndliche ModelltheorieInternetworkingNumberLecture/Conference
Functional programmingDescriptive statisticsMultiplication signMusical ensemblePresentation of a groupFunctional (mathematics)Endliche ModelltheorieSoftwareSlide ruleCodeImperative programmingBitPoint (geometry)State observerGoodness of fitInteractive televisionDependent and independent variablesInterrupt <Informatik>Internet der DingeParameter (computer programming)Computer hardwareData structurePattern languageState transition systemNumberAbstractionElectronic mailing listLecture/ConferenceMeeting/Interview
1 (number)CodeFunctional programmingMicroprocessorType theoryWritingNumberCompilerMultiplication signAllgemeine AlgebraComputer programFormal verificationProof theoryLimit (category theory)Imperative programmingCategory of beingFunctional (mathematics)Java appletOrder of magnitudeComputer configurationMereologyValidity (statistics)Sound effectAlgebraPhysical systemSpectrum (functional analysis)Formal languageBitIntegrated development environmentChemical equationReading (process)Interactive televisionRevision controlLine (geometry)Queue (abstract data type)Object-oriented programmingRight angleContext awarenessMonad (category theory)AbstractionProjective planeElectronic signatureElectronic mailing listNichtlineares GleichungssystemTorusDefault (computer science)Variable (mathematics)SpacetimeGoodness of fitVulnerability (computing)Slide ruleLecture/Conference
WikiMechanism designProcess (computing)Module (mathematics)TelecommunicationControl flowMultiplication signRight angleFunctional programmingImplementationMathematicsFunctional (mathematics)Slide ruleBitPublic domainLattice (order)Object-oriented programmingRoutingClient (computing)Variable (mathematics)Object (grammar)Formal languageCodeDifferent (Kate Ryan album)NumberModul <Datentyp>Social class3 (number)Instance (computer science)Normal (geometry)Lecture/Conference
Semiconductor memoryCartesian closed categorySicRoundness (object)Lecture/Conference
Transcript: English(auto-generated)
So, our first talk is going to be presented by two speakers, Michael Sperber and Nicole
Rauch. Michael is the CEO of Active Group. He's been developing software and teaching programming for over 30 years, and Nicole is an independent software developer focusing on domain-driven design and event streaming, and she's been organizing software craftsmanship
conferences, so please give them a big round of applause for this talk. Good morning, everyone. This thing is on. Hey, it works. Excellent. Cool. So, self-crossing code. I think before we say farewell, we should
think about what it actually is, and so I thought I'd maybe get a presentation first. Ah, excellent. So, first, maybe we should talk a little bit about what self-crossing code is, and so I brought something for you, for your entertainment.
And here we go. This is some code I found in an Eclipse tutorial. If you know a little bit about Eclipse, you can see this by looking at this eye thing here. Yeah, and this actually, I mean, I have no idea what this does, you know? You have this adapter factory, which is really, like, okay.
And then we get an adapter, and there's lots of stuff going on, but what actually is this doing? So there's to-do. Okay, this gives a hunch that this might be this famous to-do example, but then I have no idea what's happening here.
But maybe that's just Eclipse, right? In Eclipse, everything is an adapter to something else. Okay, maybe. So, okay. I had expected you to say something like this, so I thought I'd bring another example.
And this actually is from an open source project. And this actually is a native query interpreter initiator. I also want an interpreter initiator. Who doesn't? And also it's a session factory service initiator. Wow. I'm getting impressed. So, and then it also does lots of stuff,
and then, okay, we have initiate service, and then we have another initiate service. And then at the end, wow, we have this get service initiated. Wow. Okay. So, fine. But, I mean, that's just a bunch of kids doing open source software, right? Yeah, this is open source.
So these are all hobbyists, right? So, I mean, what would you expect from something like that, right? Okay, fair enough. So I brought a professional example. Oh, I see. Everybody stand back now. So here's a professional example. So this is from a system that does queries of some sort. I think there's a bit shape in translation from German to French to English in here somewhere.
So you can see that it does either full text search or it does non full text search or something like that. And so obviously in the initialization of some C++ class, it checks that flag, and it instantiates some object either to the full text variant or the non full text variant, right? And you would think this is object oriented design. You just go and call methods through that one instance variable that you have there.
If and else is so object oriented. Yeah, well, that's just the constructor, right? This is not the bad part. The bad part is that every single method that actually does something like this one looks like this, right? It checks that flag again, and it either calls full text recherche, which I guess also has something to do with full text search.
You can see that there's lines commented out, and nobody remembered to leave a comment as to why it's commented out. And you can see that this code is really fragile, right? If you want to maintain that kind of code, every method looks like this.
You always need to remember to check that flag before you do anything to be sure that, oh, I'm here or I'm there. OK? Yeah, so I mean, OK, so the fact that somebody uses an object oriented programming language does not necessarily imply they actually understand what object orientation is all about, right?
So maybe they are just crappy programmers, OK? So they happen to use this, and then they messed it up on the way, you know? You mean non-crappy programmers can produce crappy code? Now you're getting me confused. I think you have another example coming up.
Yes, I have a much better example here, a real object oriented example. So this is finance, right? So here we have options. In this case, just call options. And so the financial guys want to talk about those options.
But there are so many different kinds of options, so they cannot talk about each of them individually, and so they want to group them together in something they call a basket. So up here you can see this basket, and it contains Google and Facebook because they are sort of like the same, you know? So they just group them together in this basket, and then they want to
talk about properties of this basket of all those options that are contained in it. And for example here, they implement this market data, and so this is standard object oriented business, like everything is a class, right? And there we have two methods in there because that's also standard object oriented business.
We have a class, and then we have methods in there. And the first method, getSpot, just gives us the spot price. So all of these options have a number in the real world, and that's why they number this here. And for the fund, they call this sicova.
I have no idea why. This seems to be a French word for I don't know what it means, but yeah, just go with this. So this maturity thing, that's the date at which point the option expires, right? Yeah, so that's for the volatility. So you get the volatility for an option.
An option is defined by the underlying asset, and by the date it's due, and also by the price it's supposed to have then. And that's what is encoded here. So we have the option with this long, and then we have the maturity, which is a point in time. So we can properly use a double for this, I think.
And then we have the strike, which is a price, and probably some of you know that it's not a very good idea to deal with money in terms of doubles, but on the other hand, it's fairly common in banking. So let's do this here as well, OK? Fine, so yeah, that's it.
Yeah, and then what they actually want to do, so they don't only want to look at the world as it is, but those guys with the suspenders, they want to analyze and see what might happen if something would happen. So they want to play what-if games.
And for this what-if game here, they take the spot price, and they actually want to shift it. So they want to say, what if the spot price were different, and what would happen then with my options, right? And here, they just, you know, so if you want to modify something in object orientation,
you write a derived class. And this is the derived class, spot shifted market data, and this derived class overwrites the getSpot method, and it takes the value of the parent class and multiplies it with a factor, OK?
Sounds straightforward so far. And then, of course, they don't only want to multiply this with a factor, but they also want to do other modifications, and they want to be able to do all these modifications without recompiling, so they want to play around with these, and they don't want to recompile their code every time they change something,
so they want to have a dynamically configurable code base, so to speak, or dynamically configurable market data. And if you look this up in the object-oriented literature, you come up with the decorator pattern. And so the decorator pattern is something that allows you to dynamically modify your code.
So you have a component, and then you derive a decorator, and the decorator as a delegate to something else you want to plug in, basically. And this is how they implemented the delegate. So they wrote the decorator as a derived class, and then they have the real object in there,
and for the getSpot method, here they just ask the getSpot method of the underlying object. Fair enough. And now, going back to the baskets where I started out initially,
so what they did in this one derived modification here, they multiplied with a factor, and now in the basket, here they get a bunch of options, say, or a bunch of assets. And now they want to calculate this for all of them,
and they go into this recursively, and it's very hard to see here, but what actually happens is they go into this recursively and do this modified operation for all of them, and because of late binding, it happens that they keep getting through this upper method again and again,
so adding the factor again and again. And of course they did not figure this out by looking at the code because it's, like I said, really hard to understand, and of course this is all just small snippets of the code, but this is the essence. But they found this because the values were incorrect, right?
And so what they did is they compensated for this. And for example here is the most interesting part, I think. Does the first market data derive from the second one? So they check whether they have this chain going on,
and then they do something differently. Well, I mean this is production code, right? And this is still in operation, and probably this method by now is like hundreds of lines long because they have so many edge cases they need to compensate for.
Yeah, I can imagine that. But I mean it's obvious they just shouldn't have done this in C++ or using object-oriented programming, right? So do you have a better suggestion? Oh, absolutely, absolutely. We have slides on this. You have slides? People should have used functional programming, right?
Which is great because... Oh, how could I forget this? Of course, you would say that. I'm the functional programming person here on stage. So functional programming has all these advantages, right? You can have immutable data. Immutable data means you have less coupling, you don't have these complicated effects going on that you saw earlier maybe. Functional programming is very close to mathematics,
so you can apply formal verification. Isn't that scary? Yeah, and you can use all these great mathematical things in there. You can have catamorphisms, you can have bifunctures. That's my new favorite thing. Monads, monadic profunctures is also something that we've been using lately. That's great. Kleisli arrows, there's all these wonderful things in functional programming, and they solve all of these problems.
Yes, I could... Why are you laughing? Who's laughing? I should have imagined you saying something like this. Have you ever considered that you're tackling the problem from the wrong angle? I mean, you and your horde of IT tech nerds,
you're sitting in your cave hacking away, having your hood over your head, and just sitting there and hacking and hacking. So that problem solved. Anyway, yeah. And I mean, really, just throwing tech at the problem is not a solution.
It's actually part of the problem. But we're producing software, we're producing tech, right? Have you gone through this thing here? There's tech outside everywhere. How do you make that? Probably not by sitting in the corner and just writing hacking away.
OK. Have you considered that there is more to it? That it's not only just tech, that you need to talk to each other? Yesterday, I saw this robot walking around in a circle, and it said, I need new code, please talk to me, right? This is something like this.
OK. So we need to talk to each other. It's not only tech. Tech is nice and everything. So do you have like a pattern manual for that? A pattern manual, yes, of course. There are talking patterns, actually, for people like you. So, go ahead.
Educate me. OK. So, I mean, there were many approaches over the years, right? Some approaches were, for example, looking at agile software development, you know? And it says individuals and interactions over processes and tools.
Tech. OK. So let's talk together, and let's figure out things. OK. Well, but it does say working software also, right? One of four, you know, says working software, because, of course, we also want working software, right? I mean, just talking and no coding is also not the answer.
Anyway, so last year we were at this conference, right? And you were probably talking to somebody, but I actually attended the keynote. And it was by somebody who talked about what worked and what were the ongoing problems in software engineering. And this was an agile company, right? They do everything in an agile manner. So supposedly they communicate all the time.
But still, when they look at where they spend all of their time and all of their work and effort, they say that they still spend 53% on maintenance and complexity and not on new features or, I have no idea what that professionalization thing is actually, but it takes up 18%. Looks nice. So let's get back to the technical problem, shall we?
Yes, I mean, we already saw this, right? In the market data example. I think much of this maintenance and complexity problems is caused that we're in a world consisting of objects and so everybody jumps on this object-oriented bandwagon, right?
And what they actually end up with is something like this. OK. And this is sort of, like, not helpful. So maybe, but I would like to explain this maybe in a different way. So modern object-oriented programming,
well, you can all laugh at that slide before, but we really need to understand the problem, right? The technical problem is this, right? So at the heart of modern object-oriented programming, something called imperative programming, where all these objects that you showed on the previous slides, they have what's called encapsulated state, OK?
There's some state in there, and what happens is the world progresses by all these objects sending messages to each other, and as a result of a message, some code gets executed that modifies that encapsulated state. Now, the thing was, I mean, object-oriented programming was originally developed to support simulations of the real world,
and the problem is that the real world just does not work like that. The real world is not a bunch of objects sending messages to each other. So one simple example that maybe can help explain that is, speaking of elephants, right? You had a great elephant slide. So there's an elephant, and the elephant comes in from the jungle and walks into some kind of room, right?
And the object-oriented model for this is, well, all the entities get models, get objects, so the elephant has an object, the jungle has an object, and the room that the elephant enters has an object that represents them, and you have the sequence of method calls or message sends that tries to reproduce that sequence as well.
You know, the elephant exits the jungle, and the elephant enters the room, right? The problem is that the exiting of the jungle and the entering of the room are one and the same act. So the real world has dependencies. It's not just a bunch of isolated entities that are sending messages to each other.
Things hang together in the real world. So I think a more useful model for thinking about programs and how programs should model the real world should really go through the way that we perceive things. So if you watch a soccer game these days, there's lots of objects that you see, right?
So you see 22 players, maybe. You see a ball, you see the referees, and you see lots of people in the audience, and they all move. Now, so they all change their internal state, if that's the model that you use. Now, if you want to know what's going on in the football field, you need to observe all of these changes. But do you know what the object-oriented model is for observing changes?
Something called the observer pattern, which means that you register each of these objects and tell them, well, if anything changes with you, send me a message. You know, dear ball, send me a message. If you move, you do that with all the players. Supposedly, you do that with all the 20,000 audience members.
And of course, when you leave the stadium, you all send the messages, oh, no, I'm no longer interested in what you're doing, right? The world doesn't work like that. It has another problem, is that all these messages will arrive in some sort of sequential order. And that also would mean that with all of these objects moving around, we would observe inconsistencies all the time,
the same way that we observed it with the elephants going into the room, right? If you remember, there was an inconsistent state in the middle here, which was that after the first step, the elephant is, for a brief amount of time, is nowhere. It has exited the jungle, but it has not entered the room yet.
And the same is true, of course, if we have many moving objects. But yet, we never observe one person getting up and suddenly appearing in another place, or two people appearing in the same place at the same time. And that's because our perceptive apparatus creates consistent snapshots of what we observe, right?
We look at something, and it gets stored in memory, and we can think about it for a little amount of time and analyze what's going on. And of course, we remember things that were in the past, which is also something that an object-oriented model cannot do. So, I think there's fundamental problems with this object-oriented model of programming, and that's one of the fundamental things
that leads to that soul-crushing code that we've been talking about. Yeah, that actually reminds me of a very interesting thing that lots of people are using, and that's in the UI, and it's called the MVC pattern, or Model View Controller. And if you have ever worked with this, you can see here that this all goes in circles,
and you can go in any direction, and then you end up here again, or you go this way around, or anything, or follow this dashed line, and so you can go from anywhere to everywhere. And this leads to the obvious problem that if you have changes in the model and changes in the view,
they need to hopefully be corresponding, or maybe not. And what do you do about this? So, what you end up with, if you do this enough, and if you aren't very, very careful, you end up with this. Certainly my MVC programs have always looked like that, right?
Yes. It feels really familiar, doesn't it? Yeah, it does. And I think that's also what Alan Kay was talking about back in the day. So, this is a quote from 1996, but I think the paper just appeared then, but the original quote is much older.
And so, he said, OK, OOP had those motivations that we described here, but eventually we need to overcome this model, and we need to find something better, and eliminate it altogether, is what he says here.
OK, but that never happened, right? No, I don't think so. Never happened. So, these days, if you look for examples of how object-oriented programming works, it always is about encapsulated state that Alan Kay wanted to get rid of. So, I think that's the first thing when I searched for object-oriented examples, was something with students,
and you can immediately see that a lot of attributes that you have there go through some method that modifies them. My favorite one is that you have the student, and you can set the grade point average of the student. So, if you're not happy with the grades that your kid is getting, you just sent the object a message. Get a perfect GPA there.
And let me reiterate, Nicole, of course people should have used functional programming, which has all these simple languages, less complexity, higher productivity, less bugs. We have all these powerful type systems. We can do property-based testing. It all goes on and on. We've got more predictable behavior. Generally, testing is easier,
because we don't need set up and tear down methods. You get lower couplings. You have fewer dependency cycles. So, I didn't even say monad here in this list. So, you get all these concrete advantages from doing functional programming. So, that's what people should do to solve those problems. So, do you remember Fred Brooks?
He said, there is no silver bullet. Okay. So, what do you say about that? Fred Brooks is an old guy, right? Yes. And what about you? Yeah, I guess I am too. I'm getting there. Yeah, well, so, Fred Brooks said that, but he's an old guy.
So, let me get you one example of why that maybe is not true. So, in the early 90s actually, there was a big study conducted by the US Navy on the effectiveness of different programming languages. And they had one set problem that was about determining the regions of influence of warships
and they had different teams write solutions for their problem in different languages. And what they ended up doing is they gave that also to people who were using functional programming, specifically in the Haskell programming language, which was still pretty young back then. And you can see, well, the solution in Haskell
is much shorter than the solution C++, definitely less than 10 times as short than the C++ solution. I think Java wasn't as big then, but I think the factor would also be around between three and 10 somewhere. Also, what's maybe interesting is that there are two Haskell solutions, one at the top and one at the bottom.
Probably they just split the code so the numbers look nice. Yeah, yeah, you would need to add them up. That would be interesting. But what they did is they had a Haskell expert write a solution and then they also gave the solution to a student, I think, who learned Haskell for two or three weeks. And who also wrote a solution.
And if you look at development time, so somebody took 10 hours and somebody took eight hours, and the eight hours is the student. That's because the Haskell expert tried to put many interesting flourishes and super cool programming techniques into the program, but the student was actually doing pretty well. So if that's not what a silver bullet looks like,
I don't know what would. OK, so the Yale study, right? Yeah. They got a fixed set of instructions and they just had to code those instructions. Do I remember that correctly? Yeah, yeah, yeah. OK, so do you ever experience that in the real world,
getting a fixed set of instructions from your client and then just implementing this? And they never change their mind, they never come up with new ideas, they never say, oh, I forgot something? Well, I actually don't experience this.
Let me think about it. Maybe you can move on. So that's what we need to consider as well, coming back to the elephant, right? OK. Talking to each other. Everybody has different ideas. Now you can start with that agile stuff again.
Everybody has different ideas when they look at something and everybody describes things differently. And so what we need to do is to figure this out together. You know, coding a bit, talking a bit, talking a bit, coding a bit. And so this needs to go hand in hand and this is sort of agile, you know?
And that doesn't mean scrum and, you know, standing in a circle every day or something. Relax, OK? So personally, I like to communicate with code. Yeah, you can do that too. I think of an example that we were working on in our project that was in a semiconductor factory. So this was serious business.
I see. Anyway, so when we started this, I don't know, well, you all know this, right? When we started this, I thought, well, a semiconductor, the way it gets made, there's a big machine. You put in a piece of silicone and you go like this and chunk and out comes a microprocessor. And it doesn't really work that way.
One of the reasons is just that the modern chip consists of many layers. Another one is that there's just many different production steps that are necessary for making even a single layer. And some of the machines that make a layer are so expensive that you can't just make an assembly line. And also a lot of things break all the time in a semiconductor factory.
So it makes no sense to just have an assembly line and push things through that. But things just move around among the different machines in a semiconductor factory, right? And so what's important is that each chip or each wafer undergoes a sequence of steps in the factory, and that needs to be managed. And those steps, it's typically for big microprocessors
that might be like 1,000 steps. So you need to manage something that's called a route, which is just a sequence of operations. And now here's a bunch of Haskell code. Haskell code is great because the programs are so short that they fit on slides. But if there's something unclear about that code, then I invite you to interrupt me and ask.
So first of all, you can read that declaration at the beginning. It says data operation. And that's just a simplified data type that describes what an operation would be. And it says, and you can read that vertical bar as or. So it says an operation is either track in or process or track out. And tracking in just means putting a wafer into a machine
and process as you do something inside the machine and track out as you take it out of the machine. And then the next thing is that a route is just a sequence of operations. And these brackets that you see there, they mean list off. So what it says is a route is a list of operations.
And down here, you have an example for a route, for a very simple route that says, well, one route, route number one, might be a list of the following operations. You put a wafer into a machine. You process it. You process it some more. And then you take it out again. Clear so far? Everybody nod? Everybody who's still awake nod?
OK. So don't be afraid to ask. So one thing that you do is when you have data types, as you just saw, is you define functions on them that describe some aspect of what happens in a FAB in a semiconductor factory. So in a FAB, what happens, of course,
is you need to execute the next step, the next operation that happens as part of making a semiconductor. And for that, we're making a function called route head, the head of the route. And what you do is you write a type signature. And type signatures are very good for communication, actually. So you put in a route. And you get out a single operation.
And then you write equations that describe what that function would do on different aspects or different classes of input. So in this case, you remember a route was a list of operations. And lists, there are two different kinds of lists. One type of list is the empty list. And the other kind of list is a list that has what's called a head
or a first element and a rest. And because there's two kinds of lists, you write two equations. And so that's why you see two things where it says, route head something equals to something else. And the first equation is for the empty list. This is why you have these two empty brackets. And the second one that says, well, it's a non-empty list.
And the first thing in that list is some operation op. So there's something called pattern matching. You match this onto the actual list that you see. And op then gets bound to that first operation. And we don't really care about what comes after that first operation. And so the second equation is pretty clear. If you want the head of a route that is not empty, you just take the first element of that list.
Okay, so far? And the other equation says, well, what do we do with an empty list, right? An empty list does not have an operation. So you're saying you're into the second slide of your beautiful Haskell code and you already don't know what to write there? Well, so we're communicating, right?
Okay, okay. So you're talking, you're talking to some of the experts, and you say, well, you have got an empty route. What's the first operation of an empty route? And he says, well, empty routes, they don't really have a first operation. They only maybe have an operation. And sometimes they don't. So for that, we can create a data type that says that something might sometimes be there
and sometimes it's not, and we'll just call it option. Are there any Haskell programmers in this room? Oh, okay. So this is built in, of course, as the maybe type. But I'm just making a separate type called the option type. And that says, well, the a says it can be anything, right? Anything in option a means it can either be there or not.
And for that, it has two constructors, or two different classes of maybe objects. And one are called the some objects, and the other one are called the none objects. Maybe we'll start with none. So anything can be a none. It just says that anything is not there, right? So anything can be of type option of a, and it means that something is not there.
And that is the type of that particular constructor. The other constructor says, well, that thing actually is there, and so the constructor has to accept something of type a and then give us something of type option of a. So you're saying it wraps this object? Yeah, it wraps the object. Okay. And so if you're not a Haskell programmer, but maybe an F sharp programmer or an ML programmer,
then that is what it looks like there. And I believe it's even built into Java these days, something called optional. So and now that means we can change our route head function a little bit because our first attempt didn't work out. And instead of saying route arrow operation, we write route arrow option operation.
It may seem trivial to you, but it already communicates a tiny little bit of something. And then we can write route head of the empty list as none. So there's no head of the empty route. Or if we have an operation coming out, we just write some in front.
And so if we use that example route that you saw earlier, where R1 was track in, process, process, track out, what we get is some track in. Okay? So that type communicates a little bit of what we do. Ah, it's already calling the shots. Very good.
The next thing that we might want to do is we don't want to always know only the first operation. We also want to know what happens after that. So we can use that option, and we already know that, of course, an empty route will not have something coming after that first operation. So we could write another function called route advance, and it takes a route as input. That's to the left of the arrow.
And it gives us both an operation and a route. That's why there's these two things in parentheses with a comma in between. So that's a tuple. So it gives us an operation and a route, but only sometimes when that actually exists, which is why there's an option wrapped around that. So what we want to do is if we take our route number one, we want to split it into that first operation and a list of the rest,
so it should split out the track in and then give us a list of the remaining, or a route of the remaining operations that are in there. Okay, so far? So it gets technical. Does anybody have a question? Okay, so don't hesitate to ask.
I'm looking at the clock. Ah, so then this is actually pretty easy to write now. Again, we need to make two equations, because a route is a list, and lists always need two equations. So we can say route advance of the empty list is none, and route advance of op, and the rest is we just return a sum of op and the rest, because the list already splits exactly along the line that we want it to
between the first and the remaining elements, right? So this is just very simple code, or at least it's short code, that communicates what routes are, right? I see. And? So, if I remember correctly, I mean you said you put the wafer into the machine and then it processes it.
If I remember correctly, some of these processing steps can be chemical reactions or something? And so it might be the case that they must happen in a certain amount of time or something? Is that true? Yeah. Okay, so what we could actually do is we could model something like this.
Yeah, I sneaked at your part of the slide, so I chucked this in. So what we actually could do is we could model something like those three steps here need to happen together in a set period of time? Yeah, so the chemical reactions mean that your wafer might go bad.
If you start the sequence of steps and you don't finish on time, then your wafer goes bad. Like etching and washing, for example? If you etch too much, then... That's always a problem in existing systems. Oh, is it? Okay. Ah, so cool. So maybe I can try and see how I can model this into your existing code?
Cool. So let's have a look. So what we first need is we have this route element here with this operation, right? And now we need another representation for a route element. And let's call this route QT zone for Q time zone.
And there, of course, we have the duration. That means the amount of time this step needs to be finished in, or this sequence of steps needs to be finished in. And then we have this list of operations here. We saw this before, right? The list of the operations. And then what this gives us is, of course, again, a route element.
So we can combine like ordinary steps, like putting the wafer into the machine. It doesn't matter how long it takes. Maybe it blocks the machine. But other than that, no issues come from that. But if we do the etching and the washing, for example, we would need to have a Q time zone
because we need to restrict the time that this takes in conjunction. Right? Is that correct so far? Good. And then if we look at our example, this is the previous example we had here. We could create another example. Where is my? There. R2.
And here we have a route Q time zone. Say it may only take five, whatever, seconds, say. And then we have two processes here that need to be finished within five seconds. And then we do the track out again. Okay? So far so clear?
Good. And then if we look at this, and we discover that here we have this route element list, and here we have this operation list. This is actually sort of similar, isn't it? So maybe we can make something out of this.
And maybe we can actually turn this down here into route elements as well. Oh. So that's what you were doing before, right? Before it set up there, it also set list of operation. Up there? Yeah, up there when it said type route, when you started, my code. My code had route equals list of operation.
Right? And now you did the same thing. Oh, yes. Yeah. Right. So now it's the same again. So it's both route elements. Yeah. Good point. And now if we look at this again, so maybe this actually means that this here is not just a list of route elements,
but maybe this is actually a list of routes. It's actually a route down there. So I actually derive some information here from the code, so we discover that our route queue time zone actually contains a route.
So what? Ah. Right? So if we look at this here, what we then can do here with this route element, so here we could plug in any route element, right?
For example, we could plug in a route queue time zone, which is also a route element. So coming from this example here, where we have just a flat list that just contains some route operations and a route queue time zone and then a route operation,
we could also stack them into each other. So a route queue time zone could again contain a route that contains a route queue time zone. That's pretty cool. Do you think that would happen in reality? Yeah, that's pretty cool because now we can nest queue time zones, and that's something that occurs in reality.
Oh, really? Does it? Oh, cool. And so your model has suggested that, but it's something that our old IT systems based on object-oriented programming couldn't model. That's pretty neat. So now I understand why you're aiming at functional programming and saying that you can model things better with it. Yeah, and this is pretty cool.
So we discovered this in the code, and then we were able to get back to the business people and check back with them, whether they would actually see this in practice and whether it's a valuable addition here. And we discovered that just from looking at the type information we had.
Yeah, and then we can continue this, and because now we have this list of route elements down there, we could actually say, oh, yeah, a list of route elements. We know what that is. This is actually a route. And now we go one level up.
So whenever we learn more about routes or whenever we change this here, this route thing, it will automatically be reflected in here because we abstracted it. And that's what functional programming is all about, abstracting things and figuring out what the common parts are.
I noticed you're agreeing with me. Very good. Excellent. So and now we can also, of course, check how our functions will be modified because now we need to go to all of our functions
and see whether they still work. And here we have this route head and also route element head. And now we need to extend this because the route element head works on the route element, and now we have a new route element, which is the route queue time zone. And, of course, if we want the route element head of the queue time zone,
this is, of course, the head of the containing route. And we have this neat function up here already, route head, which gives us the head of the route, and so we can just reuse this here. So even this has become simpler for us to implement
because we have discovered that there's a route in there instead of just a list. So no special handling. We can just revert to the standard function we already have. And if we look at the route advance, so if we want to proceed our route to the next operation
and proceed to the next step, then, of course, we also need to add this here, the queue time zone. And now the question is what happens if we advance into a queue time zone process
because somehow we need to keep track of when does it need to be finished. So initially we said, okay, it may only take like X time or D time, and now we need to keep track of whether this time is already taken up or not. And so in this case, what we actually do is we need to add another route element,
and that's a route queue time limit, which defines when a started operation needs to be finished. So it has an actual time, which is the point in time,
like now duration or something, just the finishing point in time. And then it's just the same as the route queue time zone. So this limits our process up to this end point of time. And now we can implement our route advance
because whenever we have a queue time zone, that's where we didn't know what to write before. So whenever we advance this route, then we know that we need to come up with a route queue time limit here. And whenever we have this queue time limit and we advance over that one,
then we know that we just need to basically behave like before. We need to split this up and also keep our time limit, of course, and then just proceed into this limited while keeping the time limit.
And here, if we start this out, then we need to determine the end point. So we take the current time, which we now need to pass in here at the top. So we take the current time, add the duration, and then we know when we need to be finished with this process.
And then in here, we just work on every step while keeping the time limit. So your code suggested that there was a gap in your understanding of what needs to be represented, right? Yes, so I didn't know what to implement for the route advance.
And now I know that, yeah, I can handle this. So watching this, I'm thinking that there's still a little, if I look at it with the eye of a domain person, I think there's still a little problem in there. Oh, is there? Which is, yeah, if you look at this, right, remember a route element is something that can occur anywhere in the middle, at the beginning, at the end of a route. So it's these three things.
Obviously, we can have queue time zones anywhere, we can have operations anywhere. But the thing is, we can only enter a queue time zone when it's at the beginning, right? Oh, I see. So you mean here we could have a random list in a random order. Yeah, that's a good point, actually. So this suggests that the queue time zone has been entered
because there's your route queue time limit, but there's still an operation there in front of it. Okay, yeah, that doesn't make sense. Yeah, that makes no sense. So if we could go back from the domain knowledge to the code now a little bit, we could refine that type further, and we could pull out the queue time limit from that type down there,
because these are all the things that occur in the middle of a route, and pull it up to a top-level type, and introduce an intermediate type that distinguishes between what's in the middle and what's at the beginning. Oh, I see. That's neat. So what we now have is we have this back and forth between the code, which yields insights about the domain and the domain,
and from the domain back to the code, and we can play that game. We can use the code for communication. Yeah, that's what I intended. If you understand this. Yeah, so that code no longer crushes my soul. Excellent. So I can say that, right? Yeah, same here. Cool. Okay. So that's the point we wanted to make.
So if you take functional programming, and if you add communication and discussions, and this going back and forth, and learning from both sides, and enriching both sides with the information coming from the other part, then you actually end up at a silver bullet.
Everybody's looking confused. That's a bullet train, a silver bullet train. Okay, we're done? Yeah, thank you. Thank you for a very entertaining talk.
We have some time for questions, Q&A, so if you have any questions, please line up next to the microphones. We have four microphones spread across the room, and we'll start from a question from the internet. So here's a question from the internet.
As an FP beginner with a weak background in math, would it be preferable to learn functional programming in pure functional language over languages that are multi-paradigm? So, should I take that one?
Okay. So I think the point is that there's many different functional programming languages, and Haskell happens to be what's called a pure one, but there are also languages that are hybrid between object-oriented and functional programming. Scala, I think, is a prime example right now. And, I mean, Scala is a fine language.
The problem is if you want to combine these two paradigms, you typically get something that's pretty complicated, so Scala is a complicated language that takes more time to master. Also, because you have both paradigms available to you at all times, you often get confused about what paradigm you should use in a given situation.
So I think both of us, we haven't really seen the great advantages you get from that hybrid model. Also, the problem is if you're a learner in FP, and you try to tackle this with something like Scala, you will inevitably fall back to what you know if you run into problems.
And so maybe just jump into the deep end and try to swim and see where you get at and get help on the internet. That was a good presentation, thank you.
Every time I see some functional programming, it's refreshing and it's interesting. But the description of your presentation was talking about using functional programming in IoT, so there was nothing specific to IoT in this presentation. There was no interaction with the hardware,
no interrupt handling, no nothing. How do you handle that, for example? Yeah, good point. I think we had a bunch of slides on that that we ended up dropping because of time. But my argument would be that IoT is the same software as any other software.
What's special about IoT is the risk that emanates from IoT, obviously. So if you want to do things like interrupt handling, I think my response to that would be to convert it into functional data structures.
And this gives you a deterministic model for handling that kind of stuff. So we talked about that. I think we talked a little bit about the observer pattern, which is analogous to what usually happens with interrupt handling, which is what you were talking about. And the way to do that really is to have, of course you have a tiny bit of imperative code that hooks your functional code to the hardware or whatever it is,
but to convert your interrupts into a list. And Haskell actually is pretty good at that. And that then gives you all the advantages of functional programming, the testability, the funky abstractions, and you can use that even on the interrupts. And it turns into software just like any other functional software. Microphone number one.
Hi, thank you for your talk. I have to write code for microprocessors. And most of the time I only have a C compiler, and if I'm lucky I get a C++ compiler. Where can I get a silver bullet? The old Haskell compiler used to compile to C.
Nowadays it doesn't do that anymore by default, but probably you can make it do that still? I'm sure you can still do that. But there's a number of functional languages that compile to C, so it's kind of difficult to give a one-shot answer. We've also done a project, for example,
where we get a lot of the advantages from functional programming by writing code in Haskell that generates the C code. And so it's difficult to give you one answer without knowing more details about what it is that you're doing. But there's certainly a spectrum of options available in that context.
So functional programming is pretty concise and pretty compact. So no one really wants to use large variable names. And I saw in your examples like a D and a T, TLs, RTs, and I don't think that they're so much better than the long versions you showed earlier.
Like, what is your take on that? Yes, so the general... So I'm also struggling a little bit with this. One thing is that this was fairly concrete code, right? But often you go into the abstractions, and in the abstraction, there it's arbitrary what you have.
So you can use short names because you're not talking about concrete things anyway. So that's why it's easier to use also more like abstract variable names. But what I actually do is I also use longer names.
So I would not always use D and RT and something like that to get a better grip on this. But one important thing you must not forget is that you have a function, right? And it's two lines, three lines. And so if you start out and you understand D and RT,
for example, from the signature, and reading three lines of code with a D and a RT in it, it's not that bad, right? And in object-oriented or Java or whatever, you sometimes have hundreds of lines, and then you have a D and a RT, and you read this for half an hour, and then, of course, you forget what it means.
So it's a bit of a balance. So I would use longer names as well probably, but sometimes also shorter because just the code is so short. One detail is I find myself using longer names than dynamically typed languages, right? They're dynamically typed functional languages, and there you don't have the type that spells out what that thing is,
and then you need to put it in the variable name. Microphone number one. Yeah, in one of the slides, you made the claim that functional programming lends itself to proving. How would you actually do this? Good question. That's another talk, right? I mean, in practice, so there's various ways of doing that.
So first of all, as you saw, right, a Haskell program is a bunch of equations, so you can use algebra as a mathematical technique to reason about functional programs. So first of all, going to the abstract aspect of that question, which is something, well, you can sort of do it with your Java program, but it is much harder to establish an algebraic way
of talking about Java programs. There's also plenty of tooling available to prove aspects of your programs in functional languages, starting with a classic tool called ACL2. We've given talks on something called Idris, so there's a newer breed of functional languages where you can put more proofs into the types of your languages.
So it tends to be just an order of magnitude easier to prove properties of functional programming because you can use algebra and equational reasoning as you would about Java programs. Does that answer your question a little bit? A bit, but I think Idris uses dependent types,
and isn't it possible to use it in imperative programming as well, maybe? I don't know. So is that specific to functional programming dependent types, or could it be used in imperative programming? Even the way that Idris talks about imperative programming is functional,
using monads, by the way. So there is that, and there's this whole spiel about reasoning about effects. But the thing is effects, side effects, you have an imperative programming, they don't make it impossible to reason about programs, but they make it much, much harder. And so in a functional program,
in a proper functional program that doesn't crush your soul, you tend to have large parts that are purely functional and that allow functional, that allow equational reasoning, and you have smaller parts that might be a little bit more difficult that are about the interaction with the imperative environment. Also, the thing that we did with the type system,
you remember, first we had the list, and we had the queue time limit in the middle, and that was an illegal state, and so we changed the type system to disallow this. And so actually already the compiler tells us, hey, this is forbidden code, right? And it's not syntactically wrong,
but it's semantically wrong, and that's what is also like a weak kind of validation or verification in my opinion. So we could talk about this all day, sorry. Another question from microphone number two.
I noticed that you didn't present any mechanism to hide your implementation or to make things private, things that you can do in C++, and I don't miss those mechanisms, but I would like to know your take on why, I think you don't miss them, so why do you don't miss them either?
No, they exist in functional languages as well, right? And so the mechanisms that you're familiar with, private things, modules, functional languages tend to not use objects and classes for modularization. I think that's the primary difference, but functional languages tend to always have mechanisms for doing that. They just differ between languages, so it's difficult to talk about this in a talk.
We could have told you how to do this in Haskell and write a module and hide things, but would have put more code on the slides. And the other aspect is that you don't really have to hide things because everything is pure. So if you call this function, I don't care, you know? You can't destroy anything,
whereas in object-oriented programming, you have this change my object to really bad something, you know, and you don't want anybody else to call this because it will really break things. And in functional programming, Chuck in some variables, get something out, do this as much as you want. I don't care.
That last one is the take I love, and I endorse fully. Microphone number three. You had some slides on the importance of communication. I have a hard time to see myself communicating with business people using Haskell code. How do you... What would you do about this code?
How would you do the communication with like normal people? This actually... I mean, we clean it up somewhat, but this actually happened. So it's sometimes a little bit of a process to get there. And sometimes... I mean, what you notice maybe in the code with the routes
was that playing with the Haskell code yielded domain insights that you could have also explained to somebody in a meeting, right? Without showing the code. And so the communication goes through the Haskell code. Maybe it doesn't happen by the Haskell code.
But all I can tell you is that that actually happens. We sometimes communicate with clients, showing them code and talking to them about is this really what you're doing? Is this what your domain is like? That happens. Happened to me as well. So it depends on your clients, you know. They need to have a bit of...
billions, so they can, you know, they can accept that they wouldn't understand everything, but if you like talk them through and say, look, here's this and this goes in and that comes out and what do you think about this? And then so you're just not throw the code at them, but you have a informed communication
say. This can also be contractually enforced, and I remember one instance where we did that. I've got a big round of applause for this talk. Thank you.