Lies My OO Teacher Told Me [TALK]
Sign up for weekly Clojure tips, software design, and a Clojure coding challenge.
Did you learn Object-Oriented Programming in school or at work? Were you told the same lies as I was? In this talk, I document the oversimplifications, generalizations, and misinformation my professors dished out that I had to discover as I learned Functional Programming.
**Eric Normand**: I did a year abroad in Paris. It was my final year. I was in a school called Paris 8, which is just north of the city. It's in another...It's like a suburb.
Coincidentally, that is where the Basilica is. There's all the tombs of all the kings and queens of France. This is another building. They like architecture but if you go inside, it's an acoustic nightmare. It's just this cavernous, big space that is not useful.
Anyway, one day they told me, "We're going to do registration day." This is the day you have to go to school. There's no Internet. This is 15 years ago. A lot of things didn't have Internet.
I was used to UNO where we had this phone system, where you would buy a big book called the catalog, and then you'd have the bulletin that would tell you all the courses for that semester, with all the codes for each session.
You call on the phone. It would be busy a lot, and you'd have to punch in these codes and it would say, "No, that one's full." It was a pain. For weeks, you would see people on the phone, trying to get in.
I was very surprised when I went to the university, and I go there and I'm like, "Where's the registration?" They're like, "Go up the steps." You go, and it's a piece of paper on the wall, and there's a list of classes. Then next to that, there's a sheet for every class and you put your name down.
The thing is, that's one department, so if you want a class in the History Department, you have to go across the building and write your name down for that class.
But then, you can never see all the classes at the same time, so you're like, "Wait. I signed up for a class at 8 o'clock. I have to go change that one because I need this one." It was a mess. It was total chaos. I was running around the building.
**Audience Member**: Question. If a class was full, did you cross somebody's name off and write your own?
**Eric**: You probably could.
No, if a class was full on the first day, they would say, "If you don't have a seat, you're not in the class." If you didn't get there early enough, that's another part of the system that's not included in that paper.
I was studying computer science and I remembered that this was something that we had actually studied. There's a case study, a problem, of how to code up a registration system in an object-oriented system.
My name is Eric Normand. This is my talk, "Lies My Object-Oriented Teacher Told Me." I have some disclaimers here because this is not an anti object-oriented talk.
My education was object-oriented. We did learn Java at school and my teachers wrote the textbook on object-oriented design. It's not me bashing object-oriented. It's me bashing that education.
A lot of people ask me how do I get out of my object-oriented mindset when I'm learning functional? How do I develop that? This is some of the things that I had to get rid of in my head when I was converting to functional, so that's another [inaudible 3:57] .
These are not just only applicable in functional programming and object-oriented, they're totally applicable.
This is something I was taught. One day at class, the teacher said this is how you model a problem in object-oriented.
You take an English description, the description of students registering for a class. You underline the nouns and those become your classes. Then you look for stuff like "have." You say a student has multiple classes, or, can have multiple...Then that becomes like a relationship between the class and the student. Then you underline all the verbs and those become the methods.
Let me see a show of hands. Who learned something like this in school?
**Audience Member**: Don't forget "is."
**Eric**: Oh yeah, and "is a". That's a hierarchy, like a sub-class relationship.
Wait. Show me your hands again. Oh, about half. Who learned it outside of school? It's not just about school. OK, cool.
**Audience Member**: Can you say what your first language was?
**Eric**: My first language?
**Audience Member**: Somebody taught you this. What was it?
**Eric**: It was Java.
Let's just go through it real quick. This is a university allows students to register for courses. Ta-te-ra-te-ta. You underline the nouns. Look, there's three. There's university, student, and course, and some are repeated. Then you draw a diagram like this. You have a student. There is no UML. I would do it in total UML, but I didn't have the software.
You have a student, and it's got some courses. You see there is an arrow there. There's a university, has students and courses. You can call register, which is a verb. It takes a course and adds it to this list. It probably calls that one too, to get back in there.
Then just for fun, like George was mentioning, you say a student is really a person, so we are going to do an "is a." Then, you are going to have different departments and a history course might be different from a math course, so we are going to have these kinds of lines too.
It's lies. It's all lies. It might not be lies in a way you expect. The first one may shock you.
**Eric**: Noun and verb? That is like middle school-level grammar that they're trying to say the software is based on. Like a student, it's a noun, right? But it's also a verb. You just change the ending and it goes to...It's a study. Studious, it's an adjective. What do you do with an adjective? Does that become like a sub-class? It's crazy.
Same for register. It's a verb, but it's also a noun, a register. Registration is a noun. Registry, the place where you register, that's a noun. They're saying that you should design your software around the way you happen to describe your problem, like the words you happen to use.
It's just an easy take-away. We need to look deeper than just the noun, and verb, and stuff. There's more options for modeling than just like things become a class and actions become a method.
Another thing I learned, this was maybe we went a little deeper than that other noun/verb thing. I learned that queries are like questions that you're asking the object, and so they don't modify any other state. It's just like "what's your name?" that kind of thing. Then, a command does modify or might modify, and it could also call a command on another object.
Here's some example questions. What is your name? What is your student ID? What classes are you registered for? Seems straight forward, right? Those should be queries. Then there's these actions which become commands in your design. You have to change your name to this, here's your new student ID, and register for that course.
But again, lies.
Those aren't very interesting questions. What is your name? That's like the first five minutes of knowing someone, you're asking these kind of question. What about these? Where do they fit in the query and command?
"What would it take for you to register this course?" That's a question, but is it modifying something? It's not straightforward. "I bet your schedule would be better if you added this. Is it? What do you think?" That's a question. "What was your schedule last year?" That's a question.
"I know you haven't decided, but could you give me an example schedule? Like what would your schedule look like even if you might not be able to register for those courses, what would it look like?"
These are questions and they don't fit into this query command system very well. We need a way to ask these questions. These are hypotheticals or counterfactuals, that kind of thing. Like another world, a multiple universe kind of thing. These are the interesting problems that we want to deal with.
That's the end of that one.
This one I learned was that you have a student that has some state, like a list, or an array, or some container of courses. That is going to be references to course objects. The same with course.students. It's going to point to student objects. You're going to have to keep them correlated so that if you ask the student what courses you're in, it's consistent with what the course lists.
Of course, the university is going to have a list and the student. They're all references. They're all pointers.
There's my animation again, it's lies. There's just so many problems with pointers. First, you're pointing to a mutable object. That's how we've designed it already. You're already in this deep water of dealing with things changing out from under you.
They're ephemeral. Every time you boot up your system, you turn it on, you've got different values for your pointers. Things get allocated in memory, totally out of your control.
What happens if you instantiate the same student object twice? Which could happen with an active record situation or something like that. Are you actually making the correct modifications? It just becomes a nightmare to keep it consistent.
What I've learnt over the years is to model it with a value. Something that's not going to change, something that you don't care if there's two copies of them because you can compare them equal, and it has to represent the identity. It doesn't matter when you boot and where in memory it is.
I'm going to point to someone. What is something that you could represent a student with that you have control over? That is immutable and has value? Ben?
**Audience Member**: I don't know. Maybe like some kind of hash or something?
**Eric**: Other Ben?
**Audience Member**: Their name.
**Eric**: Their name, OK. Brian?
**Audience Member**: Object.
**Audience Member**: What do you mean?
**Eric**: Somebody else? Thank you.
**Audience Member**: Birthdays.
**Audience Member**: ID? Like an ID?
**Eric**: An ID.
**Audience Member**: A GUID?
**Eric**: A GUID. Does the university already have a system for this?
**Audience Member**: Student ID.
**Eric**: Student ID.
**Audience Member**: [inaudible 13:03] .
**Eric**: Yeah. Student number, student ID. That's what I would use because this university already use it. Everyone already knows it. It's on their ID, whatever.
The course has a number as well. Yeah? Question? No? OK. It's immutable, right? A student ID is probably just a string, which should be immutable.
**Audience Member**: The course you used is probably not the best thing since there's a new one every year, but it still has the same ID.
**Eric**: Right, that's true. Maybe you should have the year in it.
**Audience Member**: You also can do SU16 [inaudible 13:39] .
**Eric**: Right, right.
**Audience Member**: It's not going to be the same.
**Audience Member**: You have to have [inaudible 13:43] semester, like unique ID for each iteration of a course.
**Audience Member**: Instance of a course.
**Audience Member**: Somebody. [laughs]
**Audience Member**: Yeah.
**Audience Member**: God, George.
**Audience Member**: [inaudible 13:53] it up.
**Audience Member**: Did I mention I'm also a database programmer? [inaudible 13:58] .
**Eric**: This is how you would set up your little university simulation. You construct the University, you construct the Student, construct the Course they want. Then you have to call register. You probably have to put these things into the University with whatever method. Call register method on Student with a Course, and then...
It's a lie.
**Eric**: Here is the question. Do we need to model all of that stuff? Is that the point of our system? It's to have a system that mimics what's happening in the real world? Like people going to this piece of paper and writing it down. Is this what's important? Why is the register method on Student?
It seems like the only reason was because we have that sentence in there that says, "A student registers for the course." Further down, with our design decisions, well, we need to record the course in there. That's why the method is on there — because it's going to modify it.
Why is the register method on Course? Well, because we need to record the student in there. What if someone says what students are in you? Well, they got to sync maybe, probably, at some point they [inaudible 15:28] . [laughs]
**Audience Member**: At some point in time, yes, because you can't call both of them at the same time.
**Eric**: Right. You will have locks and then it's a mess.
Why are we even modeling courses and students? That's, to me, the real question. Why are we even talking about a thing that's called a student in our system? I think the reason is object-oriented programming was made for simulations. It's really good at simulating stuff.
What should we model? What should we simulate? What are we building in this system? Here is the question for the group. If you had to use paper and pen, how would you model a registration system? A student-course registration system?
**Audience Member**: Probably the same way that you saw at the university. You take a piece of paper and you say, "This piece of paper represents the class, the course. This particular instance of the course for this term." We're going to write in the names of the students that are taking it because to the university ultimately what's...Then you would have a student [inaudible 17:00] .
**Audience Member**: And you don't have [inaudible 17:03] conditions because two students can't actually write at [inaudible 17:04] .
**Eric**: At the same time.
**Audience Member**: [inaudible 17:06] writing of the student IDs because it's like...
**Eric**: Yeah, a student ID. There was a student ID, and your name. Yeah.
**Audience Member**: OK.
**Audience Member**: It depends what you want to optimize for.
**Eric**: OK, you could explain?
**Audience Member**: If you want to optimize for people registering for things, then name, course ID. That's nice and easy. If you want to optimize for seeing who is registered for a particular course and making sure it doesn't overflow, then a separate a sheet of paper for each course and put your ID on there, like you described earlier.
It depends on what questions you're going to be asking. It's possible these are two different systems completely.
**Audience Member**: [inaudible 15:54]
**Eric**: Uh-huh. There's three people who talked and it seems like it's converged on this paper for a course, write your name down, that kind of thing. Does anyone have anything else? Any other suggestions? No.
**Audience Member**: You submitted [inaudible 18:15] .
**Eric**: Yeah, and then someone takes it to a room, and probably collates them and makes copies. That kind of thing.
**Audience Member**: Probably what's going to happen is someone would have to take all the lists and write for each student, have another piece of paper where they're writing out the student's taking course A at such and such time, da-de-da.
**Audience Member**: Because for example, the student's adviser will want to know what class they signed up for.
**Eric**: Ah, interesting. I don't think they did that in France, just as a side note. I remember being like, "Well, what courses did I register for?" And they're like, "We don't remember."
**Eric**: I mean, it was similar on the phone. You had to go to this little ATM-style terminal and get your thing printed out.
Anyway, these are all really good concerns, but you could think of how to solve it. OK, someone has to copy, write new papers, and stuff like that.
My question is why don't we just do that? Why don't we just make a system where you can enter in a student ID, and a course, and a course ID, and that's your registration? Why are we making a thing called a student, who's also a person, and then make a thing called a course? You just have two pieces of data that you're keeping in a many-to-many relationship.
**Audience Member**: Because people like to be cute.
**Eric**: They like to be cute. They like to model the universe.
**Audience Member**: It's like you're not designing the API. You're thinking about the data model and all the questions you'll ask. You're not thinking about all the data model concerns get linked into the API.
It's like, "Oh, we're going to need this method to look this up, this method to look this up." It seems like if you design it from an API-first standpoint, you'd maybe come up with a simpler [inaudible 20:13] .
**Eric**: Interesting. Interesting. Like use case first, what do we have to do? We need to have a place where we write everything down. If you went to use case-y, maybe you would even start writing the student's adviser is a person, so we need a class called Student Adviser that can know the students that he's advising. It just gets messy.
Lies. Everything I've said is a lie.
These have all been probably over-simplifications that the professor knew when they were telling me them. They're like straw men that I've been able to beat up on. I'm not saying object-oriented programming is better or worse. You can do all of this with object-oriented programming.
I think a lot of good programmers do. If you went to one of those object-oriented design gurus, they'd be like, "What are people doing with all of these classes?"
For instance, I was just reading the "Refactoring" book by Martin Fowler. So many of them are about blurring the line between method and object, and switching. "Oh, it's too big? Well, now make a new object just for that one function." It's not as clear as noun/verb.
Queries are interesting. It was the lie. The problem was these hypotheticals, these counterfactuals. Simulation, which is what object-oriented programming is all about, is actually great for counterfactuals.
The biggest problem is it actually takes a lot of code and boilerplate to set-up the simulation to create a new university, because you can't modify the one that is real. You have to make a new one. Then you have to make sure that if you're using an active record, it's not actually saving it into the database and stuff like that.
It's great for that kind of thing but it's rarely used because of all the boilerplate that has to go on. Value objects instead of pointers. They're better.
Modeling all of the actors, you don't have to do that. It's easy. It seems like that's what object-oriented programming is for. You just make a class and now you can do an instance of it. You're modeling actors. It's not what you're trying to do.
Object-oriented programming is good for exploring different ways to model because you do have all these nice classes and stuff. You might explore, "Oh, let's model detailed stuff," like a class hierarchy and stuff. Then you say, "Oh, let's model just this book [inaudible 23:34] ."
You can explore both because you've got all of the tools.
That's the end of my talk. Any questions?
**Eric**: Thank you.
**Audience Member**: When you say actors, is that specifically for object-oriented design or is that something that can be done in functional too?
**Eric**: When I said actors, I meant the student who is registering is like an actor in this situation.
**Audience Member**: It's a verb/noun? It's the nouns?
**Eric**: Yeah, the nouns, the people, the processes that are going on. You don't have to model the secretary separately.
**Audience Member**: Was that an oblique reference to the [inaudible 24:16] model?
**Audience Member**: Just the idea of all of the nouns.
**Audience Member**: Yeah. It reminds me of the adage that education is a series of diminishing lies.
**Audience Member**: I read somewhere, or heard something about where the value of object-oriented programming [inaudible 24:43] big because it auto-completes.
**Audience Member**: Interesting.
**Audience Member**: Tail wagging the dog.
**Audience Member**: I would think more static typing would be the thing with that, but I guess...
**Eric**: Right, because you know the type, the class of the thing you're typing.
**Audience Member**: You're talking Java.
**Eric**: Yeah, Java and C#, kind of thing.
**Audience Member**: Also, object-oriented programming is deceptively simple because it's so easy to teach that class where you're like write down your description. Underline the nouns. Underline the verbs. Turn them into classes, turn them into methods.
**Audience Member**: Because nobody [inaudible 25:19] and go," References are back."
**Audience Member**: I think that the industry tends to lean towards these things that are deceptively simple to teach and grant people [inaudible 25:30] because there are a lot of bad programmers out there, but you've got bodies. You've got [inaudible 25:35] .
**Audience Member**: That's an asset you're using...
**Audience Member**: ...counterfactual. What you would say is let's build the object-oriented version of this program. Then all of the stuff that breaks, write that down and then build a functional version of it.
**Eric**: Is that what you think I'm saying?
**Audience Member**: You said it would take too much time.
**Eric**: Oh yeah.
**Audience Member**: And too many resources.
**Audience Member**: When you're saying simulation, are you saying functional simulation, or you just mean [inaudible 26:10] it's great for counterfactual book? Counterfactual in object-oriented programming is a book.
**Eric**: I'm calling it a book. This is the registry for classes, and there is a page for each class. You would go to an office and you'd say, "I want to be in this class." And they'll write your student ID down on that page.
This is the database, basically, of classes. This thing has to have certain properties, and that's what you start modeling. What are the properties of this book that we want to capture in a computer system? That's the kind of modeling that you want to do.
If you can capture those properties, you can start to look and say we can simulate a world where the properties are different, or we can simulate a world where, say, how many students could even...
If we open up a new course, a basic English course that everyone's going to have to take anyway, how many schedules could be different? How many people might take that if they don't change anything else on their schedule?
Questions like that that you would want to ask if you were an administrator figuring out what courses to offer. That's really hard in these object-oriented systems. It's really hard.
**Audience Member**: That leads a little bit to, I was thinking, would be a good way to design something like this. Assuming that you actually wanted to create a good experience of registering people for the right thing, that's what you want to optimize for. You were kind of circling around this like, "Hmm," the registration thing.
Then, the registration, there's your object. It just has two IDs, to course, student. To make it interesting, it would be good to have a preference. The degree that you want that particular course...
**Audience Member**: I have relational database background. Relational database programming and object-oriented programming go hand-in-hand because everything is a table. The problem is every relationship becomes a table and it can become very...
If you were to put all these tables in to express the relationships between two things, so for example, student registered in a class is the ID of the instance of the class, then the ID of the student. Then you're creating tables for stuff representing rules, like the number of students who could be in a class, or requirements this, requires that, can become quite hellish in relational programming.
Actually, the question I would to ask, what I want to know is, how can functional programming help me overcome these lies? It's this background that from this school of hard-knocks where [inaudible 29:30] work in object-oriented and relational databases. How can I use functional programming to overcome these problems and become a better programmer overall?
**Audience Member**: Well, I wouldn't say necessarily functional programming, there's nothing wrong with objects and classes and of themselves. If you just go to back to an object class or something that holds state; you get rid of inheritance, so you just have this thing.
You can also get rid of mutable state. Now, every time it changes, you have a new thing. You can also get rid of methods. Why do you need a methods on object? You want to hold some state or something.
**Eric**: With static methods or something.
**Audience Member**: I like complaining something. Someone registering for a class doesn't mean they're registered for that class. That means they want to register for that class. A registration is a desire. It's an object. What are you storing? You just store a registration.
**Eric**: It's a message that gets...
**Audience Member**: Then you run it through a process and say OK, here's everyone's desire these classes. These are desired. Here's the outcome that is optimal for it. Notice how well that feeds into the functional aspect. That's input in, input-output. Any storage is incidental just because [inaudible 30:56] .
**Eric**: It's just some strategy, like first-come, first-serve or...
**Audience Member**: Yeah, and you want to run a simulation, sure. Try that, input in, output. Output becomes...
**Eric**: You just generate thousands of registrations, just randomly.
**Audience Member**: Simulated and [inaudible 31:12] .
**Eric**: Then you see what happens.
**Audience Member**: That's where the simulation comes in because before the students actually register for it, then you get to address hypothetical problems like requirements.
**Eric**: Can people actually graduate if there were four years like this? That kind of thing.
**Audience Member**: Do we really want to let anybody just register for any class?
**Audience Member**: Should we prioritize certain classes that everyone needs to take over elective classes?
**Eric**: Does a certain class fill up every simulation? Maybe we should have two.
**Audience Member**: I just think of the art department at UCF where that was how it basically worked. They told you until they were blue in the face that there were only so many seats, but when the day showed up, "All right, who needs overrides?"
**Audience Member**: I think it's a great combination of all of the different pieces of state that we're talking about and then the CQRS being the, "If you don't do it this way, you are going to be in so much pain. You're going to have so much side effects of that."
When you try register for a class, three other things happen. You're just looking to register for it, you don't want to side effect something else that's [inaudible 32:30] .
**Eric**: It is a great point, the command thing. I kind of glossed over this. The thing is there are commands that are more command-y than others. There are commands that write to the database which is a huge deal, versus there are commands that change a pointer or something.
You might say, in this OO simulation, we're allowed to call each other's commands, but we don't want to save anything out to the database.
**Audience Member**: I think if you have ever seen, Sandy Metz [inaudible 33:08] . She talks about commands and queries. She's a Ruby person and she's very much into OO.
One of the things she talked about with testing is there is a third class of methods that a command would basically just be something that I'm telling this object to change something about the state. The third class would be something that actually...
**Eric**: Sent an email or fired a missile.
**Audience Member**: ...and possibly mutate state of something else. The reason that she was bringing it up was in terms of testing, all you need to do is test that that thing is...If you are trying to test the interface, you just need to test that it sent that message off.
**Eric**: It sent the right message.
**Audience Member**: You don't actually need to test any [inaudible 33:55] .
**Audience Member**: That's you have to have so many layers. You have to have a persistence layer, and your DBAL, and your actual interface layer. If you don't keep all those separations of objects, you're going to have chaos when you actually try to do something that you don't expect originally.
If your model doesn't match perfectly, it's like "I want to try to register for this just to see if I can hold my spot for my friend, and then unregister for it." It turns out they only do that once a day and now you're locked into it. You can only register for it once. Lots of hypotheticals are really hard to model if you don't think of it up front.
**Audience Member**: I take a little bit of umbrage at this bad-mouthing of CQRS that's going on here.
**Eric**: CQRS is super important, right?
**Audience Member**: Yeah, but you are saying some commands are more command-y. Well, kind of.
**Eric**: It's a fault I have of Pascal, too, where they just classify everything as IO.
**Audience Member**: Yeah, but here's the thing, even the example you gave, really there you're complaining about an optimization that might be taken, when the real way that that system would actually evolve is you're just saving the commands and doing event sourcing.
Yeah, something might write to a database at some point, but that's just an optimization so you don't have to recreate event sourcing state from the beginning, but in theory, you can. [inaudible 35:16] .
**Eric**: Right, but you're agreeing with me that there are commands that you have said these are safe to call, and there are commands that you can't just call all the time.
**Audience Member**: Or they need to be validated against, but any command could be rejected.
**Eric**: Right, but what I'm saying is there are commands that will fire a missile, and there are commands that change a pointer.
**Eric**: That's the thing. You don't even know if a query won't fire a missile. [laughs]
**Audience Member**: Often times they do when you're actually [inaudible 35:48] .
**Eric**: What would happen if I fired this missile? Let me see. Whoosh.
**Audience Member**: That would be horrible.
**Eric**: Thank you. Any more questions? Yay, cool. Thanks a lot. This was fun.
**Audience Member**: [inaudible 36:08] .
**Audience Member**: All I see is the missile streaking away and somebody going red and following it.
**Audience Member**: Eric, I stopped the recorder.
**Eric**: Thank you.
**Audience Member**: I just found in C# there's situations where viewing something into the designer will run code.
**Eric**: Wait. What?
**Audience Member**: Yeah.