📜 ⬆️ ⬇️

Functional programming: there are too many ceremonies in Java and C #

Many have probably heard about functional programming, some have tried to write their own Hello World, and some have even started their own “functional” pet-project. But how many people used functional languages ​​in production? What are the advantages and disadvantages of php? Does the functional programming paradigm justify the expectations of developers? These and many other questions were answered by a person who discovered the advantages of a functional approach after 20 years of OOP development.



Vagif Abilov - developer at the Norwegian company Miles. He actively uses functional programming in real projects that place high demands on speed and scaling.

In the PLO, we force ourselves to work within narrow limits in advance.


- Vagif, did you come to functional programming after procedural and object-oriented? Or was it the first one that was functional? What was your starting point?
')
Vagif Abilov: When I started looking towards functional programming, I already had about 20 years of experience in object-oriented programming. In the 90s it was C ++, and then, with the advent of .NET, I programmed in C #. I am a typical backend developer. Worked with services and, mainly, with projects where scalability and speed was important.

We can single out one of the main reasons for which I began to look closely at something else. If you look at how to write with the help of OOP of this kind of system, then there is a big problem with the so-called shared state or state of public access. That is, if you have a multi-threaded system, then it should have access to shared data. Thus, it is necessary to manually manage flows, it is necessary to close the state of the public access from being accidentally broken. A significant part of human resources is spent just to program it correctly. Generally speaking, this is not part of the main domain, the main functional.

A certain concomitant factor is that it was formulated as the “ Amdal law ”, which establishes the dependence of the performance of a parallel system on the availability of resources for parallel processing. On a concrete example, it sounds like this: “if you have 10 processors, but you only parallelize 40%, then the speed increases 1.56 times”. Thus, for parallelization of systems in which a large focus is on restricting access to data from different streams, there are not many possibilities. At some point this ceased to suit me, and I began to look more at the possibility of solving this with such means that would allow me to get rid of the shared state. The advantage of many functional languages ​​is precisely the fact that by default all data does not mutate in them, they cannot be changed. This was the first reason why I began to look towards functional programming.

Somewhere six years ago I received an invitation to speak at a fairly large international conference NDC. By that time, I had already started working in hobby projects with OP and presented my F # experience there. It was a romantic period when the developers of C # came to the reports on functional programming, listened with pleasure, and then asked: “well, where does this apply in real systems? Is it possible to apply it at all? ” Often, the speakers themselves said that in real systems they do not use the FC, but they are going to. I was about the same condition, that is, I worked in all projects on C #, but for the pleasure I was introduced to F #.

My report was called: "Playing functional Conway's game of life", that is, the implementation of Conway's game "Life" using functional programming. Quite a famous game. I showed how to write it in F #, I did it and, starting to figure it out, I was surprised myself. I must say, before that, I found a project to implement this game on C # on CodeProject. This project consisted of five classes, five properties and methods, there were more than 300 lines of code, while effective. Even if you remove all the brackets, there are about 100 lines left. When I wrote Life on F #, I got 14 lines of executable code: seven functions on average two lines (if you think this is the limit, look at the code of English programmer Phil Trelfold, who fit the solution to Conway’s F # game with 140 characters and posted on twitter). The compactness of the development on F # shocked me. This is the first thing that impressed me. Then I started reviewing my code. I began to think, and where in general in this code says that the decision is made for a two-dimensional board ? I found that only one function, which calculates the neighbors of the cell, says that it is a 2D board. If this function is replaced with work with a three-dimensional or even multidimensional whiteboard, then everything will also work.

In many functional languages, in particular in F #, there is a so-called type inference : when you do not directly specify the type of your data, the compiler itself determines what to substitute, depending on how you use them. Because of this, you write immediately generalized code. If in Java or C # you need to specifically go to generalize your classes, then in F # this is obtained by default. This gives a very big advantage, which I could see personally when working on various projects.

When I finally prepared my report and spoke with him at conferences, I turned to the hall and asked where to start writing the game Conway. Practically everyone offered with the definition of classes and properties, for example: you must enter the class "Board", "Cell", define the properties "Cells". That is, everyone is accustomed to starting with the definition of types and their interrelations. We are so accustomed. But in fact, the introduction in advance of such a large number of definitions imposes a significant limitation on further work with them. The third important aspect in the implementation of the game "Life" on F # was that there I did not introduce any type. Everything was done by setting functions. This gives complete freedom to how to “play” with the original data. I realized that with the PLO, we “force” ourselves to work in advance within the framework of the definitions that we introduced.

I found a tweet suitable for describing this situation when I worked with the presentation of my report. Some English-speaking programmer wrote: “ programming in Java is the same as doing Russian literature: you need to define a hundred names before any events occur . This comment well defines the approach of the PLO. We should describe everything well from the beginning, and only then some events will start to occur, and we will be able to “string” some methods on our definitions. And, often, our design already limits us.

Returning to the original question, I must say that it was an attempt to get away from mutating data that became the starting point for me in the world of functional programming.

There are too many "ceremonies" in Java and C #


- In your opinion, should a person who has been engaged in object-oriented programming for a long time get acquainted / switch to functional?

Vagif Abilov: The question of complete transition is a rather pragmatic question. And to meet, yes, of course it is.

If we look at object-oriented languages ​​like Java or C #, then they have undergone quite large changes in recent years. If I do not confuse anything, in C # version 3.0, when LINQ appeared, lambda expressions appeared, it was already a noticeable move towards the introduction of functional programming elements.

There arises the following argument: “why should I study functional languages ​​themselves, if we can do a lot in C # with elements of functional languages?”. At least one of the answers to this goes into the field of data structure variability, since both C # and Java will always remain languages ​​with mutations. When the data that you define by default is available for change, then whatever elements of functional programming you make, the fundamental essence of these languages ​​will not change that. In recent versions of C #, you can “play” with elements of the FP, but, of course, it makes sense to try working with a real functional language, such as Erlang , Haskel, or F # . I would especially recommend the latter, since this language is very well embedded in .NET. It is enough to sort out some examples, to see how concise the code is. This, in my opinion, is a serious argument - compact code. The more experienced a programmer is, the more he should realize that there are too many “ceremonies” in languages ​​such as Java and C #. You can avoid them by halving the code, because usually F # programs are twice as compact as C #.

- What are the advantages of the OP in comparison with the PLO?

Vagif Abilov: The first, as I said, this lack of data mutation is very important. In programs that are written in a functional language, there are no variables. In a sense, they immediately turn out to be "tough."

If you look at the object-oriented code, there will be some variables, some data, then they are sent somewhere, and all of this is accessed from many threads. In functional languages, at first, this is a bit confusing: how can you generally work without introducing variables? But everything is implemented using the methods of "functional transformations". This is precisely the foundation of parallelism. When you receive any data, you do not need to answer the question: “is it thread-safe or not thread-safe? Will it survive access from many streams or not? ” You by definition know what will survive. You don’t even have to do any tests to check with access from multiple threads.

Due to the lack of variables and the fact that you are passing through functional transformations, tests are very simplified. As a result, logical errors are much more often caught by the compiler. One of the "good" problems when working with F # is this: I can spend several hours just to make the program compile, but when this happens, it will work without errors. It is so "lulling" that you start writing less tests. At first I tried to fight it and wrote as many tests as in C #. Then I realized that this was not necessary, since most logical errors are caught by the compiler, which is much less “forgiving” than object-oriented language compilers.

Perhaps this is the main advantage: parallelism, no mutations, more interaction with the compiler, which is susceptible to logical errors. In addition, the style of work is changing. If I work on C #, I often use classical TDD methodology. With F #, I work in the REPL mode (read-eval-print loop). Such work is very effective.

- Is there anything that is beyond the power of the OP in comparison with the PLO? What are his weaknesses?

Vagif Abilov: For each task, their means should be used. As for the advantages of functional languages ​​in the development of scalable systems with high speed, this is understandable, well known. But for me the advantages of functional programming when working with visual interfaces are not obvious. If your program is single-threaded and comes down to editing forms, then, in general, it will be natural to apply an object-oriented approach here, since forms are easier placed on the data model. F #, Clojure, Erlang are also used for developing a user interface, but the advantages seem to me unclear.

You can also say that, referring to functional languages, the developer can decide that the problems of parallelism and speed will be solved by themselves, but this does not replace the analysis of problems affecting speed. For example, a developer needs to think about it if he is working with multi-core processors. The program must be written so that it enjoys the benefits of the processor cache. Performance can be lost due to the fact that the cache will be constantly updated. This is, generally speaking, a task that has nothing to do with either functional programming or object-oriented. In any case, when developing fast scalable projects, it is necessary to understand the internal architecture of the systems on which they will work. In other words, this is not a “silver bullet”; one cannot expect that turning to a functional language will immediately solve all these problems.

- If you summarize, what tasks does the FI address?

Vagif Abilov: On solving problems that require parallelism, high speed. In general, the entire back-end can be successfully written in functional languages.

- Vagif, what infrastructure (tooling) needs to be assembled for the implementation of the project in the FP language?

Vagif Abilov: Since I work with C # and F #, for me Visual Studio is the most frequently used tool. But, more and more often I notice that I use other, less “heavy” means. For example, as for the F # language, if we are talking about .NET-development, that is, Visual Studio Code with the Ionide plugin. This is a terrific environment for working with F #.

I would recommend using editors such as Atom + Ionide, VS Code + Ionide, Paket, Fake. For tests, there are F # friendly frameworks: FsUnit and the Expecto library, which is very well built into working with functional languages. And just the other day there was information that the new IDE JetBrains Rider, which is still in beta, will support F #. This is a remarkable event, because JetBrains are generally practical guys, and they have long discarded when they were asked about supporting F #, citing the complexity of embedding language principles in the Resharper platform (as I understand it, difficulties relate to type injection, which is not in object-oriented languages ). But the ice has broken, F # has become too important in the .NET environment so that it can be further ignored.

If you need to write a web application, then there is a wonderful Suave framework. It allows a very compact, literally in a few lines, to write a web application or web service. If we talk about the implementation of microservices, then very well functional languages ​​work together with the model of actors (Actor-model). I have been developing the F # system for the last one and a half years using Akka.Net, in which this model is implemented.

Among other things, the important components will be the providers of types (type providers), which are implemented in F # and allow you to work very effectively with databases. They replace heavyweight libraries like the Entity Framework.

By the way, an interesting example. There is a SQLProvider library in F # open-source, which is unusual in that it includes seven drivers in one module: MSSQL, Oracle, SQLite, PostgreSQL, MySQL, MsAccess, ODBC. And all this weighs only 1.3 megabytes. And the driver for each of the databases is approximately 600 to 800 lines of code. This, by the way, is about how compactly you can write many things on F #.

- Are there big and serious projects on your personal account implemented with the help of functional programming?

Vagif Abilov: Yes. In a small group over the past year and a half, using F # using Akka.Net, we are writing a system that has high demands for speed and scalability. This system is being developed for the Norwegian state radio television. It handles many hundreds of terabytes of files, working with the cloud. The code is very compact, despite the complexity of the system.

- Do you think that the FP will become popular enough to compete with the PLO?

Vagif Abilov: As for competition, functional programming already now successfully competes with object-oriented and in many projects replaces it. If we talk about quantitative comparison, we must understand what time perspective we are talking about. Probably, in the next five years, the FP will not reach a comparable number of projects with the PLO for various reasons. One of them is that it is much easier to start learning programming from object-oriented languages. Plus, there are a large number of tasks with a user interface, where, as I said, the benefits of the OP are not obvious.

It seems to me that large scalable systems will increasingly be written in functional languages. One of the reasons for this is that Moore's law does not work. If earlier it was possible just to wait until more powerful processors come out, and everything in itself will become faster, but now this cannot be done. It is necessary to redo the architecture under the existing speed, knowing and bearing in mind that it will not increase. This is a very big trump card in favor of functional programming.

- What can you advise those who decided to start learning functional programming?

Vagif Abilov: I would advise you not to treat this choice as a serious life step. I noticed that trying to change the main language of programmers is considered to be some kind of radical step, unlike, for example, changing a database or some kind of framework. For example, javascript developers change the libraries they use as gloves. And it does not look like some serious change. If you have switched from a relational database to a document base, this is in many ways a more serious step than switching from one .NET language to another.

I happened to talk once with the guys who wrote the system for one of the customers on F #. I asked how easy it was to convince the customer that you would be doing a F # project. They said that the customer did not talk about it. The contract stated that the system should work under .NET. In this approach, in fact, there is something. If you are writing for this operating environment, then my advice is to try as much as possible and more. Try other languages, libraries and programming models. From all this will only benefit.

- What will be your report at the St. Petersburg DotNext conference in May?

Vagif Abilov: My current report will not be directly related to functional programming, but it will, in a sense, be associated with a change of paradigms. I will talk about how a developer can make an API in such a way that it is equally easy to use by both those who prefer typed programming and those who use dynamic type programming. As you know, with the advent of .NET 4.0, the opportunity to embed dynamic types in C # (type dynamic) has appeared. In a sense, I will talk about the need to be prepared for a paradigm shift. And this brings together my report with the topic of our conversation today.

The whole topic of the report of Vagif Abilov, who will speak at our DotNext conference in St. Petersburg on May 20th, sounds like a Typed or dynamic API? Both! We will be glad to see you at this event, where we managed to collect about 30 great speakers from different parts of the world and on the most relevant topics.

Source: https://habr.com/ru/post/328042/


All Articles