Teaching

Less abstract! Surprising effects of expressing rules of OOP in pictures

Less abstract! Surprising effects of expressing rules of OOP in pictures

by Ivan Nemytchenko

In his talk titled "OOP in Pictures" at RubyConf 2019, Ivan Nemytchenko explores the challenges of teaching and understanding Object-Oriented Programming (OOP) concepts due to their inherent abstraction. He outlines how visual representations can bridge the gap between high-level concepts and concrete code, ultimately making it easier for learners to grasp complex ideas. The talk is structured into three parts: establishing a foundation for the visual language, explaining advanced concepts, and applying these ideas in practical scenarios.

Key Points Discussed:
- Abstract Nature of Programming: The discussion begins with the importance of recognizing the difficulty in communicating abstract concepts, noting the frequent misalignment in understanding among programmers. Traditional tools like UML are not widely adopted or effective, highlighting the need for a more intuitive approach.
- Artistic Soldiers Method: As a pedagogical tool, Ivan introduces the "Artistic Soldiers Method," where students must develop an electric kettle without code. This method encourages students to visualize roles and responsibilities, fostering a deeper understanding of class and method interactions.
- Visualizing Methods and Classes: The talk uses analogies to illustrate how methods and arguments interact. For example, methods are depicted as hands with varying numbers of fingers, representing the number of arguments they can accept. Private methods are likened to internal arms, showing their restricted access.
- Design Patterns and Issues: Ivan illustrates common design issues using visual representations, such as a hand with too many fingers indicating methods that are overly complex. This approach aids in diagnosing structural problems in code.
- Advanced Concepts: The visualization of polymorphism demonstrates how methods across different objects can hold similar characteristics. Classes are represented as blueprints guiding object creation and behavior.
- Dependency Injection: The process of managing dependencies in methods is illustrated by visual metaphors like holes in arms, emphasizing the importance of their management for effective programming practices.
- Refactoring with Visualizations: Towards the conclusion, Ivan demonstrates how these visual tools can facilitate code refactoring, transforming chaotic representations into simplified ones, thereby fostering a clearer understanding of code structure.

Conclusions and Takeaways:

- Ivan emphasizes the practical utility of the developed visual language, which aids in teaching programming principles and documenting processes. While the models may not be perfect, they serve as effective tools for enhancing comprehension and communication in software development. For those interested in further exploration, Ivan invites the audience to engage with additional resources related to his "Painless Rails" project.

00:00:11.990 Thank you for coming! I can promise you that it will be fun and hopefully useful as well. I wasn't sure how to title my talk, which is why you may have seen two different titles in different places. But essentially, I call it "OOP in Pictures."
00:00:18.930 A little bit about me: I do some teaching, particularly for people learning Ruby as their first programming language. I also run an educational website and create online courses. For the past 15 years, I've been a freelance consultant, mostly working with legacy code, which is why I consider myself a complexity fighter.
00:00:39.359 I lived in Siberia for a year, and let me explain what that means. It confuses a lot of people. I am originally Russian, as you might guess from my name. I was born in a city called Omsk. Recently, I discovered that many people know about Omsk because when they fly from Europe to Asia, their flight path often crosses over it. About halfway through a long flight, feeling bored, they look at the flight monitor and see that they are flying over Omsk. This is how most people know about my city. Omsk is located in the Siberia region of Russia, which is important to clarify because I actually live in Serbia now.
00:02:52.680 It's essential to distinguish that Serbia is not Siberia and it is not Syria. When unprepared people hear these three different terms, they can easily mix them up because they sound similar and can all imply a distant location. Today, we will discuss the opposite issue: where a term can have different meanings in the minds of different people.
00:03:11.019 This confusion happens a lot in programming because the concepts we deal with are highly abstract. We build on layers of abstractions, and this makes it really hard to teach students. It can also be difficult to ensure that the person you are communicating with has the same understanding of a concept as you do. On the one hand, rules and principles are high-level, abstract concepts; on the other hand, code is low-level and very concrete. When you are overwhelmed with code, it becomes challenging to see the big picture. Various tools and methods attempt to bridge this gap, like CRC cards or UML diagrams, but very few people actively use them or find them appealing.
00:03:52.020 What we aim to do today is to fill that gap. You can expect to have fun and, hopefully, to improve in learning, teaching, and explaining complex concepts. You will learn how to visualize the big picture in your projects, identify architecture flaws, and track changes in the dynamics of your codebase. The talk consists of three parts: first, we will establish the foundation; second, we will use that foundation to explain some advanced concepts; and finally, we will see how we can apply that knowledge in practice.
00:04:59.260 Let's get started. I first came up with this idea at another Ruby conference in Russia. During a discussion with others who were teaching, we complained that OOP is too abstract and challenging to teach effectively. I casually suggested it would be great to illustrate concepts like dependency injection with a single picture, ensuring everyone understood it correctly. I later forgot this thought until I was preparing to teach students again.
00:06:38.070 In the course I'm teaching, there is a particular task where students must develop a smart electric kettle that can boil water correctly and safely without writing any code. They need to come up with the number of classes and methods, which can be challenging for some learners. To help them, I developed a method I call the "Artistic Soldiers Method." Imagine you are an officer with a squad of artistic soldiers. They excel at the roles assigned to them, regardless of how odd the assignment. For instance, if you want them to boil water, you would consider what roles they need to fulfill that mission.
00:07:56.440 As you assign roles, you think about the tasks each soldier must perform to boil water safely: someone must detect the presence of water, another should measure the temperature, etc. Through this exercise, we have identified several classes that together tackle the problem. This approach not only illustrates how to break down a problem but also leads to a visualization of the roles as a diagram, which makes complex ideas more digestible.
00:10:00.550 Now that we have established these roles, we need to illustrate how methods interact with them. Just as methods can have varying numbers of arguments, they can also be represented with arms in our illustrations. Some objects may sport two arms, while others might have one or more, serving to visualize the different number of arguments they can accept.
00:10:10.660 Consider the act of calling a method as shaking hands — if you pass an argument, it's like extending a hand for a handshake. Some methods may not require arguments, reflected in their design as having no fingers. Instead, methods can store values in an internal 'brain' and reuse them in later calls, illustrating how objects function.
00:11:09.800 What about the way methods return objects? We can visualize a door on the body of our object that opens to allow data to pass through. Let's talk about private methods: they resemble internal arms that no one outside can access. Exception handling is often uncomfortable; exceptions signal something has gone wrong. With our illustrations, we can identify where exceptions might occur in the process.
00:12:38.290 With these rules, we can already depict basic design patterns. For instance, if a method has too many arguments, represented by a hand with many fingers, it likely indicates a design issue. Similarly, arms that are too long suggest methods are overly complex or cumbersome. Through our visual language, we can easily visualize and diagnose various problems in code design. This understanding leads us to the next part of the discussion: more advanced concepts.
00:14:35.050 The concept of polymorphism can now be illustrated. Essentially, polymorphism can be viewed as having the same arms (methods) with the same characteristics across different objects. Certain objects may have varied arm structures but still retain consistency dans bed their performance. This conceptualization helps understand how polymorphism operates within code.
00:15:54.070 Now, while we have established understanding for objects, it’s crucial to discuss classes. Classes are essentially blueprints or spawning platforms from which we create objects. The lever in this scenario can be thought of similarly to how we code methods — both may provide means to instantiate objects and accept arguments. Here, we introduce the idea of topology, drawing comparisons to shapes such as donuts and cups which can represent the underlying structures of code.
00:17:07.539 Let’s visualize execution flow within our methods. While it may seem that sections of code execute sequentially like a linear path, the truth is that our code is much more intricate, resembling a complex amusement park. This complexity can also be illustrated using analogies such as a Rube Goldberg machine where the action of one object triggering another leads to an unexpected outcome, like a cup of tea.
00:19:02.639 In ideal situations, we aim for pure functions within our designs, where internal workings are sufficient without needing external inputs. However, sometimes external dependencies need to be accounted for, and it becomes essential to recognize how these affect execution flows. When we introduce dependencies into our methods, we visualize them as holes in our arms, indicating points where outside information may be required.
00:20:36.060 At this stage, we have generated a clear depiction of dependency injection. By comparing various approaches to executing methods, it becomes apparent why managing dependencies wisely is critical. Having the capability to channel these through our methods prevents leaks and results in more effective programming.
00:21:16.780 Now, let's transition to the final part of this discussion and see how we can utilize these concepts in practice. With our established visual vocabulary for object interactions, we can apply it to practical coding scenarios. I'll illustrate a case following the structure of a previous talk on refactoring, whereby we can visualize the process of adapting complicated code into something more manageable.
00:22:33.700 Initially, we encounter a somewhat chaotic visual representation of our code, where conditions complicate things significantly. As requirements evolve, we can perceive how the overall structure becomes more intricate, indicating signs of problematic design. By visualizing these changes, we can discern the complexity that arises in our code, seeing improvements while identifying where problems persist.
00:23:40.540 By employing this graphical method, it becomes easier to assess the code's condition and determine areas for improvement. For instance, upon seeing a figure with numerous swollen arms and legs, we immediately recognize symptoms of complexity that demand refactoring. The aim is to transition to a more simplified view, offering clarity over these behaviors.
00:25:52.880 The final resulting visualizations can reveal that the inherent complexity has not entirely vanished; instead, its form has simply shifted. The goal of simplifying code is to manage or redistribute complexity through either streamlined logic in a method or clearer hierarchies of related objects.
00:27:05.660 In conclusion, the visual notation we've developed serves as a simple yet effective tool for explaining programming principles. Each model we create may not be perfect, but some models can provide real utility. This visual language can be used for modeling application structures, documenting processes, and sharing insights.
00:29:09.180 If you're interested in exploring this further, follow the QR code, which links to resources and further reading. This is part of my ongoing project called "Painless Rails," aimed at simplifying the experience of using Rails. Should you have any questions, feel free to ask!