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!