 Once again, hello folks and again, so sorry about these technical issues my colleague commented on that title and set like they haven't told you because you didn't ask so here you have it and thanks you for coming, but actually I want to talk about software design which is frankly quite subjective. But there are some things I'm returning to when discussing code organization with junior developers. Now this talk has quite click baited title honestly and the abstract is well abstract. So what can you actually expect in this session. I will talk about some very fundamental principles from functional programming, but wait before you sign off. This won't be about category theory or first class functions and stuff like that. I would like to discuss some ideas useful regardless of language or platform you use. In particular, I will focus on distinction between actions and calculations or side or side effects. Maybe some of you probably consider this as a common knowledge every programmer should know. And I told so as well but I learned it's not the case so I designed this session mostly for that it should be approachable for beginners. And from that I will talk briefly about architectural patterns and some tips on how to use these ideas. I have code examples in basic JavaScript. I hope it won't be a problem even if you aren't familiar with the language, though I will refer to promises and asynchronous functions a bit. And I want to underline that no question is done. Just go to the Q&A and ask if anything is unclear and I look forward to continuing the discussion with you after the talk in work adventure. So briefly about me. You can actually start tweeting at me with this handle. I currently work as a developer advocate for Superface, though I currently don't do much advocacy, but I get to think a lot about architecture and code since our focus at Superface is on improving how developers integrate with APIs. I also occasionally teach web development courses for Chequitas and it greatly helps me to learn about pains of development as professional developers normally ignore. I previously worked as a developer and technique at Social Bakers and Czech Technical University and these experiences actually let me do this talk. At the university, I worked with the student developers on a project for aggregating data about research from various sources. At certain point, one student runs into a problem similar to this. He was transforming the data from one JSON file to another. And then he wanted to switch from local file to a remote API call. Something like this. Suddenly, he needed to deal with promises and asynchronous code and the code started to grow quite complex. Promises were popping up everywhere and also minded as soon as it wasn't a thing at the time. And it was an interesting learning moment until all of the code was synchronous. We didn't have to worry much about its side effects, but really it was a delusion. This code I outlined here is somewhat untrustworthy. The request can fail because the network is down. Writing the file can fail because we don't have the right permissions. This stuff depends on the outside world. And in between, there's a pure mapping logic. We can run this and be sure that we get the same result for the same input. Let's call the code which depends on the outside world action and the mapping logic is calculation. And actually this concept can sound familiar. Maybe you know it or you probably know it under different names. Actions are also known as impure functions or functions with side effects. They have effects outside of their realm. They change stuff, send emails, launch rockets or interact with outside sources of truth. Calculations are somewhat the opposite. Pure functions or mathematical functions. Given the same input, they give you the same output. This naming, actions and calculations is from Eric Normand, whose book I cite in this talk heavily. And I have a few more examples for illustration. So check this code. Do you think it's an action or calculation? Probably hit the chat. Let me know what do you think. No one wants to guess. Okay. So it's an action. Yeah. Thank you. Because it depends on current date. We literally get different results every time we run the function. We can adjust it like this. Now it's calculation because it operates only on the input. Also know that we are copying the input argument here to avoid mutation, to avoid changing the input arguments. How about this one? Okay. Is it action or calculation? Any guesses? Action. Right. This one works with a global variable outside of its scope. And the thing is if you run this twice, we get two items into the shopping cart array. So it has side effects. It changes. It doesn't, we cannot just run it multiple times without any side effects. So how about this one? This one mutates filtered array, right? So maybe it's an action. There is some mutation. Action, calculation. Okay. I am going too fast. Thanks for the feedback. Calculation. Right. Because the thing is the mutation is limited to this function. Actually, some folks tend to overdo it and they try to avoid mutations all the time at any cost. But really it's not necessary. You can be as imperative inside your function as you need. It's like whatever makes sense for you. How about this one? Action, calculation, action. Wow. Yes. Obviously, because we are fetching data from network and it isn't guaranteed to give us the same results. We can get JSON or maybe we can get HTML page or maybe we can even get a network error. And how about this one? Any guesses? So I would say this one is a trick question because we are calling the calculate payout function. And we don't really know what this one, this function is doing. So the thing is actions have this ugly property where they infect any code that touches them. So can you spot an action in this code? I won't prolong it too much. It's right here. The fact that function doesn't return anything or we ignore the return value is a strong indicator that it's an action. But since this function calls an action, it's an action as well. And so it's affiliate payout until we reach the top level of the program. When reading the code, I usually ask myself what color is this function? I've got this idea from Bob Neisturm who wrote about how hard it is to work with a synchronous code. His point was a bit different, but the idea of coloring the function stuck with me. Imagine that this is a call graph of functions. Functions on the left call the functions to the right. We can say they depend on them. Now, if we call our calculations as blue and actions as red, we can see how they spread. If the function touches the action, it becomes action itself, it turns red. In JavaScript, you can actually think of passing functions where they have actually very similar property. So let's check our previous code where all the functions were read. While it would be lovely to not deal with any actions at all, it would make our software quite useless. So the best we can do is to keep actions separate from calculations and ideally have them short and focused. So we can move this send payout call to main and we could also calculate payout separately before sending them. So I have introduced a separate function, collect payouts for that. It can look, for example, like this. Again, we are mutating the eligible array, but it's contained. Also, you could use, for example, a reduce function here, but personally I rather avoid it in most cases since I don't find it much readable, but your mileage may vary. You could do the rest of the code as exercise. I will upload slides after the talk. And I haven't really told you why we should care about this in the first place. And honestly, I feel sometimes forcing everything into pure functions is done for the sake of it at the cost of productivity. But personally, I believe this approach leads you to better code in the long run. Calculations are easy to test. They make unit testing productive since you test input and output. You don't need to run the whole application to check how they behave. Since calculations don't have any shared state, we can easily parallelize them, for example, put them on separate threads without risk increase conditions. And last but not least, it's easier to think about calculations. You don't need to worry about side effects and order of calls, just inputs and outputs. In the long run, this should help readability of your code tremendously. Sometimes when discussing the actions and calculations, I get a response like how does this fit into object-oriented programming or I don't use functions. And these concepts are perfectly well applicable with classes as well. I just find functions easier to reason about. And really it's a personal taste, but I'm not a big fan of writing stuff into classes. Say we have the logic with affiliates, I showed earlier packed into a class. Now I need also to also care when I initialize the object and keep its inner state. And coming up with names for functions is already hard. Now I need to name the class too. But in the end, I think the functional programming and object-oriented programming aren't opposites. It's a false dichotomy. And in fact, my next topic is heavily discussed in Java and C-sharp communities. So we split our code into actions and calculation. And that's a good basis for stratified design. While it sounds fancy, the main idea is to divide your code into layers. So the lowest layers define basic operations and are the most generic. As you go up, the code becomes higher level and specific towards your business domain. This can look for example like this. Know that the dependencies go strictly top to bottom and not sideways. The lower layer doesn't know anything about what's above it. And well, maybe this is obvious to you and I would be really happy if that were the case. Proper layering should help you avoid coming to this. Maybe you heard about spaghetti code and how awful it is. So I had a colleague who kind of embraced buggy code. So instead of testing, he wrote code with debuggability in mind. There were almost no abstractions. Functions were hundreds of lines of code, low-level code mixed with high-level abstractions. It was precisely one long spaghetti to follow along. He didn't find testing productive, but instead he was always busy debugging. There being said, no technique is bulletproof. If you don't plan or maintain your layers, well, it can end up like lasagna with too many complicated intertwined layers, but it will be probably less tasty. There are so-called architectural patterns which might help you design your layers. I picked a few names and some of them have multiple interpretations. For example, on an architecture, I will show you in a moment. There's also functional core imperative shell, which was popularized by Gary Behanert for Ruby and Python. In Java world, hexagonal architecture or ports and adapters is quite popular approach. And this one actually led to Uncle Bob's clean architecture. And I'm name-dropping them because in the end they are quite similar. They just propose different layers and different approaches for communication between these layers. Onion architecture somewhat is the most abstract of them. Ideally, this onion shouldn't make you cry. At the core of your application, there is language and libraries, low-level primitives. From those, you build your domain logic and the outer layer is for interaction with the outside world. Databases, APIs, user interfaces, and so on. Similar to stratified design, outer layers point to inner layers, never the other way around. And only the interaction layer can communicate with the outside world. This should help you easily test the domain logic and keep it stable compared to more volatile interaction layer. You can find something very similar with other patterns like clean architecture. It is just more hands-on with more precisely defined layers, their purpose and rules about their communication. And you maybe recognize this. So in model view controller, and it's many offsprings, your domain usually lives in models. And these models are also closely tied to database. Now, should we follow the ideas of onion architecture that the base would belong into the interaction layer? So, for example, we could split it like this, along with UI logic, roads. And while models and entities in this approach don't have any concept of persistence, usually we implement them just like plain objects. So how to put actually these ideas into action? Well, you rarely start with a green field project. If you have an existing code base, try asking yourself, how is your code structured in directories? Typically, you have these directories like utils, helper, slip, and other. And these names sometimes didn't fit elsewhere. So really, ask yourself and your colleagues what are there for, what they are hiding. Also, think about if you can identify layers of your application. It's usually useful to look at the dependencies, how functions and classes call each other. And of course, where are the actions? Are they spread in the system or located in particular layer? Speaking of actions, some very basic heuristics for spotting them is looking at input and output of the function. Even if the function returns a value, you would call calculation only because you are interested in its result. But if you are calling a function and you are not interested in its return value, maybe it's probably a side effect, really. Promises are also a strong indicator, but there are other uses for them without doing any side effects. When you implement a new feature, well, I can emphasize enough how important it is to communicate with your intents and ideas with your colleagues, especially now when most of us are working from home. So it's really, really important. But also consider if your feature can be implemented in a separate file or module and that one could be tested. Because from my experience, many times developers don't want to disrupt existing structures and existing modules, and they rather tend to put everything into existing code and existing files. So maybe it's not the best approach, try working outside of this. And speaking of tests, teams often sacrifice testing in favor of faster delivery, which hurts them in the long run. Or the tests are there, but no one uses them because they are slow or un-maintained. And personally, I think it's better to have smaller tests suite, which is actively used and ready for covering progressions than aimed at 100% test coverage from the start. And finally, I'd like to encourage you to keep things simple. Maybe you think you need to have dependency injection containers, microservices, or whatever, but there's no shame in keeping things simple. So I have a few resources to recommend. I mentioned that I cite Eric Normand, particularly his book, Croaking Simplicity, which covers these topics, actions, calculations, and also data in much more depth. I recommend it not just only for beginners, I think like even seniors can at least learn some language or communicating these ideas and these concepts. I have a few articles and resources which I am always coming back to. I have cited, for example, what color is your function. Also, my favorite regarding the object-oriented programming is execution in the kingdom of nouns. And there is also this website called the codeless code, which contains some really interesting points about programming and coding. I really recommend checking that out. And it's good to tend to your programming craftsmanship. And I believe like excellent event for that is Global Day of Code Retreat. They have even check chapter. It happens every November around the world. So check that out and consider organizing a coding dojo with your friends, with your colleagues. That's always a good thing to try. So now to you. We have a few minutes for discussion. There is something in QA, but here is how you can reach out to me, my website, my Twitter handle. And if you are curious about Superface and what we do, check out superface.ai. Okay, so time for discussion. Great. Thank you for your presentation. There is one question in Q&A. And what do you think about the BCE pattern? Well, I haven't heard that acronym to be honest. So I don't have any ideas, but I will check it out. Okay, thank you. I think there are no more questions. So still three minutes if you want to ask anything, please put it to the Q&A. So I don't see actually results of the whole video. I was curious about people attending here. I see we have a few beginners in the polls. And yeah, looks like the Python is the most popular here. I will do this. Okay. We have one more question. Do you know the relation of actions computation with Rust language? I know that Rust has some approaches for handling this, but to be honest, I'm not familiar with the Rust. So, but I will check it out. Yeah, I think like what specific to Rust that, but also like other languages is that you need to actually mark your mutations. So that's like really good start. If I remember correctly that you need to, for example, mark variable as mutable. So it's kind of the other way around compared to other languages where you actually need to declare stuff as constants or, for example, in JavaScript, you need to, for example, decrease your objects. So yeah, I would say Rust is great language for implementing these ideas. Thank you. Okay. So thank you for your attention. I will hop into the, what's this called? Worker venture. So if you would like to discuss it in person or like talk to me, I will be there. So I'm looking forward to meeting you and enjoy the rest of the deafcon today. Thanks. Bye. Thank you very much again for your presentation. So if you have any more questions, feel free to go to work in the chair. It's a really fun way how to interact with each other. It's a virtual platform, so hopefully to go there. And see you on the next talk.