Functional programming: a wacky toy that kills labor productivity. Part 1

You may already have heard of the so-called “functional” programming. Perhaps you are even thinking that you should try it somehow.



In no case do this!







Functional programming is full of flaws, it is not suitable for real projects. Its application will lead to a sharp drop in labor productivity. Why is this so? Let's find out.



▍ → Part 2



Functional programming cannot meet multifaceted corporate requirements









To create real enterprise-class software requires a complex set of rigid and binding requirements related to the expected number of abstractions embedded in the software solution. Object-oriented programming allows the developer to use many abstraction mechanisms that are able to fully satisfy the requirements of organizations for software systems.



I believe the above text does not look particularly clear. But very soon everything will fall into place.



The so-called “functional” programming does not have a normal mechanism for creating abstractions. The fact is that it is based on mathematical rules (these rules, which is quite understandable, do not find application in the real world, located outside the walls of educational institutions). Unlike OOP, functional programming makes no attempt to meet all the numerous, tough and complex software requirements that organizations make.



The following code snippet demonstrates the problems that are widespread where functional programming is used:



import { filter, first, get } from 'lodash/fp';

const filterByType = type =>
  filter( x => x.type === type );

const fruits = [
  { type: 'apple', price: 1.99 },
  { type: 'orange', price: 2.99 },
  { type: 'grape', price: 44.95 }  
];

const getFruitPrice = type => fruits =>
  fruits
  |> filterByType(type)
  |> first
  |> get('price');

const getApplePrice = getFruitPrice('apple');

console.log('apple price', getApplePrice(fruits));
      
      





, , !



, .



! - , , , . , , , .











, , , .



, . , , . , , :



class Fruit {
  constructor(type, price) {
    this.type = type;
    this.price = price;
  }
}

class AbstractFruitFactory {
  make(type, price) {
    return new Fruit(type, price);
  }
}

class AppleFactory extends AbstractFruitFactory {
  make(price) {
    return super.make("apple", price);
  }
}

class OrangeFactory extends AbstractFruitFactory {
  make(price) {
    return super.make("orange", price);
  }
}

class GrapeFactory extends AbstractFruitFactory {
  make(price) {
    return super.make("grape", price);
  }
}

class FruitRepository {
  constructor() {
    this.fruitList = [];
  }

  locate(strategy) {
    return strategy.locate(this.fruitList);
  }

  put(fruit) {
    this.fruitList.push(fruit);
  }
}

class FruitLocationStrategy {
  constructor(fruitType) {
    this.fruitType = fruitType;
  }

  locate(list) {
    return list.find(x => x.type === this.fruitType);
  }
}

class FruitPriceLocator {
  constructor(fruitRepository, locationStrategy) {
    this.fruitRepository = fruitRepository;
    this.locationStrategy = locationStrategy;
  }

  locatePrice() {
    return this.fruitRepository.locate(this.locationStrategy).price;
  }
}

const appleFactory = new AppleFactory();
const orangeFactory = new OrangeFactory();
const grapeFactory = new GrapeFactory();

const fruitRepository = new FruitRepository();
fruitRepository.put(appleFactory.make(1.99));
fruitRepository.put(orangeFactory.make(2.99));
fruitRepository.put(grapeFactory.make(44.95));

const appleLocationStrategy = new FruitLocationStrategy("apple");

const applePriceLocator = new FruitPriceLocator(
  fruitRepository,
  appleLocationStrategy
);

const applePrice = applePriceLocator.locatePrice();

console.log("apple", applePrice);
      
      





, . — .



. - , .



. , , .











, , . , -.



-, , .



, .



, «» . , . , , . , .



. :



//  :

// calculator.js:
const isValidInput = text => true;

const btnAddClick = (aText, bText) => {
  if (!isValidInput(aText) || !isValidInput(bText)) {
    return;
  }
}


//  :

// inputValidator.js:
export const isValidInput = text => true;

// calculator.js:
import { isValidInput } from './inputValidator';

const btnAddClick = (aText, bText, _isValidInput = isValidInput) => {
  if (!_isValidInput(aText) || !_isValidInput(bText)) {
    return;
  }
}
      
      





— , . , ? — ?



- :



//  :
public class CalculatorForm {
    private string aText, bText;
    
    private bool IsValidInput(string text) => true;
    
    private void btnAddClick(object sender, EventArgs e) {
        if ( !IsValidInput(bText) || !IsValidInput(aText) ) {
            return;
        }
    }
}


//  :
public class CalculatorForm {
    private string aText, bText;
    
    private readonly IInputValidator _inputValidator;
    
    public CalculatorForm(IInputValidator inputValidator) {
        _inputValidator = inputValidator;
    }
    
    private void btnAddClick(object sender, EventArgs e) {
        if ( !_inputValidator.IsValidInput(bText)
            || !_inputValidator.IsValidInput(aText) ) {
            return;
        }
    }
}

public interface IInputValidator {
    bool IsValidInput(string text);
}

public class InputValidator : IInputValidator {
    public bool IsValidInput(string text) => true;
}

public class InputValidatorFactory {
    public IInputValidator CreateInputValidator() => new InputValidator();
}
      
      





! , 22. . , , , .











«» - , . — .



- (, , ).



- :



class CountryUserSelectionStrategy {
  constructor(country) {
    this.country = country;
  }
  
  isMatch(user) {
    return user.country === this.country;
  }
}

class UserSelector {
  constructor(repository, userSelectionStrategy) {
    this.repository = repository;
    this.userSelectionStrategy = userSelectionStrategy;
  }
  
  selectUser() {    
    let user = null;

    for (const u in users) {
      if ( this.userSelectionStrategy.isMatch(u) ) {
        user = u;
        break;
      }
    }
    
    return user;
  }
}

const userRepository = new UserRepository();
const userInitializer = new UserInitializer();
userInitializer.initialize(userRepository);

const americanSelectionStrategy = new CountryUserSelectionStrategy('USA');
const americanUserSelector = new UserSelector(userRepository, americanSelectionStrategy);

const american = americanUserSelector.selectUser();

console.log('American', american);
      
      





for (const u in users)



. - , . , , .



, , , , , -. , , «» :



SELECT * FROM Users WHERE Country=’USA’;
      
      





, SQL-, - . SQL? - ? , . — , .











- — . «» . , , , .



. , . , , . . ( ) . , - , garfield.fishHead



— , . , , garfield.swim()



() garfield.layCaviar()



(). , ! , , . , , !



. , . — .











, , . , , . «». , - . , . — .eat(veggies)



, , .doHomework()



, . — . , , ? , !



, , . Manager



. , , , , , , « Netflix ».



, , ? , , .



- , , , Factory



. , , — MonaLisaFactory



, WallFactory



.



, — «» , . , .



, , , .











, , , . .



-, - , , . ( «») . 30 , . - .



— Domain-Driven Design, , . , Resharper, - — .



20-30 . , , 30 , . - . - , , . ?



? , . JavaScript. . , . ? .







! ?






All Articles