Translate
domingo, 16 de julio de 2017
El patrón de arquitectura microkernel
Leyendo el libro, "Software Architecture Patterns" les dejo este pequeño resumen:
El patrón de arquitectura microkernel (a veces denominado patrón de arquitectura de plug-in) es un patrón natural para implementar aplicaciones basadas en productos. Una aplicación basada en producto es una que está empaquetada y está disponible para su descarga en versiones como un producto de terceros típico. Sin embargo, muchas compañías también desarrollan y liberan sus aplicaciones empresariales internas, como productos de software, con versiones, notas de lanzamiento y características conectables. Estos son también un ajuste natural para este patrón. El patrón de arquitectura de microkernel le permite agregar funciones de aplicación adicionales como complementos a la aplicación principal, proporcionando extensibilidad, así como separación y aislamiento de características.
Esta arquitectura esta compuesta por 2 componentes, el sistema core y los modulos plug-in. El core contiene la minima funcionalidad y los módulos plug-in son componentes autónomos e independientes que contienen procesamiento especializado, características adicionales y código personalizado que está diseñado para mejorar o ampliar el sistema central para producir capacidades empresariales adicionales. Generalmente, los módulos plug-in deben ser independientes de otros módulos plug-in, pero ciertamente puede diseñar plug-ins que requieran que otros plug-ins estén presentes. De cualquier manera, es importante mantener la comunicación entre plug-ins a un mínimo para evitar problemas de dependencia.
Cuando leemos esto lo primero que se nos viene a la mente es OSGi, porque este estándar nació para darle soporte a este tipo de arquitecturas y el ejemplo más significativo de esta arquitectura sea eclipse.
Dejo link: https://www.oreilly.com/ideas/software-architecture-patterns/page/4/microkernel-architecture
El patrón arquitectónico Event-Driver
Leyendo el libro, "Software Architecture Patterns" les dejo este pequeño resumen:
El patrón arquitectónico Event-Driver se utiliza para crear arquitecturas escalables, se puede utilizar en grandes aplicaciones como en pequeñas.
Este patrón arquitectónico tiene 2 topologías, el mediador y el broker (corredor, como es una fea traducción dejo su nombre en ingles).
La topología del mediador se utiliza comúnmente cuando se necesita orquestar múltiples pasos dentro de un evento a través de un mediador central, mientras que la topología de broker se utiliza cuando se desea encadenar sucesos sin el uso de un mediador central. Debido a que las características de la arquitectura y las estrategias de implementación difieren entre estas dos topologías, es importante entender cada una de ellas para saber cuál es la más adecuada para cada situación particular.
La topología del mediador es útil para eventos que tienen varios pasos y requieren algún nivel de orquestación para procesar el evento.
Hay cuatro tipos principales de componentes de arquitectura dentro de la topología del mediador: colas de eventos, un mediador de eventos, canales de eventos y procesadores de eventos. El flujo de eventos comienza con un cliente que envía un evento a una cola de eventos, que se utiliza para transportar el evento al mediador de eventos. El mediador de eventos recibe el evento inicial y orquesta dicho evento enviando eventos asíncronos adicionales a los canales de eventos para ejecutar cada paso del proceso. Los procesadores de eventos, que escuchan en los canales de eventos, reciben el evento del mediador de eventos y ejecutan lógica empresarial específica para procesar el evento.
La implementación más simple y más común del mediador de eventos es a través de frameworks open source como Spring Integration, Apache Camel o Mule ESB. Los flujos de eventos en estos frameworks se implementan típicamente a través de código Java o un DSL (lenguaje específico de dominio). Para una mediación y una orquestación más sofisticadas, puede utilizar BPEL (lenguaje de ejecución de procesos empresariales) junto con un motor BPEL open source como Apache ODE. BPEL es un lenguaje XML estándar que describe los datos y los pasos necesarios para procesar un evento inicial. Para aplicaciones muy grandes que requieren una orquestación mucho más sofisticada (incluyendo pasos que involucran interacciones humanas), puede implementar el mediador de eventos utilizando un gestor de procesos empresariales (BPM) como jBPM.
La topología broker se diferencia de mediador porque no hay un mediador central y único, sino que el flujo de eventos esta distribuido a través de los componentes del procesador de eventos de una manera similar a una cadena a través de un agente de mensajes ligero (por ejemplo, ActiveMQ, HornetQ, etc.). Esta topología es útil cuando se tiene un flujo de procesamiento de eventos relativamente simple y no desea (o necesita) orquestación de eventos centrales.
Hay dos tipos principales de componentes de arquitectura dentro de la topología de intermediario: un componente de broker y un componente de procesador de sucesos. El componente de broker puede centralizarse o federarse y contiene todos los canales de eventos que se utilizan en el flujo de eventos.
El patrón de arquitectura event-driver es un patrón relativamente complejo de implementar, principalmente debido a su naturaleza asincrónica distribuida. Al implementar este patrón, debe abordar varios problemas de arquitectura distribuida, como la disponibilidad de procesos remotos, la falta de capacidad de respuesta y la lógica de reconexión de intermediarios en caso de un fallo del intermediario o mediador.
Una consideración a tener en cuenta al elegir este patrón de arquitectura es la falta de transacciones atómicas para un solo proceso de negocio. Debido a que los componentes del procesador de eventos están altamente disociados y distribuidos, es muy difícil mantener una unidad transaccional de trabajo a través de ellos. Por esta razón, al diseñar su aplicación utilizando este patrón, debe pensar continuamente sobre qué eventos pueden y no pueden ejecutarse de forma independiente y planificar la granularidad de los procesadores de sucesos en consecuencia. Si descubre que necesita dividir una sola unidad de trabajo en los procesadores de eventos, es decir, si utiliza procesadores independientes para algo que debería ser una transacción indivisa, probablemente no sea el patrón adecuado para su aplicación.
Dejo link: http://radar.oreilly.com/2015/02/variations-in-event-driven-architecture.html
El patrón arquitectónico Event-Driver se utiliza para crear arquitecturas escalables, se puede utilizar en grandes aplicaciones como en pequeñas.
Este patrón arquitectónico tiene 2 topologías, el mediador y el broker (corredor, como es una fea traducción dejo su nombre en ingles).
La topología del mediador se utiliza comúnmente cuando se necesita orquestar múltiples pasos dentro de un evento a través de un mediador central, mientras que la topología de broker se utiliza cuando se desea encadenar sucesos sin el uso de un mediador central. Debido a que las características de la arquitectura y las estrategias de implementación difieren entre estas dos topologías, es importante entender cada una de ellas para saber cuál es la más adecuada para cada situación particular.
La topología del mediador es útil para eventos que tienen varios pasos y requieren algún nivel de orquestación para procesar el evento.
Hay cuatro tipos principales de componentes de arquitectura dentro de la topología del mediador: colas de eventos, un mediador de eventos, canales de eventos y procesadores de eventos. El flujo de eventos comienza con un cliente que envía un evento a una cola de eventos, que se utiliza para transportar el evento al mediador de eventos. El mediador de eventos recibe el evento inicial y orquesta dicho evento enviando eventos asíncronos adicionales a los canales de eventos para ejecutar cada paso del proceso. Los procesadores de eventos, que escuchan en los canales de eventos, reciben el evento del mediador de eventos y ejecutan lógica empresarial específica para procesar el evento.
La implementación más simple y más común del mediador de eventos es a través de frameworks open source como Spring Integration, Apache Camel o Mule ESB. Los flujos de eventos en estos frameworks se implementan típicamente a través de código Java o un DSL (lenguaje específico de dominio). Para una mediación y una orquestación más sofisticadas, puede utilizar BPEL (lenguaje de ejecución de procesos empresariales) junto con un motor BPEL open source como Apache ODE. BPEL es un lenguaje XML estándar que describe los datos y los pasos necesarios para procesar un evento inicial. Para aplicaciones muy grandes que requieren una orquestación mucho más sofisticada (incluyendo pasos que involucran interacciones humanas), puede implementar el mediador de eventos utilizando un gestor de procesos empresariales (BPM) como jBPM.
La topología broker se diferencia de mediador porque no hay un mediador central y único, sino que el flujo de eventos esta distribuido a través de los componentes del procesador de eventos de una manera similar a una cadena a través de un agente de mensajes ligero (por ejemplo, ActiveMQ, HornetQ, etc.). Esta topología es útil cuando se tiene un flujo de procesamiento de eventos relativamente simple y no desea (o necesita) orquestación de eventos centrales.
Hay dos tipos principales de componentes de arquitectura dentro de la topología de intermediario: un componente de broker y un componente de procesador de sucesos. El componente de broker puede centralizarse o federarse y contiene todos los canales de eventos que se utilizan en el flujo de eventos.
El patrón de arquitectura event-driver es un patrón relativamente complejo de implementar, principalmente debido a su naturaleza asincrónica distribuida. Al implementar este patrón, debe abordar varios problemas de arquitectura distribuida, como la disponibilidad de procesos remotos, la falta de capacidad de respuesta y la lógica de reconexión de intermediarios en caso de un fallo del intermediario o mediador.
Una consideración a tener en cuenta al elegir este patrón de arquitectura es la falta de transacciones atómicas para un solo proceso de negocio. Debido a que los componentes del procesador de eventos están altamente disociados y distribuidos, es muy difícil mantener una unidad transaccional de trabajo a través de ellos. Por esta razón, al diseñar su aplicación utilizando este patrón, debe pensar continuamente sobre qué eventos pueden y no pueden ejecutarse de forma independiente y planificar la granularidad de los procesadores de sucesos en consecuencia. Si descubre que necesita dividir una sola unidad de trabajo en los procesadores de eventos, es decir, si utiliza procesadores independientes para algo que debería ser una transacción indivisa, probablemente no sea el patrón adecuado para su aplicación.
Dejo link: http://radar.oreilly.com/2015/02/variations-in-event-driven-architecture.html
sábado, 15 de julio de 2017
Libros gratuitos sobre tecnología Microsoft
Microsoft nos regala muchísimos libros de tecnologías microsoft desde .net, powershell, azure hasta office y windows.
Sin más comentarios dejo link:
https://blogs.msdn.microsoft.com/mssmallbiz/2017/07/11/largest-free-microsoft-ebook-giveaway-im-giving-away-millions-of-free-microsoft-ebooks-again-including-windows-10-office-365-office-2016-power-bi-azure-windows-8-1-office-2013-sharepo/
jueves, 13 de julio de 2017
Concurrent Programming in Erlang
Luego de terminar el curso de Erlang en future learn, ahora me entero que hay un curso de concurrencia en erlang. Aunque comienza en agosto, vale la pena publicar, (y para no olvidarme) luego haré un post para recordarles.
Si bien estos cursos son gratuitos hay que pagar para recibir la certificación.
Entre información general podemos decir que el curso esta dictado en ingles (con subtitulos) por la universidad de Kent (creo que no tiene nada que ver con superman).
Y el contenido es el siguiente:
- Processes and messages in Erlang
- Message-passing concurrency
- Designing for robustness
- Handling errors and dealing with exceptions
- Testing and fixing concurrency
- Multicore and distributed Erlang
- OTP: The Open Telecom Platform
Dejo link:
https://www.futurelearn.com/courses/concurrent-programming-erlang/
miércoles, 12 de julio de 2017
Real World OCaml
Quiero compartir este libro online gratuito, es sobre OCaml un lenguaje que desconozco totalmente.
Dejo link:
https://realworldocaml.org/
Keras, la red neuronal neutral escrita en Python
Como lo dije anteriormente Keras el la red neuronal neutral escrita en Python y con la capacidad de correr cualquier TensorFlow, CNTK o Theano.
Esta librería fue desarrollada con el foco a permitir una experimentación rápida.
Utilice Keras si necesita una librería de aprendizaje que:
- Permite un prototipado fácil y rápido (a través de la facilidad de uso, modularidad y extensibilidad).
- Soporta redes convolucionales y redes recurrentes, así como combinaciones de los dos.
- Se ejecuta sin problemas en la CPU y la GPU.
La estructura de datos de Keras es un modelo, una forma de organizar capas. El modelo más simple es el modelo Sequential, una pila lineal de capas. Para arquitecturas más complejas, debe utilizar la API funcional de Keras, que permite crear gráficos arbitrarios de capas.
Veamos una secuencia:
from keras.models import Sequential
model = Sequential()
from keras.layers import Dense, Activation
model.add(Dense(units=64, input_dim=100))
model.add(Activation('relu'))
model.add(Dense(units=10))
model.add(Activation('softmax'))
Una vez que su modelo se vea bien, se configura el proceso de aprendizaje con .compile ():
model.compile(loss='categorical_crossentropy',
optimizer='sgd',
metrics=['accuracy'])
Si es necesario, puede configurar su optimizador. Un principio básico de Keras es hacer las cosas razonablemente simples, mientras que permite al usuario tener totalmente el control cuando lo necesitan (el control final es la fácil extensibilidad del código fuente).
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.SGD(lr=0.01, momentum=0.9, nesterov=True))
Ahora puede iterar en sus datos de entrenamiento:
# x_train and y_train are Numpy arrays --just like in the Scikit-Learn API.
model.fit(x_train, y_train, epochs=5, batch_size=32)
Alternativamente, puede alimentar lotes a su modelo manualmente:
Model.train_on_batch (x_batch, y_batch)
Evalúe su rendimiento en una sola línea:
Loss_and_metrics = model.evaluate (x_test, y_test, batch_size = 128)
O generar predicciones sobre nuevos datos:
Classes = model.predict (x_test, batch_size = 128)
Y listo!
Dejo link: https://keras.io/
Tuplas en C#
Desde .net core, estoy estudiando un poco más C#
Vamos desde el principio, que es una tupla? Una tupla es una estructura de datos que especifica una secuencia de elementos.
Una tupla puede retornar un numero de elementos de diferente tipo sin expecificar una nueva estructura. Esto puede ser util para retornar diferentes elementos de defirente tipo o aceptarlos como parámetros.
System.Tuples es el namespace donde se pueden encontrar las tuplas en C#
Veamos un ejemplo:
class TupleExample
{
static void Main()
{
// Create three-item tuple.
Tuple<int, string, bool> tuple =
new Tuple<int, string, bool>(10, "csharpstar", true);
// Access tuple properties.
if (tuple.Item1 == 10)
{
Console.WriteLine(tuple.Item1);
}
if (tuple.Item2 == "easywcf")
{
Console.WriteLine(tuple.Item2);
}
if (tuple.Item3)
{
Console.WriteLine(tuple.Item3);
}
}
}
Podemos no conoces el tipo de los elementos:
class TupleExample
{
static void Main()
{
// Use Tuple.Create static method.
var tuple = Tuple.Create("Csharpstar", 10, true);
// Test value of string.
string value = tuple.Item1;
if (value == "csharpstar")
{
Console.WriteLine(true);
}
// Test Item2 and Item3.
Console.WriteLine(tuple.Item2 == 10);
Console.WriteLine(!tuple.Item3);
// Write string representation.
Console.WriteLine(tuple);
}
}
Cuando utilizar tuplas?
Las tuplas se usan comúnmente de las siguientes maneras:
- Para representar un solo conjunto de datos. Por ejemplo, una tupla puede representar un registro de base de datos, y sus componentes pueden representar campos individuales del registro.
- Facilitar el acceso y la manipulación de un conjunto de datos.
- Para devolver varios valores de un método sin utilizar parámetros de salida
- Pasar valores múltiples a un método a través de un solo parámetro.
domingo, 9 de julio de 2017
GraphQL vs REST
Como sabrán me gustan las comparaciones, y estaba leyendo InfoQ y me encontre con un articulo sobre GraphQL vs REST.
Espero que todos conozcan REST, pero que es GraphQL? GraphQL es un lenguaje de consulta de datos, diseñado y usado en Facebook para solicitar y entregar datos a las aplicaciones móviles y web desde 2012. Para más info : https://emanuelpeg.blogspot.com.ar/2015/10/graphql.html
Cuales son sus ventajas ante rest y diferencias?
- GraphQL reduce el trafico red al permitirle recuperar todos los datos que necesita en una sola consulta.
- GraphQL es el modelo WYSIWYG, hacer que el código cliente sea menos propenso a errores.
- HTTP RESTful aprovecha más consistencia y previsibilidad haciendo uso de códigos de http (por ejemplo 404 si no encuentra la entidad) y de los metodos Post, Put, Delete, etc.
- Hypermedia de APIs Restful, permiten que los clientes vayan descubriendo la información y como encontrarla.
- HTTP ya implementa una caché, mientras que GraphQL no lo hace.
- GraphQL es útil porque proporciona un esquema para los consumidores, pero estas no necesariamente esta documentada.
Para concluir, no hay bala de plata, y es sólo una cuestión de elegir lo que tiene más sentido para los requerimientos.
Dejo link: https://www.infoq.com/news/2017/07/graphql-vs-rest
http://graphql.org/
https://apihandyman.io/and-graphql-for-all-a-few-things-to-think-about-before-blindly-dumping-rest-for-graphql/
miércoles, 5 de julio de 2017
Python Pedia
Si queres aprender python y más tecnologías Python Pedia es el sitio que estabas buscando. En este sitio podes encontrar todo sobre Python y muchas tecnologías más.
Entre las categorías encontramos desarrollo:
Entre las categorías encontramos desarrollo:
- Científico y numérico
- De Juegos
- Web
- Python core
- Testing
- Comunidad
- Interfaces
- Embebido
- Redes
- Acceso a base de datos
- Tutoriales
- etc...
Dejo link:
martes, 4 de julio de 2017
Un resumen de Scala for the Impatient, parte 24
Campos Abstractos
En Scala puede haber campos abstractos, y este campo abstracto es un campo sin valor inicial.
abstract class Person {
val id: Int //no esta inicializado, por lo que es abstracto igual que su getter y setter
var name: String //también abstracto
}
Esta clase si la vemos desde java no va tener estos atributos y los métodos getters y setters van a ser abstractos.
Dada la siguiente clase si queremos extenderla debemos definir estos atributos, por ejemplo:
class Employee(val id: Int) extends Person { // una subclase concreta
var name = "" // propiedad concreta
}
Como se puede ver no es necesario la palabra clave “override” para sobrescribir campos.
A la vez se puede utilizar esta clase abstracta por medio de la instanciación de una clase anónima, la cual debe establecer los valores :
val fred = new Person {
val id = 1729
var name = "Fred"
}
Construcción ordenada y definición temprana.
Cuando se desea sobrescribir un campo y se usa este campo en el constructor de la superclase, el resultado es un comportamiento poco intuitivo.
Veamos un ejemplo, supongamos que queremos modelar una criatura puede ver una dimensión y solo 10 unidades de medida:
class Creature {
val range: Int = 10
val env: Array[Int] = new Array[Int](range)
}
Pero una hormiga puede ver solo 2 :
class Ant extends Creature {
override val range = 2
}
Desafortunadamente ahora tenemos un problema, el rango es un valor que es utilizado en el constructor de la superclase y el constructor de la superclase se ejecuta antes del constructor de la subclase. Vamos que sucede en mayor detalle:
Como se puede ver env se inicializo como un vector de 0 y debía ser de 2.
Existen diferentes soluciones a este problema pero podemos nombrar 3:
En esta sección vamos a explorar la ultima opción. Para definir un campo con definición temprana lo podemos hacer de la siguiente manera:
class Bug extends {
override val range = 3
} with Creature
Note que with es una palabra reservada, que se encuentra antes de la superclase.
En Scala puede haber campos abstractos, y este campo abstracto es un campo sin valor inicial.
abstract class Person {
val id: Int //no esta inicializado, por lo que es abstracto igual que su getter y setter
var name: String //también abstracto
}
Esta clase si la vemos desde java no va tener estos atributos y los métodos getters y setters van a ser abstractos.
Dada la siguiente clase si queremos extenderla debemos definir estos atributos, por ejemplo:
class Employee(val id: Int) extends Person { // una subclase concreta
var name = "" // propiedad concreta
}
Como se puede ver no es necesario la palabra clave “override” para sobrescribir campos.
A la vez se puede utilizar esta clase abstracta por medio de la instanciación de una clase anónima, la cual debe establecer los valores :
val fred = new Person {
val id = 1729
var name = "Fred"
}
Construcción ordenada y definición temprana.
Cuando se desea sobrescribir un campo y se usa este campo en el constructor de la superclase, el resultado es un comportamiento poco intuitivo.
Veamos un ejemplo, supongamos que queremos modelar una criatura puede ver una dimensión y solo 10 unidades de medida:
class Creature {
val range: Int = 10
val env: Array[Int] = new Array[Int](range)
}
Pero una hormiga puede ver solo 2 :
class Ant extends Creature {
override val range = 2
}
Desafortunadamente ahora tenemos un problema, el rango es un valor que es utilizado en el constructor de la superclase y el constructor de la superclase se ejecuta antes del constructor de la subclase. Vamos que sucede en mayor detalle:
- Se llama al constructor de Ant
- El constructor de Ant llama al constructor de criatura
- El constructor de criatura inicializa range en 10 y luego inicializa env con el método getter de range que fue sobrescrito, este no utiliza el de criatura sino el de hormiga que aun no fue inicializado. Por lo tanto env es un vector de 0, porque 0 es el entero por defecto.
- Hormiga establece a range en 2.
Como se puede ver env se inicializo como un vector de 0 y debía ser de 2.
Existen diferentes soluciones a este problema pero podemos nombrar 3:
- Declarar val como final. Esto es seguro pero no flexible.
- Declarar val como lazy, esto es seguro, flexible pero un poco ineficiente.
- Declarar este campo como “early definition” o definición temprana en la subclase.
En esta sección vamos a explorar la ultima opción. Para definir un campo con definición temprana lo podemos hacer de la siguiente manera:
class Bug extends {
override val range = 3
} with Creature
Note que with es una palabra reservada, que se encuentra antes de la superclase.
domingo, 2 de julio de 2017
Libro Gratuito: Scala, The New web Architecture
Manning nos regala un libro que contiene varios capítulos de varios libros sobre Scala, Akka y Play.
Sin más dejo link: http://freecontent.manning.com/wp-content/uploads/scala-the-new-web-architecture.pdf
sábado, 1 de julio de 2017
Que cursos de codeschool puedo hacer de forma gratuita?
Empezó las vacaciones por lo tanto esta bueno si hacemos un cursito, y si es cortito, mejor. Estos cursos gratuitos vienen al pelo:
Try C#
Rangos en Kotlin
Todos hablan Kotlin, desde que es un lenguaje soportado por android se ha vuelto un famoso y con mucha publicidad. Y no vamos a ser la excepción.
En este caso vamos hablar de los rangos. Los rangos se define para cualquier tipo comparable, pero se usa principalmente para primitivos. Empecemos con algo simple un if, que nos permita saber si un numero se encuentra en un rango:
if ( i in 1 .. 10 ) { // equivalente a 1 <= i && i <= 10
println(i);
}
Veamos un for:
for (i in 1..4) print(i) // imprime "1234"
for (i in 4..1) print(i) // no imprime nada
//Usando downTo()
for (i in 4 downTo 1) print(i) // Ahora si imprime! "4321"
//Lo mismo pero con clausura:
(1..4).reversed().forEach(System.out::print)
//Si queremos saltarnos algunos valores:
for (i in 1..4 step 2) print(i) // imprime "13"
for (i in 4 downTo 1 step 2) print(i) // imprime "42"
for (i in 1 until 10) {
println(i)
}
Dejo link: http://developersjournal.in/pondering-over-kotlin-ranges/
jueves, 29 de junio de 2017
Novedades de Swift 4 con ejemplos
Encontré un articulo por demás interesante que nos muestra las novedades de swift con ejemplos.
Dejo link:
http://www.appcoda.com/swift4-changes/?utm_content=bufferbefa9&utm_medium=social&utm_source=plus.google.com&utm_campaign=buffer
Dejo link:
http://www.appcoda.com/swift4-changes/?utm_content=bufferbefa9&utm_medium=social&utm_source=plus.google.com&utm_campaign=buffer
miércoles, 28 de junio de 2017
Parámetro implícito en Scala
"Este es el primer paso para implementar la abstracción contextual en Scala". ¿Qué quiero decir con esto?
Abstracción: La capacidad de nombrar un concepto y usar sólo el nombre después.
Contextual: Un fragmento de un programa produce resultados o resultados en algún contexto. Nuestros lenguajes de programación son muy buenos para describir y abstraer lo que se producen. Pero casi no hay nada disponible para abstraer sobre las entradas que los programas obtienen de su contexto. Un ejemplo para resolver esto es la inyección de dependencias.
Los tipos de funciones implícitas son una forma sorprendentemente sencilla y general de hacer abstractables los patrones de codificación que resuelven estas tareas, reduciendo el código clásico y aumentando la aplicabilidad. Para entender esto debemos entender los parámetro implícito
En un lenguaje funcional, las entradas a un cálculo se expresan más naturalmente como parámetros. Uno podría simplemente aumentar las funciones para tomar parámetros adicionales que representan configuraciones, capacidades, diccionarios, o cualquier otro dato contextual que las funciones necesiten. El único inconveniente de esto es que a menudo hay una gran distancia en el gráfico de llamadas entre la definición de un elemento contextual y el sitio donde se utiliza. En consecuencia, se hace tedioso definir todos esos parámetros intermedios y pasarlos a lo largo de donde finalmente se consumen.
Los parámetros implícitos solucionan la mitad del problema. Ellos no tienen que ser propagados usando código de repetitivo; el compilador se encarga de eso. Esto los hace prácticos en muchos escenarios donde los parámetros simples serían demasiado engorrosos. Los parámetros implícitos también son muy útiles como un mecanismo general de paso del contexto.
Digamos que queremos escribir algún código que está diseñado para ejecutarse en una transacción. En aras de la ilustración, aquí hay una clase de transacción simple:
class Transaction {
private val log = new ListBuffer[String]
def println(s: String): Unit = log += s
private var aborted = false
private var committed = false
def abort(): Unit = { aborted = true }
def isAborted = aborted
def commit(): Unit =
if (!aborted && !committed) {
Console.println("******* log ********")
log.foreach(Console.println)
committed = true
}
}
La transacción encapsula un registro, al que se pueden imprimir mensajes. Puede estar en uno de los tres estados: run, commit o abort. Si la transacción se confirma, imprime el registro almacenado en la consola.
El método de transacción permite ejecutar un determinado código dentro de una transacción recién creada:
Abstracción: La capacidad de nombrar un concepto y usar sólo el nombre después.
Contextual: Un fragmento de un programa produce resultados o resultados en algún contexto. Nuestros lenguajes de programación son muy buenos para describir y abstraer lo que se producen. Pero casi no hay nada disponible para abstraer sobre las entradas que los programas obtienen de su contexto. Un ejemplo para resolver esto es la inyección de dependencias.
Los tipos de funciones implícitas son una forma sorprendentemente sencilla y general de hacer abstractables los patrones de codificación que resuelven estas tareas, reduciendo el código clásico y aumentando la aplicabilidad. Para entender esto debemos entender los parámetro implícito
En un lenguaje funcional, las entradas a un cálculo se expresan más naturalmente como parámetros. Uno podría simplemente aumentar las funciones para tomar parámetros adicionales que representan configuraciones, capacidades, diccionarios, o cualquier otro dato contextual que las funciones necesiten. El único inconveniente de esto es que a menudo hay una gran distancia en el gráfico de llamadas entre la definición de un elemento contextual y el sitio donde se utiliza. En consecuencia, se hace tedioso definir todos esos parámetros intermedios y pasarlos a lo largo de donde finalmente se consumen.
Los parámetros implícitos solucionan la mitad del problema. Ellos no tienen que ser propagados usando código de repetitivo; el compilador se encarga de eso. Esto los hace prácticos en muchos escenarios donde los parámetros simples serían demasiado engorrosos. Los parámetros implícitos también son muy útiles como un mecanismo general de paso del contexto.
Digamos que queremos escribir algún código que está diseñado para ejecutarse en una transacción. En aras de la ilustración, aquí hay una clase de transacción simple:
class Transaction {
private val log = new ListBuffer[String]
def println(s: String): Unit = log += s
private var aborted = false
private var committed = false
def abort(): Unit = { aborted = true }
def isAborted = aborted
def commit(): Unit =
if (!aborted && !committed) {
Console.println("******* log ********")
log.foreach(Console.println)
committed = true
}
}
La transacción encapsula un registro, al que se pueden imprimir mensajes. Puede estar en uno de los tres estados: run, commit o abort. Si la transacción se confirma, imprime el registro almacenado en la consola.
El método de transacción permite ejecutar un determinado código dentro de una transacción recién creada:
def transaction[T](op: Transaction => T) = {
val trans: Transaction = new Transaction
op(trans)
trans.commit()
}
La transacción actual se debe pasar a lo largo de una cadena de llamadas a todos los lugares que necesitan para acceder a ella. Para ilustrar esto, aquí están tres funciones f1, f2 y f3 que se llaman entre sí, y también acceder a la transacción actual. La manera más conveniente de lograr esto es pasar la transacción actual como un parámetro implícito.
def f1(x: Int)(implicit thisTransaction: Transaction): Int = {
thisTransaction.println(s"first step: $x")
f2(x + 1)
}
def f2(x: Int)(implicit thisTransaction: Transaction): Int = {
thisTransaction.println(s"second step: $x")
f3(x * x)
}
def f3(x: Int)(implicit thisTransaction: Transaction): Int = {
thisTransaction.println(s"third step: $x")
if (x % 2 != 0) thisTransaction.abort()
x
}
El programa principal llama a f1 en un nuevo contexto de transacción e imprime su resultado:
def main(args: Array[String]) = {
transaction {
implicit thisTransaction =>
val res = f1(args.length)
println(if (thisTransaction.isAborted) "aborted" else s"result: $res")
}
}
Suscribirse a:
Entradas (Atom)