Patrones de Programación Funcional

Sebastián Estrella

Acerca de mí

¿Qué es Programación Funcional?

¿Qué es Programación Declarativa?

Inmutabilidad

Inmutabilidad

  • Código predecible
  • Facilita la concurrencia
  • Reduce el riesgo de condiciones de carrera

Referencia Transparencial

  • Resultados determinísticos
  • Facilita el razonamiento del comportamiento de un programa

Composición

  • Dividir un problema en pequeñas partes
  • Hacer una cosa y hacerla bien (Linux)
  • Código facíl de probar
  • Mayor reusabilidad

¿Cuál es el problema con la Programación Orientada a Objetos?

Mutabilidad

  • Problemas de concurrencia
  • Díficil de debuggear
  • El número mágico siete, más o menos dos  (Miller)

Mutabilidad

Efectos secundarios

  • Operaciones de I/O
  • Modificación de variables
  • Cambios de estado en general
  • Pruebas fragiles

Mantenibilidad

  • Mayor nivel de indirección
  • Demasiado detalles de implementación (wholemeal)
0
 Advanced issues found
1

Hablar es fácil, muéstrame el código

- Linus Torvalds 

Partamos de un escenario real...

...los Vengadores nos necesitan!

public class User {
  ...
  public User(String firstName, String lastName, boolean admin, boolean enabled) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.admin = admin;
    this.enabled = enabled;
  }
  ...
}

List<User> users = Arrays.asList(
  // admins
  new User("Bruce", "Banner", true, true),
  new User("Clinton", "Barton", true, false),
  new User("Natasha", "Romanoff", true, true),
  new User("Steve", "Rogers", true, true),
  new User("Thor", "Odisen", true, true),
  new User("Tony", "Stark", true, true),
  // members
  new User("Peter", "Parker", false, false),
  new User("Stephen", "Strange", false, true)
);
Table table = new Table();

for (User user : users) {
  if (user.isEnabled()) {
    Row row = new Row();
    row.addColumn(new Column(user.getFirstName() + " " + user.getLastName()));
    String role = "";
    if (user.isAdmin()) {
      role = "ADMIN";
    } else {
      role = "MEMBER";
    }
    row.addColumn(new Column(role));
    table.addRow(row);
  }
}

table.render();
|         Bruce Banner |                ADMIN | 
|     Natasha Romanoff |                ADMIN | 
|         Steve Rogers |                ADMIN | 
|          Thor Odisen |                ADMIN | 
|           Tony Stark |                ADMIN | 
|      Stephen Strange |               MEMBER | 

Inmutabilidad

Table table = new Table();

for (User user : users) {
  if (user.isEnabled()) {
    Row row = new Row();
    row.addColumn(new Column(user.getFirstName() + " " + user.getLastName()));
    String role = user.isAdmin() ? "ADMIN" : "MEMBER";
    row.addColumn(new Column(role));
    table.addRow(row);
  }
}

table.render();

Principio de responsabilidad única

List<User> enabledUsers = new ArrayList<User>();
for (User user : users) {
  if (user.isEnabled()) {
    enabledUsers.add(user);
  }
}

List<Row> rows = new ArrayList<Row>();
for (User user : enabledUsers) {
  Row row = new Row();
  row.addColumn(new Column(user.getFirstName() + " " + user.getLastName()));
  String role = user.isAdmin() ? "ADMIN" : "MEMBER";
  row.addColumn(new Column(role));
  rows.add(row);
}

Table table = new Table();
table.addRows(rows);
table.render();
List<User> enabledUsers = new ArrayList<User>();
for (User user : users) {
  if (user.isEnabled()) {
    enabledUsers.add(user);
  }
}


List<Row> rows = new ArrayList<Row>();
for (User user : enabledUsers) {
  Row row = new Row();
  row.addColumn(new Column(user.getFirstName() + " " + user.getLastName()));
  String role = user.isAdmin() ? "ADMIN" : "MEMBER";
  row.addColumn(new Column(role));
  rows.add(row);
}
Table table = new Table();
table.addRows(rows);
table.render();

1) Seleccionar los usuarios habilitados

2) Crear una fila por cada usuario

3) Presentar el contenido de la tabla

Patrones Funcionales

List<User> enabledUsers = new ArrayList<User>();
for (User user : users) {
  if (user.isEnabled()) {
    enabledUsers.add(user);
  }
}

List<Row> rows = new ArrayList<Row>();
for (User user : enabledUsers) {
  Row row = new Row();
  row.addColumn(new Column(user.getFirstName() + " " + user.getLastName()));
  String role = user.isAdmin() ? "ADMIN" : "MEMBER";
  row.addColumn(new Column(role));
  rows.add(row);
}

Table table = new Table();
table.addRows(rows);
table.render();

Funciones de Orden Superior

List<User> enabledUsers = users.stream()
  .filter(user -> user.isEnabled())
  .collect(Collectors.toList());

List<Row> rows = new ArrayList<Row>();
for (User user : enabledUsers) {
  Row row = new Row();
  row.addColumn(new Column(user.getFirstName() + " " + user.getLastName()));
  String role = user.isAdmin() ? "ADMIN" : "MEMBER";
  row.addColumn(new Column(role));
  rows.add(row);
}

Table table = new Table();
table.addRows(rows);
table.render();
List<User> enabledUsers = users.stream()
  .filter(user -> user.isEnabled())
  .collect(Collectors.toList());

List<Row> rows = enabledUsers.stream()
  .map(user -> {
    Row row = new Row();
    row.addColumn(new Column(user.getFirstName() + " " + user.getLastName()));
    String role = user.isAdmin() ? "ADMIN" : "MEMBER";
    row.addColumn(new Column(role));
    return row;
  })
  .collect(Collectors.toList());

Table table = new Table();
table.addRows(rows);
table.render();

Composición

List<Row> rows = users.stream()
  .filter(user -> user.isEnabled())
  .map(user -> {
    Row row = new Row();
    row.addColumn(new Column(user.getFirstName() + " " + user.getLastName()));
    String role = user.isAdmin() ? "ADMIN" : "MEMBER";
    row.addColumn(new Column(role));
    return row;
  })
  .collect(Collectors.toList());

Table table = new Table();
table.addRows(rows);
table.render();

Un nuevo Vengador se ha unido al equipo

List<User> users = Arrays.asList(
  // admins
  new User("Bruce", "Banner", true, true),
  new User("Clinton", "Barton", true, false),
  new User("Natasha", "Romanoff", true, true),
  new User("Steve", "Rogers", true, true),
  new User("Thor", "Odisen", true, true),
  new User("Tony", "Stark", true, true),
  // members
  new User("Peter", "Parker", false, false),
  new User("Stephen", "Strange", false, true),
  new User(null, "Pointer", true, true)
);
Integer number = null;
String text = null;
Object object = null;

Dr. Null Pointer: Superpoderes

1) Camuflaje

2) Inmunidad al compilador

3) Paranoia

Integer a = null + 1;
Assert.notNull(x);
Assert.notNull(y);
return x + y;
|         Bruce Banner |                ADMIN | 
|     Natasha Romanoff |                ADMIN | 
|         Steve Rogers |                ADMIN | 
|          Thor Odisen |                ADMIN | 
|           Tony Stark |                ADMIN | 
|      Stephen Strange |               MEMBER | 
|         null Pointer |                ADMIN | 
List<Row> rows = users.stream()
  .filter(user -> user.isEnabled())
  .map(user -> {
    Row row = new Row();

    String fullName = Optional.ofNullable(user.getFirstName())
      .map(firstName -> {
        return Optional.ofNullable(user.getLastName())
          .map(lastName -> firstName + " " + lastName)
          .get();
      })
      .orElse("<unknown>");

    row.addColumn(new Column(fullName));
    String role = user.isAdmin() ? "ADMIN" : "MEMBER";
    row.addColumn(new Column(role));
    return row;
  })
  .collect(Collectors.toList());

Table table = new Table();
table.addRows(rows);
table.render();
|         Bruce Banner |                ADMIN | 
|     Natasha Romanoff |                ADMIN | 
|         Steve Rogers |                ADMIN | 
|          Thor Odisen |                ADMIN | 
|           Tony Stark |                ADMIN | 
|      Stephen Strange |               MEMBER | 
|            <unknown> |                ADMIN | 

References

Repositorio

Repositorio

Sebastián Estrella

Stack Builders

Gracias

Patrones de Programación Funcional

By Sebastián Estrella

Patrones de Programación Funcional

  • 78