SÓLIDO == OOP?

Supongo que no me equivocaré si digo que la mayoría de las personas preguntan sobre los principios SÓLIDOS durante las entrevistas. Las tecnologías, los lenguajes y los marcos son diferentes, pero los principios de codificación son generalmente similares: SOLID, KISS, DRY, YAGNI, GRASP y similares son dignos de conocer para todos.



En la industria moderna, el paradigma OOP ha dominado durante muchas décadas, y muchos desarrolladores tienen la impresión de que es el mejor o incluso el peor, el único. Hay un gran video sobre este tema ¿Por qué no es la programación funcional la norma? sobre el desarrollo de lenguajes / paradigmas y las raíces de su popularidad.



SOLID fue originalmente descrito por Robert Martin para OOP y muchos perciben que se refiere solo a OOP, incluso wikipedia nos cuenta al respecto, veamos si estos principios están tan vinculados a OOP.



Responsabilidad única



Disfrutemos la visión del tío Bob sobre SOLID :



Este principio fue descrito en el trabajo de Tom DeMarco y Meilir Page-Jones. Lo llamaron cohesión. Definieron la cohesión como la relación funcional de los elementos de un módulo. En este capítulo cambiaremos un poco ese significado y relacionaremos la cohesión con las fuerzas que hacen que cambie un módulo o una clase.

Cada módulo debe tener una razón para los cambios (y no hacer una sola cosa, ya que muchas respuestas) y como el autor mismo explicó en uno de los videos, esto significa que los cambios deben provenir de un grupo / rol de personas, por ejemplo, el módulo solo debe cambiar de acuerdo con Analista de negocios, diseñador, especialista en DBA, contador o abogado.



Tenga en cuenta que este principio se aplica a un módulo, que en OOP es una clase. Hay módulos en casi todos los idiomas, por lo que este principio no se limita a OOP.



Abrir cerrado



SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION, BUT CLOSED FOR MODIFICATION

Bertrand Meyer

- , — , ( ) .



( , ). , . map, filter, reduce, . , foldLeft !



def map(xs: Seq[Int], f: Int => Int) = 
  xs.foldLeft(Seq.empty) { (acc, x) => acc :+ f(x) }

def filter(xs: Seq[Int], f: Int => Boolean) = 
  xs.foldLeft(Seq.empty) { (acc, x) => if (f(x)) acc :+ x else acc }

def reduce(xs: Seq[Int], init: Int, f: (Int, Int) => Int) =
  xs.foldLeft(init) { (acc, x) => f(acc, x) }


, , — .



Liskov Substitution



:



If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.

, , "" . , , .



"", , "" . , ! , ( ), :



static <T> T increment(T number) {
  if (number instanceof Integer) return (T) (Object) (((Integer) number) + 1);
  if (number instanceof Double) return (T) (Object) (((Double) number) + 1);
  throw new IllegalArgumentException("Unexpected value "+ number);
}


, T, , "" (.. ), , — .



, , "" , , . , , ( ), , (ad hoc) . .



Interface Segregation



, , , .



, , "" ! , (type classes), .



Comparable Java type class Ord haskell ( classhaskell ):



// 
class Ord a where
    compare :: a -> a -> Ordering


"", , , compare ( Comparable). .



Dependency Inversion



Depend on abstractions, not on concretions.

Dependency Injection, — , :



int first(ArrayList<Integer> xs) // ArrayList    -> 
int first(Collection<Integer> xs) // Collection   -> 
<T> T first(Collection<T> xs) //         


: ( ):



def sum[F[_]: Monad](xs: Seq[F[Int]]): F[Int] =
  if (xs.isEmpty) 0.pure
  else for (head <- xs.head; tail <- all(xs.tail)) yield head + tail

sum[Id](Seq(1, 2, 3)) -> 6
sum[Future](Seq(queryService1(), queryService2())) -> Future(6)


, , .






SOLID , . , SOLID , . , !




All Articles