Posts Tagged ‘declaratividad’

Objetos

febrero 13, 2015
En su forma más general, un programa orientado a objetos es un conjunto de objetos pasándose mensajes para resolver un problema.

Si pensamos a la computadora como 4 objetos: un teclado, un mouse, un monitor y un gabinete, cada vez que apretamos una tecla del teclado o movemos del mouse, el teclado o el mouse le envían un mensaje al gabinete. El gabinete recibe el mensaje y lo procesa y a su vez le envía un mensaje al monitor, que puede ser según el caso dibuja un caracter o cambiá el ángulo de visión de un esapcio 3d.

El problema a resolver puede ser escribir este texto o mover el punto de vista de un personaje en un juego. Los controladores, la cpu y el monitor son los objetos. Las señales eléctricas entre los dispositivos son los mensajes.

¿Cómo hace para hacer todas esas tareas intermedias? No nos preocupa en un principio. Nosotros nos preocupamos por tipear, no cómo llegan los carcteres del teclado al monitor. O bien nos enfocamos en mover el mouse a la velocidad correcta que nos permita observar el paisaje 3d de manera satisfactoria, no los cálculos matemáticos para que ese mundo virtual sea verosímil. A esto de preocuparnos por el qué y no por el como, se lo suele llamar declaratividad. A medida que vayamos adquiriendo más experiencia en el desarrollo de soluciones, vamos a sentirnos tentados a pensar primero el “como” y mirar con desdén el que. Esto hace que nuestras soluciones se vuelvan difíciles de mantener y que de a poco vayamos perdiendo el encanto de lo simple. Por eso conviene siempre no perder de vista el “que” antes de poner el ojo en el “como”.

Los objetos no tienen que ser réplicas de la realidad, alcanza con que sean metáforas que nos permitan resolver un problema de la manera más simple posible y que fáciles de leer cuando alguien o uno mismo tenga que hacer algún ajuste en la solución o solucionar un problema nuevo con estos objetos.

Las metáforas que elijamos van a condicionar profundamente nuestra solución y nuestro estado de ánimo en el futuro.

Xtext codea por vos

noviembre 12, 2013

Buenas. El proyecto final de la carrera de Ing. en  Sistemas que estoy desarrollando es un entorno para enseñar programación orientada a objetos en el que puedo ver los objetos de manera gráfica y darles movimiento y un aspecto.

Es un prototipo todavía, pero con suerte y viento a favor en el mediano plazo va a estar completo,  y quién dice no lo podamos poner a prueba con estudiantes.

Está hecho con Xtext, un framework para desarrollar lenguajes e integrarlos fácilmente a eclipse.

Uno define una gramática, Xtext te genera los elementos para parsear y validar el lenguaje y a partir de ella se puede generar código en el lenguaje que prefiera e incluso construir un intérprete sobre la misma plataforma. HOOPE usa Xtensivamente este framework y otros chiches de la API de eclipse.

Xtext permite generar código java muy fácilmente e integrarlo con las APIs de uso común como JAX-WS o JPA.

En el laburo estoy desarrollando servicios web y tengo que admitir que no siempre es fácil la metodología wsdl-first. Sobre todo porque al que solicita los servicios web le cuesta adaptarse a los wsdl. Pero tampoco es cómodo programar de entrada y anotar con jax-ws. Hay mucho código – andamiaje y puede volverse Vogon Poetry.

Y Xtext andaba en mi cabeza…

Con una gramática muy sencilla:

grammar org.miguelius.ws.Generator with org.eclipse.xtext.xbase.Xbase

generate generator "https://lodemiguel.wordpress.com/ws/WsGenerator"

Service:
	('package' packageName=QualifiedName)?
	('targetNamespace' targetNamespace=STRING)?
	'webservice' name=ValidID '{' operations+=Operation+ '}';

Operation:
	name=ValidID '('
	(params+=FullJvmFormalParameter
	(',' params+=FullJvmFormalParameter)*)?
	')'
	'returns'
	'('
	(returned+=FullJvmFormalParameter
	(',' returned+=FullJvmFormalParameter)*)?
	')';

Como el lenguaje está basado en xbase / jvm, puedo usar un inferrer. El inferrer permite generar código con chequeo de tipos a partir del árbol sintáctico:

   	def dispatch void infer(Service element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
		val requests = new HashMap()
		val responses = new HashMap()
   		// Here you explain how your model is mapped to Java elements, by writing the actual translation code.

   				for (operation : element.operations) {

   						val req = operation.toClass(operation.name + 'Request')
   						acceptor.accept(req).initializeLater[
   							packageName=element.packageName
							for (param : operation.params) {
								members += toField(param.name, param.parameterType)
								val getter = toGetter(param.name, param.parameterType)

								val getterAnnotation=findAnnotation(typeof(javax.xml.bind.annotation.XmlElement),param)
								getterAnnotation.addStringValue("name", param.name)
								getter.annotations+=getterAnnotation

								members += getter
								members += toSetter(param.name, param.parameterType)
							}
   						]
   						requests.put(operation, req)

						req.annotations += findAnnotation(typeof(javax.xml.bind.annotation.XmlRootElement),operation)

   						val resp = operation.toClass(operation.name + 'Response')

						resp.annotations += findAnnotation(typeof(javax.xml.bind.annotation.XmlRootElement),operation)
   						acceptor.accept(resp).initializeLater[
   							packageName=element.packageName

							for (param : operation.returned) {
								members += toField(param.name, param.parameterType)
								val getter = toGetter(param.name, param.parameterType)

								val getterAnnotation=findAnnotation(typeof(javax.xml.bind.annotation.XmlElement),param)
								getterAnnotation.addStringValue("name", param.name)
								getter.annotations+=getterAnnotation

								members += getter
								members += toSetter(param.name, param.parameterType)
							}
   						]
   						responses.put(operation, resp)
				}
   		// An implementation for the initial hello world example could look like this:
   		val wsInterface = element.toInterface(element.name,[])
   		//wsInterface.annotations+=findAnnotation(typeof(javax.jws.WebService),element)
   		acceptor.accept(wsInterface)
   			.initializeLater([
   				packageName=element.packageName

   				val webService = findAnnotation(typeof(javax.jws.WebService),element)
   				webService.addStringValue("name", element.name + "Type")
   				annotations+=webService

   				val soapBinding = findAnnotation(typeof(javax.jws.soap.SOAPBinding),element)
   				soapBinding.addEnumValue("parameterStyle",
   					getTypeForName(javax.jws.soap.SOAPBinding.ParameterStyle, element),
   					'BARE'
   				)
   				annotations+=soapBinding
   				for (operation : element.operations) {

					val responseReference = responses.get(operation).fullName.getTypeForName(element)
					val requestReference = requests.get(operation).fullName.getTypeForName(element)

					val operMethod = operation.toMethod(operation.name, responseReference) [
						val parameter = toParameter(requests.get(operation).fullName.toFirstLower,requestReference)
						val webParam = findAnnotation(typeof(javax.jws.WebParam),operation)
							.addStringValue("name", requests.get(operation).fullName)
							.addStringValue("partName", requests.get(operation).fullName)
						parameter.annotations += webParam
						it.parameters+= parameter
					]
					operMethod.annotations+=findAnnotation(typeof(javax.jws.WebMethod),operation)

   					members += operMethod
   				}
   			])

   	}

Esto está en lenguaje xtend y no soy un especialista (dicho con más que pena que gloria). Admite sendos refactors, por ejemplo mejorar los dispatches del método infer. El pseudcódigo se muy sencillo:

  1. Generar una clase Request y Response por objeto con los parámetros de cada una con sus anotaciones JAXB
  2. Generar una interfaz para el Servicio y anotarla con JAX-WS
  3. Agregar las operaciones y anotarlas con JAX-WS

Esto me genera las clases java y la SEI. Heredo de la interfaz y tengo definido el servicio.

De esta manera, me puedo sentar con el cliente y definir un servicio de una manera comprensible para ambas partes y sin ahondar en detalles.

Supongamos que queremos hacer un servicio web para registrar posts que reciba un título y el contenido y me devuelva el ID del post y la URL.


webservice PostService {

RegistrarPost
(String Titulo, String Cuerpo)
returns
(Integer PostID, String URL)

BuscarPostPorID
(Integer PostID)
returns
(String Titulo, String Cuerpo)

}

Esto construye la interfaz PostService, con los métodos RegistrarPost y BuscarPostPorID. A su vez construye las clases RegistrarPostRequest y RegistrarPostResponse y otro par para BuscarPostPorID. Todo con sus anotaciones y listo para nuestra implementación de JAX-WS lo publique.

Con relativamente poco código tenemos un DSL para generar Web Services en java de manera declarativa y accesible a quién conoce el dominio.

Estoy trabajando en agregar tipos compuestos y listas.

Como sea ya tenemos la primer experiencia con Xtext en protoducción.

¡Hasta la próxima!

como llegar a ser el programador ideal

mayo 19, 2012

En la película Hero con Jet Li, en una escena se rebela del ideal al que puede llegar un espadachín. Cabe entender que en esa época se podía vivir de manejar una espada con cierta pericia. El avance de la tecnología llevó a que uno pueda vivir de escribir programas. Salvando grandes distancias, creo que se puede obtener cierto paralelismo entre lo que la peli dice de como se llega a ser un esapadachín ideal y de como se llega a ser un programador ideal.

Va acá una adaptación en inglés, porque me suena más lindo. Pero vale tanto en español como en inglés. El original es en chino mandarín.

Codemanship’s first achievement
is the unity of man and code
Once this unity is attained
even a shell script can solve any requirement
The second achievement is when
the code exists in one’s heart
when absent from one’s hand
One can deploy a full distributed system
even with bare hands
Codesmanship’s ultimate achievement
is the absence of the code
in both hand and heart
The codeman is at peace
with the rest of the world
He vows not to cludge
and to bring peace to mankind

Creo que el primer logro es cuando aprendés decentemente un lenguaje y conocés medianamente los recursos que te da el sistema operativo para hacer casi cualquier programa.

Obtuviste el segundo cuando lográs aprehender el concepto de declaratividad.

Finalmente, podés decir que llegaste al último logro cuando empezás a irte del laburo a la hora que acordaste el día que entraste.

ley de Kernighan

febrero 25, 2012

“Debuggear es el doble de difícil que escribir código. Por lo tanto, si escribo el código más ingenioso que puedo, no soy, por definición, lo suficientemente inteligente para debuggearlo”.

Así que a escribir código feliz y declarativo.