Desarrollando con WebSharper + Akka.NET (2 de ¿?): A ver si te pones a currar

¡Buenas, muchachotes! Continuamos nuestro viaje… bueno, mi viaje, qué coño, ¡el que pica soy yo! En este nuevo mega post, os presentaré uno de los dos participantes en este experimento loco: WebSharper.

Como os comenté, WebSharper es un framework de desarrollo de aplicaciones web funcional y reactivo. Se desarrolla en F# pero, en su siguiente versión (v4) que saldrá cuando les rote (dentro de ná), se podrá desarrollar también en C#. Pero C# => Caca, F# -> Fun.

Creando el proyecto

Para poder trabajar con este framework en Visual Studio, se requiere de un proyecto web preparado para F# generado mediante unas plantillas de Visual Studio que os podéis descargar desde la web oficial mediante un instalable de extensión. Tiene instalables para otros IDEs. No es la única forma de generar estos proyectos, también podéis usar Yeoman, pero es la más práctica para los que usamos Visual Studio. Actualmente, WebSharper sólo funciona para .NET tradicional. Ya se verá en un futuro cuando .NET Core madure (en plan su versión 3 o 4).

Una vez instalada la extensión, en Visual Studio, al crear un nuevo proyecto y seleccionar la pestaña de Visual F#, veréis un nuevo grupo llamado WebSharper, donde encontraréis un churro de plantillas de proyectos diferentes. El que yo utilizaré es el básico de aplicación de cliente-servidor, para poder sacarle jugo a Akka.NET. Le pondré de nombre Michakun.NihonGoWeb.WebSharper, que es muy fácil de memorizar. Yo le llamo MNGWWS. ¡Ay, mi Emengiwwués!

A continuación os pongo una foto de como queda la estructura de ficheros tras crear el proyecto:

proyecto-websharper

El proyecto que te genera tiene una pequña demostración de cómo funciona WebSharper y su interacción cliente-servidor. Si lo ejecutáis, esto es lo que veréis:

ejecucion-demo-websharper
Escribís en la caja de texto, enviais, y os devuelve el texto invertido.

Un fichero importante del proyecto es Setup.fsx. Tras crear el proyecto es necesario, si no lo has hecho anteriormente, ejecutar el script del fichero para agregar llaves de registro en el sistema para que Visual Studio tenga un soporte correcto de proyectos web en F#. Su ejecución es muy fácil: Abrís el fichero, seleccionáis todo el script y, desde el menú desplegable de ratón derecho, seleccionáis “Ejecutar en Interactivo“. Una vez ejecutado, podéis borrar el fichero y no tendréis que subirlo al repositorio. A continuación, sus dejo el script:

open Microsoft.Win32

type RegistryKeyName =
	| HKCU of string
	| HKLM of string

type RegistryKey with

static member Find(name) =
	let (r, s) =
		match name with
		| HKCU s -> (Registry.CurrentUser, s)
		| HKLM s -> (Registry.LocalMachine, s)
	(r, s.Split([| '\\' |]))
	||> Seq.fold (fun s t -> s.OpenSubKey(t))

let Guid = "{F2A71F9B-5D33-465A-A702-920D77279786}"

let AddRegistryKeys (product, key) =
	try
		RegistryKey.Find(key)
			.OpenSubKey("LanguageTemplates", true)
			.SetValue(Guid, Guid, RegistryValueKind.String)
		printfn "Added to %s" product
	with _ ->
		printfn "Failed to detect: %s" product

let InstallFSharpWebCapability () =
	[
		"VWD Express 11", HKCU @"Software\Microsoft\VWDExpress\11.0_Config\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VWD Express 12", HKCU @"Software\Microsoft\VWDExpress\12.0_Config\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VWD Express 14", HKCU @"Software\Microsoft\VWDExpress\14.0_Config\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VS 11", HKCU @"Software\Microsoft\VisualStudio\11.0_Config\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VS WinDesktop Express 12", HKCU @"Software\Microsoft\VSWinDesktopExpress\12.0_Config\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VS 12", HKCU @"Software\Microsoft\VisualStudio\12.0_Config\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VS WinDesktop Express 14", HKCU @"Software\Microsoft\VSWinDesktopExpress\14.0_Config\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VS 14", HKCU @"Software\Microsoft\VisualStudio\14.0_Config\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VWD Express 11 (x64)", HKLM @"SOFTWARE\Wow6432Node\Microsoft\VWDExpress\11.0\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VWD Express 12 (x64)", HKLM @"SOFTWARE\Wow6432Node\Microsoft\VWDExpress\12.0\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VWD Express 14 (x64)", HKLM @"SOFTWARE\Wow6432Node\Microsoft\VWDExpress\14.0\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VS 11 (x64)", HKLM @"SOFTWARE\Wow6432Node\Microsoft\VisualStudio\11.0\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VS WinDesktop Express 12 (x64)", HKLM @"SOFTWARE\Wow6432Node\Microsoft\VSWinDesktopExpress\12.0\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VS 12 (x64)", HKLM @"SOFTWARE\Wow6432Node\Microsoft\VisualStudio\12.0\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VS WinDesktop Express 14 (x64)", HKLM @"SOFTWARE\Wow6432Node\Microsoft\VSWinDesktopExpress\14.0\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
		"VS 14 (x64)", HKLM @"SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0\Projects\{349C5851-65DF-11DA-9384-00065B846F21}"
	]
	|> List.iter AddRegistryKeys

InstallFSharpWebCapability ()

Como detalle importante, este proyecto es como un proyecto web ASP.NET normal sin OWIN, vamos, clasicazo de toda la vida pal IIS. En el fondo, es un framework más de ASP.NET, ya que convive con su Global.asax, Web.configs y demás, como se puede ver a continuación:

namespace Michakun.NihonGoWeb.WebSharper

type Global() =
inherit System.Web.HttpApplication()

member g.Application_Start(sender: obj, args: System.EventArgs) =
()
<configuration>
	<!-- NOTE: comment the following to run on F# 3.0 -->
	<runtime>
		<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
			<dependentAssembly>
				<assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
				<bindingRedirect oldVersion="0.0.0.0-4.4.0.0" newVersion="4.4.0.0"/>
			</dependentAssembly>
		</assemblyBinding>
	</runtime>
	<!--
		For a description of web.config changes see 		http://go.microsoft.com/fwlink/?LinkId=235367.

		The following attributes can be set on the <httpRuntime> tag.
		<system.Web>
			<httpRuntime targetFramework="4.6.2" />
		</system.Web>
	-->
	<system.web>
	<!-- NOTE: remove debug="true" to serve compressed JavaScript -->
		<compilation debug="true" targetFramework="4.6.2"/>
		<!-- This is only needed for VS Development WebServer. IIS/IIS Express do not use this:-->
		<httpModules>
			<add name="WebSharper.RemotingModule" type="WebSharper.Web.RpcModule, WebSharper.Web"/>
			<add name="WebSharper.Sitelets" type="WebSharper.Sitelets.HttpModule, WebSharper.Sitelets"/>
		</httpModules>
		<pages controlRenderingCompatibilityVersion="4.0"/></system.web>
	<system.webServer>
		<modules>
			<add name="WebSharper.RemotingModule" type="WebSharper.Web.RpcModule, WebSharper.Web"/>
			<add name="WebSharper.Sitelets" type="WebSharper.Sitelets.HttpModule, WebSharper.Sitelets"/>
		</modules>
		<!-- This is only needed for VS Development WebServer (see above). IIS/IIS Express do not use this: -->
		<validation validateIntegratedModeConfiguration="false"/>
	</system.webServer>
</configuration>

Como podemos comprobar en el fichero de Web.config, posee dos módulus web (WebSharper.Web.RpcModule y WebSharper.Sitelets.HttpModule) que se integran en el pipeline ASP.NET de toda la vida. Son el motor de WebSharper en entornos ASP.NET.

Bueno pero, ¿dónde está mi web?

El punto de arranque de esta aplicación, aparte del Global.asax, lo encontramos en el fichero Main.fs:

[<Website>]
let Main = Application.MultiPage (fun ctx endpoint ->
		match endpoint with
		| EndPoint.Home -> HomePage ctx
		| EndPoint.About -> AboutPage ctx
	)

Intentemos explicar este snippet. Con WebSharper, la función Application.MultiPage crea un Sitelet. Los Sitelets son la primera opción en WebSharper de crear contenido web desde el servidor. El Sitelet creado debe ser marcado con el atributo Website para que WebSharper lo detecte como punto de entrada. En nuestro caso, el Sitelet que se crea espera una función en la que, a partir de un contexto generado por WebSharper a cada petición de usuario (relativo a HttpContext en el mundo ASP.NET), y un EndPoint, con el que se define el Routing de servidor de nuestra aplicación web, devuelva, de forma asíncrona, el contenido que debe “renderizar” al cliente, ya sea HTML, JSON, recurso binario o, simplemente, texto plano. WebSharper es capaz de analizar las peticiones al servidor y, a partir de los datos de la petición, generar su contexto y asignar el valor del EndPoint asociado a la petición.

El EndPoint es un tipo de unión discriminada. Se representa a continuación:

type EndPoint =
| [<EndPoint "/">] Home
| [<EndPoint "/about">] About

Como vemos, el tipo define dos rutas posibles: Una ruta para la pantalla principal de la web (Home) y otra ruta para la página de “Acerca de” (About). Para marcar qué url relativas tendrá cada ruta se marca cada definición de caso con el atributo EndPoint. Este atributo espera un parámetro con el que marcamos qué url relativa se le asigna a cada ruta.

Entonces, si volvemos de nuevo a nuestro Sitelet, vemos que dentro de la función que se le pasa a nuestra función creadora de Sitelet se realiza pattern matching con el valor del EndPoint asociado a la petición del usuario con el que se generará el contenido a devolver de la página principal o de la otra página.

[<Website&t;]
let Main = Application.MultiPage (fun ctx endpoint ->
		match endpoint with
		| EndPoint.Home -> HomePage ctx
		| EndPoint.About -> AboutPage ctx
	)

Veamos cómo se genera nuestro contenido. Empezamos por el más simple, que es nuestra página de About. El método que llama nuestro Sitelet es AboutPage. Esta función espera como parámetro el contexto de WebSharper y nos devuelve nuestro querido contenido de forma asíncrona. Mostramos su contenido a continuación:

let AboutPage ctx =
	Templating.Main ctx EndPoint.About "About" [
		H1 [Text "About"]
		P [Text "This is a template WebSharper client-server application."]
	]

Vemos una nueva función: Templating.Main. Esta función es casera, creada en un módulo más arriba en nuestro fichero de marras (module Templating). Investiguemos esta función.

let Main ctx endpoint title body : Async<Content> =
	Content.WithTemplate MainTemplate
		{
			Title = title
			MenuBar = MenuBar ctx endpoint
			Body = body
		}

Volvemos a nuestras funciones de WebSharper. En este caso, nos encontramos con la función Content.WithTemplate. Esta función se encarga de generar nuestro contenido asíncrono a partir de una plantilla. En otros mundos, la plantilla es nuestra vista. Y como en cualquier vista, se requiere un modelo que pasar a la plantilla para rellenar los huecos que ésta defina. Este modelo también es requerido por la función Content.WithTemplate. La plantilla es del tipo Content.Template<Page>,definido en WebSharper. Page es el tipo del modelo que espera nuestra plantilla y éste sí que está definido en nuestra página, como se muestra a continuación (misma página, al principio del módulo Templating):

type Page =
	{
		Title : string
		MenuBar : list
		Body : list
	}

A continuación vemos como construimos la plantilla. En nuestro caso, la plantilla es un valor bindado al nombre MainTemplate, cuya definición mostramos a continuación:

let MainTemplate =
	Content.Template("~/Main.html")
		.With("title", fun x -gt; x.Title)
		.With("menubar", fun x -gt; x.MenuBar)
		.With("body", fun x -gt; x.Body)

Vemos como se llama al contructor del tipo Content.Template<Page>, que requiere como argumento el path del fichero HTML de donde extraer la plantilla. En nuestro caso, dicho fichero es Main.html, alojado en el mismo proyecto de WebSharper. Este es su contenido:

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>${title}</title>
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" />
		<style>
			/* Sticky footer styles */
			html {
				position: relative;
				min-height: 100%;
			}

			body {
				/* Margin bottom by footer height */
				margin-bottom: 60px;
			}

			.footer {
				position: absolute;
				bottom: 0;
				width: 100%;
				/* Set the fixed height of the footer here */
				height: 60px;
				background-color: #f5f5f5;
			}

			.container .text-muted {
				margin: 20px 0;
			}
		</style>
	</head>
	<body>
		<!-- Static navbar -->
			<nav class="navbar navbar-default navbar-static-top">
				<div class="container">
					<div class="navbar-header">
						<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
							<span class="sr-only">Toggle navigation</span>
							<span class="icon-bar"></span>
							<span class="icon-bar"></span>
						</button>
						<a class="navbar-brand" href="#">Your App</a>
					</div>
					<div id="navbar" class="navbar-collapse collapse">
						<ul class="nav navbar-nav" data-hole="menubar"></ul>
						<ul class="nav navbar-nav navbar-right">
							<li><a href="http://websharper.com">websharper.com</a></li>
						</ul>
					</div><!--/.nav-collapse -->
				</div>
			</nav>
			<div class="container">
				<div data-replace="body">
			</div>
		</div>
		<footer class="footer">
			<div class="container">
				<p class="text-muted">
					For an enhanced template that provides automatic GitHub deployment to Azure, fork from <a href="https://github.com/intellifactory/ClientServer.Azure">GitHub</a>, or
					read more <a href="http://websharper.com/blog-entry/4368/deploying-websharper-apps-to-azure-via-github">here</a>.
				</p>
			</div>
		</footer>
		<script data-replace="scripts"></script>
	</body>
</html>

He resaltado los lugares más importantes de nuestra plantilla. Dichas marcas representan los agujeros donde se alojarán los miembros de nuestro modelo Page.

Una vez creada la instancia y pasada como parámetro a la función Content.WithTemplate, ya tenemos mágicamente nuestro contenido asíncronamente. ¿Qué más se puede pedir?

Bueno, se puede explicar qué són esos listados de Elements que usa WebSharper para crear contenido de forma dinámica y programada. ¿Qué representa el tipo Element? Element representa contenido HTML o XML.

Para crear este tipo de instancias, WebSharper ofrece un porrón de funciones camufladas con el nombre de los diferentes elementos HTML existentes con la intención de que puedas construir una jerarquía HTML/XML de forma funcional y que visualmente parezca que realmente sea HTML/XML. Un ejemplo:


H1 [Text "About"]

Aquí encontramos la función H1, función que genera un Element que representa un nodo <h1> de HTML. Como parámetro pide una lista de instancias de tipos que implementen la interfaz Web.INode, que pueden ser tanto atributos del nodo, como contenido del nodo, como otros nodos. En este caso, se llama a la función Text que simplemente genera el texto que contendra el nodo. En WebForms sería un control Literal. El renderizado de WebSharper desde el servidor sería: <h1>About</h1>.

Mediante Elements puedes hacer cualquier combinación que se os ocurra, hasta la generación dinámica de elementos. Hablando de WebForms, la verdad es que trabajar con WebSharper recuerda mucho a trabajar con este incomprendido framework (Fight!), ya que componer nuestros listados de Element recuerda mucho a trabajar con los controles de servidor de WebForms y su compositor de jerarquía de controles. Tanto me recuerda que, para mi, WebSharper es el WebForms para F#. De ahí mi cariño a este framework, F# + WebForms. ¡Qué más se puede pedir! Pues todo lo que te ofrece WebSharper, que no es poco.

Enter the Client code

Todo esto está muy bien, pero ésto sólo genera HTML desde servidor, incluso lo que hemos mostrado dinámicamente. Dónde está esto de que se programe JavaScript con F#. Dicha funcionalidad la encontramos en la función Site.HomePage, la que genera el contenido para la página principal. Aquí su código:

let HomePage ctx =
	Templating.Main ctx EndPoint.Home "Home" [
		H1 [Text "Say Hi to the server!"]
		Div [ClientSide <@ Client.Main() @>]
	]

Como remarca la linea de código, la magia comienza con la función ClientSide. Esta función espera una expresión de código delimitada. Este tipo de expresiones representan el código incluído dentro en un árbol de sintaxis abstracto. De esta forma, WebSharper es capaz de generar el JavaScript correspondiente al código incluido en dichas expresiones. Ese código acabara en ficheros .js autogenerados por WebSharper durante la compilación, visibles durante la ejecución la aplicación. Lo bueno es que WebSharper se encarga de referenciar esos ficheros .js por tí, por lo que no debes preocuparte por ellos.

¿Y qué ocurre con Client.Main? Client.Main se encuentra en un nuevo fichero: Client.fs. WebSharper ha decidido organizar el código de tal forma que todo lo que sea código de servidor para generar el HTML esté en el fichero Main.fs, mientras que el código cliente se encuentre en el fichero Client.fs. El distintivo de que el código contenido es código de cliente para WebSharper es el atributo JavaScript que se le asigna al módulo que contiene las funciones que representan nuestro código cliente.

[<JavaScrip>]
module Client = 

	let Main () =
	let input = Input [Attr.Value ""] -< []
	let output = H1 []
	Div [
		input
		Button [Text "Send"]
			|>! OnClick (fun _ _ ->
				async {
					let! data = Server.DoSomething input.Value
					output.Text <- data
				}
				|> Async.Start
			)
		HR []
		H4 [Attr.Class "text-muted"] -< [Text "The server responded:"]
		Div [Attr.Class "jumbotron"] -< [output]
	] 

¡Bufff! Cuántas cosas nuevas. Recordemos una cosa importante. Todo este código será convertido a JavaScript, no es coña.

¿Qué hay de nuevo, viejo? ¡El operador |>!! Este operador de WebSharper se encarga de enlazar controladores de eventos JavaScript a nuestros nodos de cliente. WebSharper proporciona, para ello, un porrón de funciones por cada tipo de evento de uso común, como OnClick. Como vemos, WebSharper nos permite usar los mecanismos comunes de trabajo asíncrono de F# limpiamente, sin tener que reinventar ni aprender nada de nuevo. Esto es magia.

RPC, RPC… Remoting enters the ring!!

Vayamos a nuestra última función a investigar: Server.DoSomething. Y dónde encontramos esta función? La encontramos en el último fichero fs del proyecto: Remoting.fs:

module Server

[<Rpc>]
let DoSomething input =
	let R (s: string) = System.String(Array.rev(s.ToCharArray()))
	async {
		return R input
	}

La función tiene un atributo nuevo, Rpc. ¿Qué hace este atributo? ¡MAGIA! ¡Dejarte todo loco! Convierte la función en un punto de entrada de un Web Service dinámico con el que poder ejecutar código, de nuevo, en el servidor, pero con la diferencia que lo que devuelves es un tipo normal de F#, mientras este sea serializable a JavaScript. Recordemos que en F# no hay concepto de void, siempre se devueve algo, aunque ese algo sea Unit. Una puta locura. ¡Bravo a los diseñadores de esta maravilla! En WebForms esto es lo que llamaríamos Page Methods pero con drogas potenciadoras de por medio.

La sensación de programar todo en F#, generar código de cliente y servidor de forma transparente, y que la comunicación entre ambos se haga a través de llamadas de funciones que obligan, por compilación, que las firmas de las mismas se cumplan, reduciendo la cantidad de errores que puedas generar en ambos mundos, es una puta maravilla.

Tras ver estas funcionalidads me enamoré locamente de este framework incomprendido. Tiene todas esas funcionalidades que desearía que WebForms hubiera conseguido integrar en su framework. Si integrar código de cliente y Web Services a tus páginas u controles fuera así de potente, otro gallo cantaría.

Bueno, espero que os haya podido enseñado algo de provecho. A ver con qué empiezo en el siguiente post, que tras esta introducción, ya podemos entrar en más detallitos. Como empezar a hacer algo.

¡Nos fuimos!

Desarrollando con WebSharper + Akka.NET (2 de ¿?): A ver si te pones a currar

Desarrollando con WebSharper + Akka.net (1 de ¿?): ¡¡Preparando a lo loco!!

¡¡Buenas noches señora, buenas noche señora!! Sé que me echabais de menos, locuelos desarrolladores. Seguro que estáis hasta la pilinga de aprender el framework de moda de turno. O peor, ¡os la tocáis mientras aprendéis! Pues sus toca aprender algo nuevo y locuelo. ¡WebSharper! ¡Akka.Net! ¡WTF#!

¿Qué es WebSharper? WebSharper es un framework de desarrollo de aplicaciones web de forma funcional y reactiva en .NET. .NET + funcional == F#. F# For The Win! La gracia de este framework no es el hecho de que se desarrolle en F#, sino el hecho de que, para programar una web su html, su javascript y su interacción con el servidor, todo lo programas con F#. Vamos, que lo que programas en F# y lo marcas como javascript, WebSharper se encarga de compilarlo a javascript por tí. Para más información, ésta es su web: http://websharper.com. Lo han hecho unos gachós que estaban hasta los webos de tener que cambiar el chip en el desarrollo web cada dos por tres (que si ahora .NET, que si ahora html, que si ahora javascript). Como yo.

Akka.Net. Qué decir de esta librería. Nos permite desarrollar aplicaciones en .NET dirigidas por eventos con tolerancia de errores, distribuidas y con alta concurrencia. Se basan en el modelo de actores y la gracia es que se programa diferente. En vez de desarrollar por capas, programas actores que se especializan en capturar una serie de mensajes, procesarlos y enviar más mensajes a otros actores, todo de forma asíncrona. Si alguna vez habéis trabajado con colas de mensajería o con streams como leer del twitter o cosas así, es muy parecido: cada actor escucha de una cola, cuando llega algo lo procesa y, de forma opcional, genera un nuevo mensaje que enviará a la cola de otro actor. La verdad es que te queda algo muy visual. Si lo haces más o menos bien, claro está. Al ser .NET, se puede programar en F#, y su librería para F# es un pasote. Para más información, ésta es su web: http://getakka.net. Sus desarrolladores originales son unos marcianos javeros que se aburrían y algún terráqueo .NETero carroñero lo ha copiado para variar.

¡¡¡Akkakkakkaakkaaakkakk!!! Curso de Akka por marcianos
¡¡¡Akkakkakkaakkaaakkakk!!! Curso de Akka por marcianos

Si lo juntamos todo, ¿qué tenemos? ¡Una marcianada! De las que me molan, de esas que nadie tiene los huevacos a plantear porque dan pereza: Hacer una aplicación web empleando el modelo de actores. Let’s go!

Antes de empezar a lo loco, esto es lo que voy a hacer sin ningún control: Una web de ayuda de aprendizaje de japonés para hispanohablantes. Así podremos entender mejor a estos marcianitos.

¿Y cómo empezamos? Pues como toca: creando el repositorio. Para ello trabajaremos con Gitlab. Gitlab es como Github pero tiene cosas más chulas como la posibilidad de crear repositorios privados gratuitos infinitos y tener un servicio de integración continua incluido en el propio repositorio. Yo que soy un rata pues es WinWin. Ésta es la dirección del repositorio: https://gitlab.com/Nihon-GO/Nihon-GO-Web. Comenzamos creando lo básico: README, LICENSE (que actualmente es ninguna, ¡¡¡mi tessoroo!!!), rama de develop y demás mierda aburrida y repetitiva. Sé que existen herramientas para agilizar estas mierdas, pero soy muy casero.

Lo siguiente es instalar Paket en nuestro repositorio. ¿Y qué es Paket? Aparte de lo que somos nosotros, paketesPaket es un gestor de dependencias para proyectos de .NET y Mono en, para variar, F#. Es como Nuget pero con esteroides: No solamente obtiene dependencias del repositorio Nuget sino de otras fuentes como Github. Su web es https://fsprojects.github.io/Paket/. Paket está hecho por gente como nosotros, ¡unos paketes de cuidao!

¡El proyecto hay que hacerlo molón! Para ello, seguimos las instrucciones de su web:

  1. Crea un directorio llamado .paket en la raíz del repositorio. Para crear esta carpeta desde la pantalla de exploración de Windows, lo mejor es hacerlo mediante consola de comandos mediante el comando siguiente:
    md <Ruta de la raíz del repositorio>.paket

    Si tenéis problemas, mirad aquí cómo abrir la ventana de comandos.

  2. Descargamos en nuestra carpeta reciente el fichero llamado paket.bootstrap.exe alojado en esta ruta: https://github.com/fsprojects/Paket/releases/latest. Este ejecutable es el que se descarga realmente Paket en tu sistema.
  3. Ejecutamos el ejecutable para ver que funciona. Descargará la última versión del ejecutable paket.exe. Pero éste ejecutable NO VA en el repositorio. ¡paket.exe malo!
  4. Subimos al repositorio el fichero descargado en el paso 2.
  5. Creamos en la raíz del repositorio creamos el fichero paket.dependencies, donde especificaremos las dependencias de nuestro proyecto cuando toque. Subimos el fichero también a nuestro repositorio.
  6. ¿Os acordáis del fichero maligno paket.exe que nos descargamos en el paso 3? Venga va, no es TAN malo. Tenemos que ejecutarlo vía consola de comandos con el siguiente comando:
    paket install

    Tras la ejecución correcta se generará el fichero paket.lock. Este fichero también pa’ la saca. ¡¡PERO PAKET.EXE NO COPÓN!!

Bueno. Ya tenemos instalado Paket en nuestro repositorio. Siguiente: FAKE. Ya sólo por ese nombre, aunque fuera un virus, ya lo vale en nuestro repositorio.  Pero FAKE es mucho más. FAKE es un sistema de automatización de compilación que emplea un DSL (Lenguaje de Dominio Específico) sencillo y molón mediante el lenguaje .NETero estrella: ¡F#! Lagrimitas de emoción. Para más info, id a su web: http://fsharp.github.io/FAKE/. FAKE está hecho pues pues por unos maderfakers como Dios manda.

¿Y cómo instalamos esta maravilla? Según la web, vía Nuget. Nuget, Nuget… WTF! Paket! Preparamos nuestro fichero de dependencias de Paket para que se descarge FAKE por nosotros.

source http://nuget.org/api/v2

nuget FAKE

Ale, volvemos a ejecutar el comando de instalar y volvemos a proteger en el repositorio los ficheros de paket.dependencies y paket.lock. Como dato importante, todas estas instalaciones generan una carpeta llamada packages. Como la protejáis os meto una tunda, ¡desustanciaos!

Lo siguiente que haremos será preparar un pequeño script de Hello FAKE:

// include Fake lib
#r @"packages/FAKE/tools/FakeLib.dll"
open Fake

// Default target
Target "Default" (fun _ ->
	trace "Hello World from FAKE"
)

// start build
RunTargetOrDefault "Default"

Como podéis comprobar, mi pereza es infinita y esto no es más que el script del tutorial de FAKE de la web oficial. ¡¡Vamos que es un FAKE total!!

¿Y cómo lo ejecutamos todo esto? ¡Pues usando el servicio de Integración Contínua integrado en Gitlab d’oh! Dicho CI se llama Gitlab CI. Para configurarlo necesitamos “simplemente” crear en nuestro repositorio un ficherito llamado .gitlab-ci.yml, justo en la raíz del repositorio. Este ficherito se escribe en YAML (YAML Ain’t Markup Language) y se pueden hacer bastantes cositas. A nosotros lo que nos interesa es que, primero de todo, ejecute el ejecutable paket.bootstrap.exe, se baje Paket y, una vez bajado, ejecutamos el comando de instalación de las dependencias definidas en el fichero paket.dependencies (en nuestro caso que se baje FAKE). El comando de instalación en este caso será diferente. En vez del comando install, usaremos el comando restore ya que no queremos que se regenere el fichero lock.packet. Una vez descargado todo, ya que ejecute el fichero de compilación build.fsx que hemos puesto y que haga magia.

Aquí os dejo como quedaría nuestro ficherito:

FAKE:
    script:
        - cmd.exe /C "%CI_PROJECT_DIR%/.paket/paket.bootstrapper.exe"
        - cmd.exe /C "%CI_PROJECT_DIR%/.paket/paket restore"
        - cmd.exe /C "%CI_PROJECT_DIR%/packages/FAKE/tools/Fake.exe %CI_PROJECT_DIR%/build.fsx"

Nota del FAKER (Uséase yo): Si no he corregido 30 veces el maldito ficherito hasta que funcionase, no lo he corregido nunca. La verdad es que es complicadillo. Encima para más INRI el runner alojado en Gitlab no soporta Windows y, al principio, pensaba pegarme un tiro, pero Gitlab te permite una cosa curiosa: Asociar tu propio runner casero al CI de Gitlab, de tal forma que puedas ejecutar tus acciones en la máquina Windows que decidas usar como runner. Mucha prueba y error, pero conseguí que funcionara (snif). Para más info, esta web: http://docs.gitlab.com/ce/ci/quick_start/README.html (apartado Configuring a Runner). La verdad es que es una alternativa molona.

¡Paketes. OK! ¡Fakers, OK! ¡Yamels, OK! ¡Todo listo para continuar con la aventura! Pero será pa’ otro día, ¡que no veáis cómo me ha cansado redactar hasta aquí! Es lo que tiene ser un pakete maderfaker.

¡Ala, a cascarla!

 

Desarrollando con WebSharper + Akka.net (1 de ¿?): ¡¡Preparando a lo loco!!

Tripis de ayer y de hoy presentan: Cómo cancelar una tarea asíncrona de forma cool

Hola muchachotes. Hoy quiero ir rapidito. Así que al grano: Cómo cancelar una petición asíncrona de forma cool. En C#.

Es de conocimiento general el hecho de que, para cancelar tareas asíncronas, existen las CancellationToken. Aunque la verdad, pocos o ningún proyecto laboral que me hay encontrado las usa. ¡Ya podéis esperar qué calidad tienen! El caso es que estos tokens van muy bien para cancelar llamadas a servicios externos por cosas como timeouts o cancelación del usuario. Pero dentro de las librerías de .Net aún hay APIs con definiciones asíncronas que no aceptan estos tokens, malditas ellas. Un ejemplo es la clase TcpClient. Esta clase tiene varios métodos asíncronos de apertura de conexión, pero ninguno acepta un token de cancelación. Y eso es un problema porque si se queda colgada la conexión ya tienes un pequeño marroncete. Tiene que existir alguna forma de no liarla parda. Os la muestro a continuación:

async Task ConnectAsync(IPAddress ipAddress, int port, CancellationToken ct = default(CancellationToken))
{
     using(var tcpClient = new TcpClient())
     {
         using (var ctr = ct.Register(() =&gt; tcpClient.Cancel(), true)) // TADA!!
         {
             await tcpClient.ConnectAsync(ipAddress, port);
             ct.ThrowIfCancellationRequested();
         }
     }
}

Gracias al método Register de la clase CancellationToken, podemos realizar la cancelación de la tarea de forma manual.

Y ahora… ¡¡CANCEL ALL THE THINGS!! ¡Nos vemos prontito!

Tripis de ayer y de hoy presentan: Cómo cancelar una tarea asíncrona de forma cool

F# – Qué es lo que me gusta de este lenguaje

Yeeeeee, que pahaaa!! Espero que animadicos como siempre, a leer tontunás de las mias. Hoy sus vengo a hablar de un lenguaje que lo peta donde pasa: F#. “Ya está éste hablando de sus paridas…” ¡¡Quién ha dicho eso!! ¡¡Como te coja te dejo atolondrao para el resto de la semana, copón!! ¡¡Desustanciao!! Maño, que saltos cojo.

F# es un lenguaje multi-paradigma orientado a los lenguajes funcionales. Digamos que es principalmente funcional, pero que es capaz de permitir desarrollo imperativo u orientado a objetos. Este diseño viene dado principalmente por ser un lenguaje de .NET, y para poder ser compatible con los otros grandes miembros de la familia (C# y VB), pues se tiene que adaptar a todo. Pero lo que interesa es la parte funcional, claro.

Características únicas que tiene especiales F# podríamos hablar para muchos posts, pero soy un vago. Buscaros la vida. No sabéis la pereza que da escribir desde el móvil. Yo quiero hablaros de esas características que, realmente, lo hacen único.

Inmutabilidad por defecto, tipos no nulos, pattern matching… todas esas cosas tarde o temprano llegará al resto de lenguajes de la familia porque son unos culo veo culo quiero, pero hay ciertas cosas que jamás llegarán porque implicaría cambios tan grandes que la gente prepararía hogueras en las oficinas de Microsoft. En mi opinión, son esas cosas las que realmente nos ayudan a ser mejores programadores en general.

La organización del código top-down

Existen un par de cosas que chocan cuando creas proyectos de F#: La imposibilidad de crear carpetas y la exigencia que los ficheros estén uno encima de otro, como si fuera una torre de jenga. Lo de las carpetas se puede trucar pero te recomiendan evitarlas. Lo de los ficheros ya no, y es mejor que sea así. Es curioso ver como Visual Studio te ofrezca las opciones de “Crear por encima” o “Crear por debajo” a la hora de querer crear un nuevo fichero. Todo este berenjenal es por una razón: Cuando compilas una librería de F#, va parseando los ficheros uno a uno de arriba a abajo en orden secuencial. Con esto, F# consigue que las compilaciones de sus librería sean muy ágiles, ya que no tiene que complicarse mucho la vida. También evita las referencias circulares entre ficheros y objetos.

Imaginaros ahora un mundo donde las librerías de C# ni tuvieran carpetas ni tuvieras la flexibilidad de crear fichero y que el visual se espabile de colocarlo como toca. Una locura. Pero en F# acaba siendo algo genial.

He comentado antes de que esta compilación top-down evita referencias cíclicas. ¿Pero cómo se hace si se quiere definir un tipo con referencia bidireccional de otro tipo? Es decir, si quiero definir un tipo A que expone una propiedad de tipo B, y dicho tipo B expone una propiedad de tipo A. Vayamos a ello:

 
// ERROR DE COMPILACIÓN. TIPO BFail NO DEFINIDO 
type AFail = 
   { PropertyB : BFail }
  
type BFail = 
  { PropertyA : AFail } 

Vaya, menudo problema… Será posible… ¡¡PUTA MIERDA F#!! ¡Nooo F# es nuestro amigo, es bueno, nos cuida! ¡¡NOO!! ¡¡F# ES MALO!! ¡¡NOS ODIA!! ¡¡NO NOS DEJA DEFINIR TIPOS CON DEPENDENCIA CÍCLICA SEBOSA!! ¡Nooo miremos ForoCoches! ¡Ahí está el conocimiento absoluto!

Admirando el conocimiento de ForoCoches
Admirando el conocimiento de ForoCoches

Ah, ForoCoches. Olimpo de la sabiduría. En F# existe una partícula llamada and que nos permite solventar el problema de los tipos con propiedades bidireccionales:

 
// ¡Esto compila!
type AOk = 
   { PropertyB : BOk } 
and BOk = // ¡ALERTA AQUÍ, EL SEGUNDO TIPO NO REQUIERE TYPE!
   { PropertyA : AOk } 

Esta solución, tal y como podemos ver, sólo es posible cuando defines los tipos dentro de un mismo fichero y un mismo ensamblado o módulo. La verdad es que, en el fondo, definir este tipo de objetos son malignos, por lo que F# te lo restringe la basura de código que vayas a hacer a lo más controlado. Dentro de lo malo, lo menos malo. Y ver esos and por todo el código es hasta molesto, porque te obliga a cambiar la forma de leer el código.

Uno de los mayores beneficios de esta forma de programar es que te obliga mucho a estructurar tu código muy bien. Por ejemplo, algo muy común de encontrarse es la definición de una arquitectura por capas en la que cada capa es un fichero y que el fichero más alto es la capa de mayor relevancia. Por ejemplo, en una arquitectura a tres capas, la capa más transversal es la de infraestructura. Pues ese es el primer fichero. Después sería la capa de dominio, que tiene acceso a la capa de infraestructura y nada más. Pues ese es el segundo fichero. Después vendría la capa de repositorio, que depende del dominio y de la infraestructura (tercer fichero). Cerrando el ciclo sería la capa de aplicación. Esta capa ataca tanto a la capa de infraestructura, como la de dominio y la de repositorio (cuarto fichero). Para finiquitar, suponiendo que sea una aplicación de servicio web, tendríamos el fichero final que sería el fichero donde estarían los endpoints y las llamadas a la capa de servicio de aplicación. Las dependencias están muy claras con esta organización de ficheros. En F# lo de que un fichero tenga muchos tipos es algo bien visto porque el hacer tipos es algo tan barato que el tener fichero por tipo se ve una inutilidad. Y la verdad es que cuando trabajas con ello al principio choca, pero acaba convirtiéndose en algo natural, algo que, cuando vuelves a C# es como decir “otra vez este palazo de escribir por gusto y la locura de ficheros”.

Sobre esto os recomiendo que miréis en ForoCoches y, en caso de que no sepáis hacer la o con un canuto, os dejo el enlace de un articulo no tan bueno como los de ForoCoches pero se le acerca (se copian, fijo): http://fsharpforfunandprofit.com/posts/recipe-part3/.

Bueno majetes. Ya me he cansao de escribir por hoy. Nos vemos pronto. ¡¡Ala a cascala!!

F# – Qué es lo que me gusta de este lenguaje

Project Euler (Aka Proyecto Lerder): Problema 1

Que pasa muchachada, cuánto tiempo. Os diría miles de excusas para explicar el porqué llevo tanto tiempo sin escribir y todas serían mentira, así que os diré una: ¡Mudanza! Por lo demás, vaguería que me caracteriza.

En mi día a día de leer sobre frikadas de lenguajes en vez de porno o Foro Coches/Wikipedia, me he encontrado a un tío que se dedicaba a resolver problemas matemáticos de un sitio llamado Project Euler. Esta web se dedica a tocar los webos al personal retándolos con problemas matemáticos, a cada cual más difícil, todos ellos en inglés para tocar la moral. Yo lo he nombrado Proyecto Lerder. Te puedes registrar y vacilar copiando las respuestas de otros y creerte listo y todo. Vamos, nada que un usuario de Foro Coches medio/bajo no sepa contestar. Actualmente cuenta con 534 ejercicios. Cuando leáis esto ya habrán 15 o 20 más pero no pasa nada. Googlead, que es sano.

Pues me registro. Mi usuario es Micha-kun. Me intento autenticar. Error de código de confirmación. ¡¡ME CAGO EN LAPUTA PUTA MIERDA DE RECAPTCHA!! Si no me he intentado logar 20 veces no lo he intentado. Al final, después de una alineación de planetas conseguí entrar. Y continuan ahí los retos para lerdos. El primer reto es el entrar.

Veamos el primer problema, llamado Multiples of 3 and 5. En mi cabeza es Múltiples de tres y cinco, lerdo, que esto ya lo han resuelto 531870 frikis aburridos antes que tu, de todos ellos 531869 han sido copy/paste del primero. Dificultad: Tu gato lo resuelve con los huevos, y está castrado. Bien.

Veamos el enunciado del problema:

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.

El texto original está en Nigger, por lo que os he eliminado los “Fuck dis” o “Fuck dat”. Tras varios intentos en mi cabeza se traduce así:

A ver lerdo, te lo voy a explicar en sencillo porque no te enteras. Si coges los números del uno al nueve que dividan entre tres o cinco y los sumas, da 23.

¡A que no hay huevos a hacer lo mismo pero del 1 al 999, lerdo de mierda!

¡¡ME CAGO EN LA PUTA!! Putos niggers se van a enterar de quien es el Micha-kun! ¡¡A pelo!!

3 + 5 + 6 + 9 + 10 + 12 + 15 + 18 + 20 + 21 + 24 + 25 + 27 + 30 + 33 + 35 + 36 + 39 + 40 + 42 + 45 + 48 + 50 + 51 + 54 + 55 + 57 + 60 + 63 + 65 + 66 + 69 + 70 + 72 + 75 + 78 + 80 + 81 + 84 + 85 + 87 + 90 + 93 + 95 + 96 + 99 + 100 + 102 + 105 + 108 + 110 + 111 + 114 + 115 + 117 + 120 + 123 + 125 + 126 + 129 + 130 + 132 + 135 + 138 + 140 + 141 + 144 + 145 + 147 + 150 + 153 + 155 + 156 + 159 + 160 + 162 + 165 + 168 + 170 + 171 + 174 + 175 + 177 + 180 + 183 + 185 + 186 + 189 + 190 + 192 + 195 + 198 + 200 + 201 + 204 + 205 + 207 + 210 + 213 + 215 + 216 + 219 + 220 + 222 + 225 + 228 + 230 + 231 + 234 + 235 + 237 + 240 + 243 + 245 + 246 + 249 + 250 + 252 + 255 + 258 + 260 + 261 + 264 + 265 + 267 + 270 + 273 + 275 + 276 + 279 + 280 + 282 + 285 + 288 + 290 + 291 + 294 + 295 + 297 + 300 + 303 + 305 + 306 + 309 + 310 + 312 + 315 + 318 + 320 + 321 + 324 + 325 + 327 + 330 + 333 + 335 + 336 + 339 + 340 + 342 + 345 + 348 + 350 + 351 + 354 + 355 + 357 + 360 + 363 + 365 + 366 + 369 + 370 + 372 + 375 + 378 + 380 + 381 + 384 + 385 + 387 + 390 + 393 + 395 + 396 + 399 + 400 + 402 + 405 + 408 + 410 + 411 + 414 + 415 + 417 + 420 + 423 + 425 + 426 + 429 + 430 + 432 + 435 + 438 + 440 + 441 + 444 + 445 + 447 + 450 + 453 + 455 + 456 + 459 + 460 + 462 + 465 + 468 + 470 + 471 + 474 + 475 + 477 + 480 + 483 + 485 + 486 + 489 + 490 + 492 + 495 + 498 + 500 + 501 + 504 + 505 + 507 + 510 + 513 + 515 + 516 + 519 + 520 + 522 + 525 + 528 + 530 + 531 + 534 + 535 + 537 + 540 + 543 + 545 + 546 + 549 + 550 + 552 + 555 + 558 + 560 + 561 + 564 + 565 + 567 + 570 + 573 + 575 + 576 + 579 + 580 + 582 + 585 + 588 + 590 + 591 + 594 + 595 + 597 + 600 + 603 + 605 + 606 + 609 + 610 + 612 + 615 + 618 + 620 + 621 + 624 + 625 + 627 + 630 + 633 + 635 + 636 + 639 + 640 + 642 + 645 + 648 + 650 + 651 + 654 + 655 + 657 + 660 + 663 + 665 + 666 + 669 + 670 + 672 + 675 + 678 + 680 + 681 + 684 + 685 + 687 + 690 + 693 + 695 + 696 + 699 + 700 + 702 + 705 + 708 + 710 + 711 + 714 + 715 + 717 + 720 + 723 + 725 + 726 + 729 + 730 + 732 + 735 + 738 + 740 + 741 + 744 + 745 + 747 + 750 + 753 + 755 + 756 + 759 + 760 + 762 + 765 + 768 + 770 + 771 + 774 + 775 + 777 + 780 + 783 + 785 + 786 + 789 + 790 + 792 + 795 + 798 + 800 + 801 + 804 + 805 + 807 + 810 + 813 + 815 + 816 + 819 + 820 + 822 + 825 + 828 + 830 + 831 + 834 + 835 + 837 + 840 + 843 + 845 + 846 + 849 + 850 + 852 + 855 + 858 + 860 + 861 + 864 + 865 + 867 + 870 + 873 + 875 + 876 + 879 + 880 + 882 + 885 + 888 + 890 + 891 + 894 + 895 + 897 + 900 + 903 + 905 + 906 + 909 + 910 + 912 + 915 + 918 + 920 + 921 + 924 + 925 + 927 + 930 + 933 + 935 + 936 + 939 + 940 + 942 + 945 + 948 + 950 + 951 + 954 + 955 + 957 + 960 + 963 + 965 + 966 + 969 + 970 + 972 + 975 + 978 + 980 + 981 + 984 + 985 + 987 + 990 + 993 + 995 + 996 + 999 == ¡¡KABOOM MENTAL!!

Tiene que haber una forma más molona de hacer esto… ¡Pues claro! ¡Programando! ¡Vayamos a resolver el problema mediante código!

Para ello usaré mi herramienta favorita para mierdas de éstas: LINQPad. Como soy así de toca huevos, lo resolveré en dos lenguajes: C# y F#. Me han tocado los webos y bien estos del Proyecto Lerder.

Versión C#:

 Enumerable.Range(1,1000-1).Where(x => x % 3 == 0 || x % 5 == 0).Sum(); 

Versión F#:

 [1..1000-1] |> List.filter (fun x -> x % 3 = 0 || x % 5 = 0) |> List.sum 

Y la solución es… ¡¡SÓLO MÍA!! ¡¡MWAHAHAHAHAHA!! ¡¡PRUEBA SUPERADA!!

PD: No me seáis lerdos y, si queréis solventar estos problemas para lerdos hacedlo vosotros mismos a vuestra manera sin mirar el código de los demás. Pero si sólo tenéis curiosidad… ¡Pues adelante!

Project Euler (Aka Proyecto Lerder): Problema 1

Freimuorcalipsis Nau – Los Kejikas

Aaah la vida de un kejika… llena de sufrimiento autoimpuesto. Todo programador profesional ha sido un poco kejika a lo largo de su vida profesional. Yo el primero. Y aún escribiendo esto, seguro que en el futuro lo seguiré haciendo.

¡¡Menudo código de mierda!!
¡¡Menudo código de mierda!!

¿Qué entiendo por programador kejika? Todo aquel programador que le molesta trabajar sobre algo que no cumple sus requisitos de calidad mínima o con alguna tecnología que no es de su agrado. Hay más causas, pero esas dos son las más predominantes.

¡¡Esto está hecho con el puto culo!!

No sé cuántas veces habré dicho esa frase gritando al mundo. Es el momento en el que te toca mantener código legado. Inconscientemente, el programador busca si la solución está diseñada tal y como haría él mismo. Y eso, a no ser que trabajes en una empresa que exija unas normas de desarrollo mínimas, no va a ocurrir nunca. Pero nunca aprendes y siempre lo haces.

Da igual el nivel de conocimientos que tenga el programador. Si eres muy novato, porque el código es muy difícil de entender. Si eres muy experto, porque es muy ineficiente o porque no cumple tu interpretación del patrón X tal y como sabes. ¡La cuestión es kejarse!

Frases típicas:

  • WTF!?
  • ¡Esto es una puta mierda!
  • ¡Hay que tirarlo todo y rehacerlo!
  • ¡No me entero de nada!

Las reacciones posteriores suelen variar un poco, en dependencia del tiempo disponible. Los cambios van desde el parcheo de código al desprecio absoluto y rehacer el producto a su manera, porque es mejor. Ninguna de las dos decisiones suele acabar bien, pero algo hay que hacer.

¿Qué puede ayudar en momentos así? Es inevitable soltar improperios sin ton ni son en situaciones así. Respira hondo. Lo más seguro es que sea más grande la imagen del Armagedón de tu cabeza de la tarea que lo que tengas que realmente que hacer, pero esto te lo da la experiencia. Muchas veces ese código realmente no es tan mierda… simplemente un poco incomprendido. Hay que tener en cuenta que el o los que hicieron el código lo hizo así con la intención de solventar el problema.

¡¡Puto XXX (pon nombre de framework) de mierda!!

Si hay algo en nuestra profesión que genera la mayor cantidad de kejas, es el uso de frameworks. Pero no de cualquier framework, sino del framework que no quieres usar por infinitas razones. Porque si hay algo que sorprende en nuestra psique es que parece que nuestra profesión sea como ser aficionado de fútbol: Elegimos un equipo (un ejemplo, Entity Framework o NHibernate) y el resto es el enemigo acérrimo que debe desaparecer del mundo. Y vemos algo hecho en esa odiada creación y da igual si ese código es funcional y que, simplemente, el problema a corregir es activar una opción de la librería o agregar algún filtro. ¡¡Hay que tirarlo todo!! ¡¡Ese framework es el mayor mal del universo!! ¡¡Espuma por la boca!! Quien dice ORMs, dice WebForms vs MVC, Ninject vs Unity, XUnit vs NUnit, etcétera.

Y los frameworks es lo más suave, a la que hablamos de lenguajes la radicalización se multiplica. Aunque es cierto que últimamente estamos en un periodo donde, gracias al desarrollo orientado a Microservicios, vamos aceptando el desarrollo en varios lenguajes o tecnologías, cierto es que este tipo de desarrollos actualmente es muy minoritario y muy poca gente habituada a este tipo de proyectos. Menos en España. Así, tenemos gente que programa en C# que si se topa con código en Visual Basic lanza maldiciones. Bueno, contra cualquier cosa que no sea C# (exceptuando Javacript en el caso de desarrolladores web).

No os enfadéis con estas tecnologías diferentes a vuestras favoritas como JustinBiebORM, RealMadriVC o FCSharpcelona. Aprovechad la ocasión para conocer nuevas cosas y sacarle jugo, que tampoco son tan malos. Sólo diferentes. ¡¡¡¡Xenworkfobos todos!!!!

Bueno, por hoy ya estoy. Iré actualizando este post con nuevas tontunadas que se me pasen por la cabeza. Sed buenos niños y no os quejéis tanto. ¡Yogur!

Freimuorcalipsis Nau – Los Kejikas