10
Oct

Functional Programming:Learning by Application to Redux and Canvas| Gyujin Cho |JSConf Korea(en sub)


Hello. This is my first time doing a full-scale presentation so I’m really nervous. As you can see, in this session, I’m going to make a presentation about functional JavaScript. It’s not that I know functional Javascript that well that I’m making a presentation. Some of the traits of functional programming that I’ve applied on real projects and my experience of grasping it little by little, is what I want to share. And that’s why I’m here. I’m a developer in a company called Lunit that analyses medical images. It’s been 3 years since I started being a developer. Before this, I worked in design. It was 2016 when I just started learning how to program, three years ago. There was a keyword that was very popular at the time. That is ‘React’. React is a library that helps to make interfaces. There would be some of you who haven’t used it but I’m sure everyone has heard of it before. It’s a library that people have been constantly giving love to. And three years ago, along with ‘React’, there was another keyword that arose. That is ‘Redux’ MobX is used a lot recently too, and it’s compared with React Hooks a lot too. At the time Redux was thought to be very innovative. So it was in the center of the stage. Redux is used with the library that makes UI and it’s a tool that maintains state in Javascript. As you can see on the right, it separates the state and the UI interface on the bottom and makes the state into action. That is the basic structure of Redux. With Redux, it is not as fast but there’s a keyword that slowly appeared. That is ‘functional programming’. Dan Abramov, who made Redux, got the idea from Elm, a functional language, and made it. So with Redux, the keyword ‘functional’ was gradually mentioned. At the time, I was a beginner in development. So it was too hard for me to get the grasp of what it meant. Although I didn’t understand all the basic concepts of Redux, using Redux by itself was very interesting and fun. When you make apps following the structure of Redux, eventually, the interests were all separated and the codes, including the components, became very neat. That’s why I liked Redux very much. Because of my interest for Redux, in the case of functional programming, I looked at it with vague curiosity and admiration. As time passed and I got used to the job, my curiosity for functional programming was revived and I started to study with my co-workers. In this study, the basic concepts of functions, to use a pure function, to prevent additional effects, to use preface grammars, I was able to understand these basic concepts. I also got to know about Monad and Reactive Programming. The most memorable thing that I remember from this study was actually the advantages of using functional programming. Since it connects simple pure functions, it’s less likely to have errors in a function, so it’s more stable. And it’s more likely to be reused since it connects small functions. And it’s easy to understand higher logic. These three were the advantages. It was very appealing at the time but after studying, other co-workers and I still didn’t catch the grasp on what exactly the functionals were. I think this was because when we wrote for a real project, this was the limitation of what we could apply from what we’ve learned while studying. Well, we could do more but when we copied, there was feedback that it didn’t seem like functional programming. So this was mostly what we wrote. So we… studied functional programming but it was still vague. Just understanding the concepts, a year passed. I went to a new company and started a new project. To show you simply, this is the app. One moment. Add a grid like this, and from that cell slide, which is the cancer cell or the fat cell, is all marked. It’s the tool that helps process data. Refactoring this tool was the task given to me. Because, before, only React and Canvas were applied and it wasn’t organized. Using Redux, I was given the task to refactor it. Like I wrote originally, I naturally used combineReducers and wrote the code. When using the combine reducer, it takes the state of the reducer and see it as each domain like DB and it separates the reducer completely. The connection between reducers can be made actions. So let’s say we are adding a label to a display like this I put together the key points here. When you write a reducer to add a label like that you need to use label type and other information from grid reducer. As the app gets more complex, more information is going to be added. When using combine reducer like this in order to process this you need to take information in the other reducer and pass it onto the factors and parameters. With more actions like these, there is going to be more cases of having to pass onto the parameters. Also, there was one other thing I was not happy with. You can use a middleware when using redux, and this middleware, takes care of ajax or processes events that cause additional effects, and loads other action or processes loading other actions right away. Let’s say we are writing reducer that exits the selected grid here, after writing the reducer exiting the grid it needs to be processed along with the other reducer although there is no api call in order to simply load other action the code for middleware must be written. And of course with more processes like these unnecessary middleware code is going to increase. So it’s going to look like this. So then we wondered if there is another way to write it. So we looked into redux documents and there was a post called Beyond combineReducers. It has been updated so it looks different from when I first saw it but the basic information is the same. Here, it talks about combine reducers, that it can only cover simple cases. And that there needs to be some kind of a customization? or reducer logic is needed. So I wanted to minimize having to pass factors into function and write each reducer code separately then in the redux middleware, I wanted to write the reducer and customize it so that it will only deal with additional effects. These are the purposes I started the works with. There was something else that helped with that If you scroll down to the previous document it introduces a library called reduce-reducers as another method. As you can see in the code here it is a reducer function composition library where you can execute different reducers in order and finally make it into one type of state. This is the official document on reduce-reducers I saw this format, and if I were to follow it exactly I would need to add a state so I wanted to make it into a format I liked by composing reducer like this and tried writing it. Actually I did not look into libraries composing reducers closely at the time. When you go through the documents in redux there are so many libraries. This is only part of the page and there is a library called reducer ramda. There are so many reducer composing libraries and I wanted to just simply start with something I knew about so I chose ramda. Ramda.js focuses on currying and composition and it is a functional library as I remembered from studying before, so I wanted to give it a try. Also, among these I used pipe which composes each function in order as the main method. Composing the functions is the main work but I didn’t use compose because compose basically does its work backwards, so I did not think it would be natural to read them. So I used pipe instead so using this composition I wrote the reducer exiting the grid earlier Here, select label and select type and select grid are separated like this. And there is reducer for each as well. This reducer combining and finally made a reducer called exitGrid. And each of the reducers could be mapped in the action. Seeing each reducer like this individually as a separate function and writing them like this. eventually rather than a switch a reducer used to map formation seemed to be better for writing. So that’s why I wrote it like this. The mapping formation actually is used more often these days. To show you more of how it’s processed in the store the reducer map called switch reducer makes a function that selects a reducer map for the action type. By using that, we finally make a root reducer. The code was simply written in that formation. However, when you look here, it’s going the same from root reducer to state action. According to the action type, the selected reducer does not need the action type’s information. So we additionally made a change to pass the payload. So according to this here, by not receiving the action but receiving the payload only, the code became more simple. The method I used in this process is to combine all the states in one and writing each of the many reducers. Then I thought of a chapter I saw while studying That is, ‘Few data structures, many operations’. That’s how it was translated in Korean. It was that quote. Thinking, ‘Would this be what that means?’, I got the grasp of it as I wrote the code. When you see the writing of the reducer exiting this grid, The exitGrid on the very bottom, you have to use it by putting only one factor of each function, so the select label the select labels or select label type, select grid, each reducer is all curried. Curry, as you see in the example code, if you surround a function with a curry, you can practice the factor to the function in order and you can apply it all at once. As you see here, As you see here, in the first item, the count and the list are in order. If you change that, the same code as you can see on the bottom, now needs a placeholder. When you use a function called curry, the first 10 when you select the first 10 items, if you receive the count first and get the list later, it’s natural to add in the factor 10 first. However, when the order is reversed, as to set it up first, you add in the placeholder. From this function composition I found out that the order of the factors matter. So here, functional programming connects the various functions and it’s written to pass down the data there. When you see the one I wrote, I made the state as one and by chaining the various reducers, I made it pass down like that. But, when you make this, the root reducer, since the original order of passed state and payload, That is why this code came out. In the exit grid on the bottom as I showed you earlier, you have to use the placeholder. So you reverse the places of state and payload like this and rewrite the reducer. And you can get a function with no placeholder. It’s more neat. By writing the code, I knew the reason that Ramda.js’s skills are currying and composing in detail. When you see the code I showed you earlier through explaining Ramda’s pipe, it filters the wrong factors, organizes it in order, cuts the first 10, adds each of them and divide it by 10 again. It connects all these functions and passes on the list. When we write the same one with the most famous library, lodash, When wrote with basic lodash, it becomes like this. You have to curry each of the functions individually. And the order is all different so you have to put in the placeholders in all of them. In lodash, the basic lists or or the main data is on the front. About this, the reason Ramda appears so clean is because the utils in Ramda are all automatically curried. And as I showed you earlier, The parameter’s order is best set to currying and composing. lodash too, considers this need considers this need and exclusively provides a library called lodash/fp. There, it passes the other factor first, almost like Ramda and passes the data later at the end. So if you look at the rewritten code that exits the grid, this is the original code and this is the rewritten code that we made using composition. If you look at it, the code is reduced by 3/4. And it works to fulfill one purpose. And the simple functions needed for exitGrid are separated into middleware and reducer and it is written so it comprehends the logic right away, without being stored. When you write a lot of code reducers like this, the code shrinks and I think it look more organized. So, after writing all the Redux parts, I am reminded of the quote, ‘Few data structures, many operations.’ These functions seem to carry that meaning and I started to like currying and composition to the point I adore them. I am very satisfied with their results So at the time, I had a part to refactor in the unorganized canvas, on the app I showed you earlier. It was an app that draws records. With this, thought(?), with this attitude, I kept on writing. And as a result, this ended up being the most exported upper function. It was written like this. As you can see, I got the Canvas context and passed it down like this. I wasn’t really satisfied with it. Because I had to bind the contexts by currying. If we look at another minor part here, when we see the part of adding new guides to the grid, we can see how it was written. Like I did previously, I did binding to the context. Then I took it to a lower level and in a more basic context, when you see the functions doing its job, I’ve bounded all the contexts here too. And to write a higher order function into a pipe. I got obsessed with it The information passed on to context got all mixed up and became a giant lump. It was okay when it was a state. All the irrelevant context process functions were using the same data, so it became a ridiculous data structure. So when I looked at the codes in detail, It was hard to figure out the logic, compared to other upper functions. At this time, someone who told me a lot of things about functional programming, the leader of the company I worked in before, told me to research about polymorphism. He also told me to work on how to practice polymorphism in functional programming So I started researching. Polymorphism is an idea more familiar as a class or in OOP, When there’s a class called drawing, the method is extended elsewhere and polymorphism is the ability to use the same method in a different use. I looked up how to practice this on functional programming and this idea came out. It’s called. ‘Discriminated Union’. I searched again and there was a typescript document. When you look at this typescript document, it separates the kinds and adds the res of the information needed. And when you scroll down, there’s this code. Through a switch, according to the kind of the information, different functions are practiced. This is a code that would be familiar to you all. This is the action type and structure of reducer that is used in Redux. Through this research, in the process of learning, I previously thought that Redux’s functional programming was constructed ambiguously. But I began to learn about how the ideas that it was borrowed from. I thought I should write the canvas this way And wrote it. But as I wrote it, I realised I made another misunderstanding. In this whole grid logic, If you look at the part where it draws only the new grid guide the function that makes the data and the function that operates the logic are stuck together. I saw this and thought it was strange. Because in functional programming, basically, data and functions are very loosely connected. As you can see, in object-oriented programming, Class firmly connects data and function. In functional programming, through chaining or pipe, the basic thought is that data and function are loosely connected. But for this upper logic, I saw something like this. When I first wrote it, it passed the drawing state data Then I thought of connecting the necessary canvas contexts to map out the actual operation But, looking at the detailed function and the lower function, the data and operation are stuck together. So, when I restructured it, it came out like this. I dropped the drawing state and the canvas context to the function. Here, to each sub function drawing state and canvas context, so the data and the method are stuck together and passed. That’s the structure I constructed. As you can see, the state, data and the operation are together and are wandering. So I thought I should separate them. I realized that I was coding just by using pipe to fit to the class. That came to my mind. So now, I changed the structure like this. I exclusively modified the data and using that data, I made the effects that would be passed at the end. Then, all of them together are applied to canvas context, and changed the overall data flow. That is what I’ve been working on. When you see this, the data structure was like this, each was separated by canvas effects like this. It’s almost like action, right? It’s now separated. And the basic drawing functions with too much curry are now neatly organized. What’s added is this effector map, which is added like a reducer map. Then, the grid guide on the drawing part, has a function that makes data. Then it receives the data that was made and the function that is practiced is typed. Here too, the function is changed into the function that processes the data first. The final function also has a bit of context bound. The context and the data weren’t so far apart In the new function, I made a function that only handles the data and finally applies it to the text. And the code is changed like this. I lifted the Redux and the Canvas part and distributed them. Surprisingly, after distributing, there were a lot of corrections to be made. Excluding a few components, all of the codes were modified. There were only three minor issues that occurred for three months. One thing that we could observe here is that, when we first learned about functional programming, one of the advantages was the reliability. The stability was something that was experienced. And after writing each function, it was highly reused. And by turning Redux into one state, selectors could reuse them in Redux so a lot of codes could be reduced. There was an uncertainty about whether it was easy to notice the final logic. Because, as I mentioned earlier, in the written codes, there is a function called converge or juxt function which use codes that only involve methods found in functional programming. So, a lot of effort is needed for other people to understand more and maintain it. So in that aspect, I gave this a triangle rank. To sum up, I explained a few data structures and many operations. such as currying and composition, and discriminated union. As I was familiarizing with these concepts, I learned something more important that as you can see when I wrote the wrong flow, In my opinion, the data flow of the whole structure is essential in functional programming This is the end of my presentation. Thank you for listening.

Tags: , ,

There are no comments yet

Why not be the first

Leave a Reply

Your email address will not be published. Required fields are marked *