Marzo de 2017

Volumen 32, número 3

Bot Framework: cómo mejorar la inteligencia de los bots

Por Kevin Ashley | Marzo de 2017

Microsoft Bot Framework, LUIS, Azure Bot Service, Azure Functions son términos que he oído por todas partes estos días: los bots son las nuevas aplicaciones. Un motivo es la sencillez y la eficacia que confieren a las tareas comunes. Piense en ello: En lugar de pasar de Bing o Google a dos, tres o más sitios web para reservar un vuelo o hacer una reserva en un restaurante, puede simplemente pedir a algún tipo de asistente digital que lo haga por usted. No obstante, podría haber un motivo todavía más importante para que los desarrolladores de aplicaciones adopten esta tendencia: El costo de creación de aplicaciones móviles es cada vez más alto. La compilación de una sola aplicación móvil puede costar entre 30 000 y medio millón de dólares para cada plataforma: iOS, Android y Windows.

Cierto, existen algunas tecnologías multiplataforma, como Unity o Xamarin, que pueden contribuir a reducir el costo del desarrollo para varias plataformas. No obstante, los bots emergen como una nueva opción, y cambian el paradigma mediante el uso de una interfaz de conversación. Este enfoque aprovecha las comunicaciones que la humanidad usa desde hace miles de años, y abarca voz y texto (piense en Skype o Messenger). La UI de conversación (CUI) también se puede mejorar con imágenes, vídeos y controles tradicionales, como Buttons y CardActions. En los bots, el foco se encuentra en la simplicidad y en los aspectos naturales de la entrada, en lugar de confeccionar la UI con controles tradicionales.

¿Cuál es el beneficio? Un ahorro acumulado potencial de miles de millones de dólares, al alejarse las organizaciones de la compilación de distintas UI para cada paradigma de pantalla y, en su lugar, adoptar interfaces de conversación que funcionen en todos los dispositivos y factores de forma, con o sin pantalla. Por ejemplo, compilé un bot de Active Fitness que ayuda a buscar rutas para correr, ir en bicicleta, hacer senderismo, esquiar y realizar otras actividades en zonas próximas. (Visite bit.ly/2knZVbr para agregarlo a Skype). Aunque la aplicación presenta una UI completa y controles, el bot está diseñado para comprender la entrada de conversación, como se muestra en la Figura 1.

Bot de Active Fitness que muestra rutas
Figura 1 Bot de Active Fitness que muestra rutas

El impacto va más allá del desarrollo de aplicaciones. Los bots pueden abordar los retos de los sitios web, en los que cada vez es más difícil navegar y muchos de los cuales usan marcos o estándares web antiguos u obsoletos. Intente completar una tarea en cualquier sitio web de atención al cliente, por ejemplo. Probablemente, pasará una media hora navegando por el menú del sitio web.

Luego, solo existe una única cobertura de bots. Imagine una aplicación de juego de cartas, como Solitario. Antes de los bots, tenía que compilar una versión para cada plataforma. Ahora, sin embargo, los bots alteran la trampa que bloquea la plataforma. De repente, mis aplicaciones basadas en Windows funcionan como bots en todos los dispositivos iPhone y Android de mis amigos. ¿Por qué no? Porque los bots funcionan en canales: Skype, Telegram, Facebook Messenger, Slack y otras plataformas de aplicaciones masivas.

Supuse que estaría bien compilar el juego más popular del mundo con Microsoft Bot Framework, así que la Figura 2 muestra mi interpretación de Solitario, listo para jugar. (Visite bit.ly/2jrzP7S para agregarlo a Skype).

Mi bot de Solitaire en Skype gestiona 500 000 solicitudes semanales
Figura 2 Mi bot de Solitaire en Skype gestiona 500 000 solicitudes semanales

Para comenzar a crear bots, diríjase al sitio de Microsoft Bot Framework (dev.botframework.com). Puede compilar bots con Microsoft .NET Framework o Node.js, la tecnología que prefiera. Recientemente, Microsoft agregó Azure Bot Service (bit.ly/2knEtU6) como un nuevo y práctico método para implementar bots. Azure Bot Service proporciona una experiencia basada en explorador para compilar bots a partir de plantillas fáciles de usar. El servicio usa Azure Functions, una arquitectura de código sin servidor basada en eventos con "funciones" que permiten ahorrar dinero y escalar mejor los bots. 

Esto es lo mejor de Azure Functions: Cuando empecé a compilar bots, me di cuenta de que, cada vez que necesitaba un bot, tenía que crear una nueva aplicación web para proporcionar un contenedor de aplicaciones. Eso está bien para una aplicación, pero no para varios bots, cada uno de los cuales necesitaría una infraestructura diferente. En su lugar, Azure Functions permite hospedar pequeños fragmentos de código en la nube, sin tener que preocuparse por toda la infraestructura de la aplicación.

Inteligencia y desarrollo de bots

Como sucede con las aplicaciones, los bots tienen la finalidad de ayudarle con la tarea específica que mejor saben realizar. Por ejemplo, mi bot de Solitario puede jugar a Solitario con usted, e incluso enseñarle reglas y trucos del juego. Cierto, no es probable que pase el test de Turing (un método para medir la inteligencia de una máquina desarrollado por Alan Turing en la década de los 50), pero eso sería probablemente excesivo para la mayoría de los bots.

Igualmente, un bot para su oficina de un concesionario local debería saber algunas cosas sobre el envío de un pago para el registro de su licencia o cómo ayudarle a pagar una multa o una prórroga del permiso de conducir. Un bot de meteorología debe responder a preguntas relacionadas con el tiempo, y la inteligencia del bot podría incluir maneras de resolver la ubicación y las necesidades del usuario de datos meteorológicos específicos.

Los bots pueden automatizar muchas tareas a través de una interfaz de conversación, pero también se pueden mejorar con imágenes, botones y otros controles, que mejoran aún más la interacción con los dispositivos móviles. La inteligencia del bot entra en juego realmente cuando las conversaciones pasar a ser abiertas. El uso de cuadros de diálogo para un conjunto predefinido de respuestas es una tarea de programación estándar relativamente sencilla. Por otro lado, responder a una conversación humana implica inteligencia. Afortunadamente, Microsoft Bot Framework permite ambas cosas: LuisDialogs habilita la compatibilidad de las conversaciones basadas en el lenguaje, mientras que los controles más tradicionales permiten a los usuarios presionar botones, secuencias u otros controles para seleccionar opciones.

La inteligencia es el centro de la IU de conversación que emplean muchos bots, lo que permite la interacción intuitiva con humanos. El volumen creciente de Cognitive Services de Microsoft (bit.ly/2jx1kMQ) permite conectar funcionalidades inteligentes directamente al bot. Estos servicios incluyen (sin limitación):

  • Visión
  • Voz
  • Lenguaje
  • Información
  • Búsqueda
  • Ubicación

Lea el fantástico artículo de Alessandro Del Sole sobre Cognitive Services en msdn.com/magazine/mt742868

La mejora de la inteligencia del bot implica el uso de algunas medidas comunes que podrían no conseguirlo en un test de Turing, pero que sin duda mejorarán las conversaciones con el bot:

  • Cuadros de diálogo, imágenes y otros métodos para recopilar datos normalizados, transmitir un mensaje y simplificar las conversaciones
  • Localización
  • Canalizaciones de ayuda y cuadros de diálogo para mejorar las funciones básicas de los bots
  • Datos de usuario (como la ubicación) para eliminar la duplicación de preguntas

No debe pretender ser demasiado ambicioso ni intentar crear un bot que parezca el equipo Deep Thought del tamaño de una ciudad de Douglas Adams (de "The Hitchhiker’s Guide to the Galaxy"). Más bien, cuando empecé a compilar mis bots, los limité a las funciones esenciales para las principales tareas: como jugar a cartas o sugerir las mejores rutas para correr y, luego, les agregué inteligencia para mejorarlos.

Inteligencia del lenguaje con LUIS

El primer componente de inteligencia que se debe tener en cuenta para agregar a una interfaz de conversación es Microsoft Language Understanding Intelligent Service (LUIS). Este servicio funciona mediante el análisis de conversaciones u oraciones que le envía, y la extracción de intenciones y entidades reales específicas para la aplicación. Para agregar un cuadro de diálogo de LUIS al bot, solo tiene que crear una clase que herede Luis­Dialog, registrar su aplicación de LUIS en luis.ai, y proporcionar un id. y una clave de la aplicación al cuadro de diálogo:

[LuisModel("<YOUR_LUIS_APP_ID>", "<YOUR_LUIS_APP_KEY>")]
[Serializable]
public class IntelligentLanguageDialog : LuisDialog<object>

Para obtener una guía detallada de LUIS, consulte el artículo de MSDN Magazine de enero de 2017 de Ashish Sahu en msdn.com/magazine/mt745095.

En mi bot de rutas de Active Fitness (Figura 3), definí las intenciones relacionadas con actividades de forma física. Espero que el usuario proporcione la ubicación y la actividad de forma física como parte de una conversación de bot inteligente. Un usuario debería poder decir, por ejemplo, "muéstrame las rutas de esquí de Colorado", y el bot debería comprenderlo y mostrar un conjunto de rutas. Los usuarios de mi aplicación Active Fitness recorren millones de rutas diariamente y, al realizar consultas en Active Fitness, pueden asignar la intención GetActivityLocation de mi modelo de LUIS, que devuelve las entidades de geografía y actividad al bot.

Modelo de LUIS
Figura 3 Modelo de LUIS

Imagine cuánta codificación tendría que hacer para extraer todos los datos de la entrada de usuario sin normalizar. Incluso una oración humana breve suele implicar un nivel de complejidad que solo las herramientas de Machine Learning pueden comprender y procesar. Agregue todas las variaciones posibles de esa oración simple y observe que la inteligencia del bot no es una tarea trivial. Afortunadamente, LUIS actúa como un analizador y extractor de conversaciones inteligente que lleva a cabo todo el trabajo duro por usted. Todo lo que tiene que hacer es agregarlo al bot.

Después de definir el modelo, puedo entrenarlo mediante el suministro de declaraciones que ayuden a LUIS a comprender cuáles son mis intenciones y cómo obtener entidades para mi bot. Al entrenar el modelo para mi intención GetActivity­Location, proporcioné las siguientes declaraciones: "Mostrar rutas de ciclismo cercanas", "Mostrar las últimas rutas de snowboard de Austria" y "¿Dónde están las pistas de esquí más largas de ?" Como muestra la Figura 4, cuando LUIS procesa las entidades, resalta las entidades que especifiqué en mi modelo. ¿Qué sucede si LUIS no reconoce una entidad? Aquí es donde se entrena mediante la asignación manual de entidades. Por ejemplo, tuve que entrenar mi bot para que reconociera "snowboard" como una actividad.

Entrenamiento de modelos en LUIS
Figura 4 Entrenamiento de modelos en LUIS

A continuación, debe definir modelos que controlen las intenciones que devuelve el modelo de LUIS. Puede tener métodos que controlen una intención None o cualquier otra intención del modelo, como muestra la Figura 5.

Figura 5 Control de intenciones

[LuisIntent("None")]
  public async Task NoneIntent(IDialogContext context, LuisResult result)
  {
    await context.PostAsync(
      $"You have reached the none intent. You said: {result.Query}"); //
    context.Wait(MessageReceived);
  }
  // Go to https://luis.ai and create a new intent,
  // then train/publish your luis app.
  // Finally, replace "GetActivityLocation" with the name of your newly
  // created intent in the following handler.
  [LuisIntent("GetActivityLocation")]
  public async Task GetActivityLocation(IDialogContext context, LuisResult result)
  {
    await context.PostAsync(
      $"You have reached the GetActivityLocation intent. You said:
      {result.Query}"); //
    context.Wait(MessageReceived);
  }

Cada vez que el modelo determine que la entrada coincide con una intención Get­ActivityLocation, llamará al método de mi bot. LUIS devuelve el resultado en el objeto LuisResult e incluye entidades, como las de ubicación y actividad. Por ejemplo, quiero comprobar si entre las entidades se incluye un país. Para hacerlo, uso el método TryFindEntity del objeto LuisResult y busco el tipo de entidad "builtin.geography.country". LUIS proporciona varias entidades pregeneradas, que simplifican el trabajo enormemente. Puede obtener una lista completa de estas entidades en bit.ly/2kWgCHR.

Observe que la entidad builtin.geography contiene subentidades, como las de país y ciudad. Una entidad que contiene subentidades se conoce como una entidad compuesta. En este caso, me interesa específicamente la subentidad de país, como se muestra en la Figura 6.

Figura 6 Búsqueda de la entidad de país

// Go to https://luis.ai and create a new intent, then train/publish your luis app.
  // Finally, replace "GetActivityLocation" with the name of your
  // newly created intent in the following handler.
  [LuisIntent("GetActivityLocation")]
  public async Task GetActivityLocation(IDialogContext context, LuisResult result)
  {
    await context.PostAsync(
      $"You have reached the GetActivityLocation intent. You said:
      {result.Query}"); //
    EntityRecommendation country;
    if(result.TryFindEntity("builtin.geography.country", out country))
    {
      await context.PostAsync($"Country: {country.Entity}");
    }
    context.Wait(MessageReceived);
  }

Sugerencias básicas sobre los bots

Microsoft está ejerciendo presión en el frente de desarrollo de bots, con el lanzamiento de herramientas, tales como Language Understanding Intelligent Service (LUIS) y Azure Bot Service, para contribuir a simplificar la creación y la administración de esta nueva clase de software. La buena noticia es que la mayoría de las aplicaciones actuales se pueden transformar fácilmente en bots, donde la UI de conversación (CUI) es la solución perfecta para múltiples tareas y tipos de aplicaciones. Para sacar el máximo partido del esfuerzo de desarrollo de bots, estos son algunos aspectos que se deben tener en cuenta:

Apostar por el alcance: uno de los aspectos más atractivos de los bots es que se ejecutan en canales que se encuentran en cada PC, tableta y smartphone, como Skype, Facebook Messenger y Telegram. Llegue al máximo de destinatarios con la publicación de sus bots en varios canales. Asimismo, aproveche los servicios disponibles para localizar su bot a varios idiomas.

Sea un conversador: haga un buen uso de la interfaz de conversación, que resulta ideal para múltiples tareas y tipos de aplicaciones. Para obtener los mejores resultados, céntrese en las interfaces de conversación, como el chat, la voz y el lenguaje, en lugar de en los controles de interfaz de usuario tradicionales, como los botones.

Servicio: el nuevo Azure Bot Service es una plataforma basada en la nube, que minimiza la sobrecarga de la infraestructura y permite la escala de los proyectos de bots. Detrás de esta funcionalidad se encuentra Azure Functions, que permite a los desarrolladores hospedar pequeños fragmentos de código en la nube.

Manténgase alerta: al compilar bots, céntrese en las tareas específicas que cada bot debe resolver. No se complique demasiado: un exceso de inteligencia artificial no siempre es mejor. Comience con la tarea principal que su bot debe resolver y, luego, inyecte inteligencia.

En voz alta: use las capacidades integradas en LUIS para permitir las conversaciones abiertas y proporcionar una entrada para el bot. Para obtener unos resultados óptimos, procure entrenar su modelo de LUIS, prestando especial atención a un reducido conjunto de entidades e intenciones. Cuanta menos "dispersión" tenga el modelo, mejor funcionará la inteligencia artificial.

Obviamente, también debo conocer la entidad de actividad (puede usar Active Fitness para realizar el seguimiento de más de 50 actividades, como correr, ir en bicicleta y practicar esquí o snowboard). Por tanto, cuando pregunto: "¿Cuál es la mejor estación de esquí de Austria?" Espero que el bot de Active Fitness devuelva "esquí" como mi entidad de actividad, como se muestra en la Figura 7.

La intención GetActivityLocation en acción con el emulador de bots
Figura 7 La intención GetActivityLocation en acción con el emulador de bots

Entonces, actualicé mi método GetActivityLocation para devolver la actividad. Observe que, a diferencia de builtin.geography.country, mi actividad no es una entidad integrada. Aún así, LUIS lo resuelve bastante bien cuando proporciono algunas declaraciones durante el entrenamiento del modelo, como se muestra en la Figura 8.

Figura 8 Entrenamiento del modelo con declaraciones

// Go to https://luis.ai and create a new intent, then train/publish your luis app.
  // Finally, replace "GetActivityLocation" with the name of your newly
  // created intent in the following handler.
  [LuisIntent("GetActivityLocation")]
  public async Task GetActivityLocation(IDialogContext context, LuisResult result)
  {
    await context.PostAsync(
      $"You have reached the GetActivityLocation intent. You said:
      {result.Query}"); //
    EntityRecommendation country;
    if(result.TryFindEntity("builtin.geography.country", out country))
    {
      await context.PostAsync($"Country: {country.Entity}");
    }
    EntityRecommendation activity;
    if (result.TryFindEntity("activity", out activity))
    {
      await context.PostAsync($"Activity: {activity.Entity}");
    }
    context.Wait(MessageReceived);
  }

Bot Framework proporciona ejemplos de código genéricos en profundidad para C#, en bit.ly/2gHupjg, y para Node.js, en bit.ly/2kWolWx.

Perfeccionamiento de la ubicación

Muchos bots proporcionan respuestas basadas en la ubicación, pero la codificación en torno a las respuestas de ubicación puede ser soporífera. En el ejemplo anterior, usé la inteligencia de LUIS para someter una entidad de geografía integrada al análisis de LUIS desde la conversación. Afortunadamente, el control de ubicación de Microsoft Bing forma parte ahora de Bot Framework, lo que facilita enormemente a los desarrolladores la recopilación de datos basados en la ubicación.

El control de ubicación de Bot Framework también proporciona una interfaz visual que incluye mapas (consulte la Figura 9). Esto puede resultar muy práctico si su bot tiene que proporcionar direcciones que incluyan datos de código postal, región y localidad, desde una interfaz intuitiva o nativa que funcione en canales, como Skype y Facebook Messenger.

Control de ubicación mediante la interfaz visual de Mapas de Bing
Figura 9 Control de ubicación mediante la interfaz visual de Mapas de Bing

Para comenzar a usar el control de ubicación de Bing, solo tiene que obtener una clave de API de Mapas de Bing y un componente LocationDialog para un proyecto .NET (a través de NuGet) o Node.js (a través de npm) y, a continuación, inicializar y llamar a una instancia del cuadro de diálogo Ubicación en su código:

var options = LocationOptions.UseNativeControl | LocationOptions.ReverseGeocode;
var requiredFields = LocationRequiredFields.Locality |
                     LocationRequiredFields.Region |
                     LocationRequiredFields.Country;
var prompt = "Where are you looking for trails?";
var locationDialog = new LocationDialog(
  apiKey, this.channelId, prompt, options, requiredFields);
context.Call(locationDialog, this.ResumeAfterLocationDialogAsync);

LocationDialog proporciona opciones para solicitar distintos campos de dirección y personalizar avisos. Cuando se devuelva el resultado, puede controlarlo en un método Resume, como se muestra en la Figura 10.

Figura 10 Control de los resultados de ubicación en un método Resume

private async Task ResumeAfterLocationDialogAsync(
  IDialogContext context, IAwaitable<Place> result)
  {
    var place = await result;
    if (place != null)
    {
      var address = place.GetPostalAddress();
      var formattedAddress = string.Join(", ", new[]
      {
         address.Locality,
         address.Region,
         address.Country
      }.Where(x => !string.IsNullOrEmpty(x)));
      await context.PostAsync(
        "Where are you looking for trails " + formattedAddress);
    }
    context.Done<string>(null);
  }

Más allá de LUIS

Además de LUIS, Cognitive Services proporciona varias API que pueden dotar a sus bots de conocimientos que pueden parecer incomprensiblemente complejas para que un desarrollador individual o una empresa puedan implementarlos. Afortunadamente, no tiene que hacerlo usted mismo:

  • Recommendations API permite incluir recomendaciones sobre productos (como aquellos que se suelen comprar juntos) o recomendaciones personalizadas para los usuarios.
  • Vision API agrega capacidades de imagen y vídeo a los bots para el reconocimiento de objetos, caras de personas, la edad, el género e incluso los sentimientos.
  • Academic Knowledge API puede agregar conocimientos académicos, crear preguntas y respuestas, e incorporar capacidades de base de conocimiento específicas al bot.

Vale la pena mencionar que los bots también están abiertos a las API y los servicios de terceros. Puede usar servicios y API propios para hacer que sus bots sean únicos y resolver problemas que no se hayan solucionado anteriormente. De hecho, Bot Framework proporciona un nuevo mundo de oportunidades, además de la evolución del conocimiento humano y la accesibilidad a este, por medio de interfaces de conversación simples y API fáciles de usar.

Nuevo y emocionante

Además de las actualizaciones regulares para Bot Framework de .NET Framework y Node.js, y las API de REST, Microsoft agregó recientemente características que llevan el desarrollo de bots a un nuevo nivel.

Una de las últimas incorporaciones a Bot Framework, Azure Bot Service, ofrece ahora un sencillo método para aprovechar la conveniencia y la escalabilidad de la nube para sus proyectos de bots (bit.ly/2knEtU6). Bot Service, que se muestra en la Figura 11, usa Azure Functions y una colección de plantillas de inicio rápido para ayudarle a aprovechar al máximo el código de los bots y permitirle escalarlos a cualquier nivel (bit.ly/2kuo9Bb). Por ejemplo, puede elegir entre las plantillas de bots Basic, Form, Proactive, LUIS o Question and Answer, cada una de las cuales proporciona un bot listo para ejecutar que puede ampliar según sea necesario.

Edición del código de Bot Service directamente en el explorador
Figura 11 Edición del código de Bot Service directamente en el explorador

Azure Functions es la tecnología que está detrás de Azure Bot Service, y proporciona experiencias controladas por eventos basadas en la arquitectura sin servidor y el proceso a petición. Lo que esto significa realmente es que ya no necesita una costosa infraestructura de hospedaje de aplicaciones para cada bot. En su lugar, puede crear bots mucho más ligeros, escalarlos más fácilmente y ahorrar tiempo y esfuerzo en desarrollo, todo ello gracias a la simplicidad de la conectividad que ofrece Cognitive Services.

QnA Maker (qnamaker.ai) es otra incorporación que vale la pena mencionar. Disponible en Azure Bot Service como un proyecto de bot de plantilla, QnA Maker ocupa un escenario muy común de los bots, que responde a preguntas típicas de una base de conocimiento existente.

Resumen

Microsoft Bot Framework ofrece una manera rápida y sencilla de comenzar a compilar bots, que proporciona una interfaz de conversación para aplicaciones o servicios nuevos y existentes. Permite crear nuevas experiencias y llegar a miles de millones de usuarios conectados a través de Skype, Facebook Messenger, Telegram y otros canales. Microsoft Cognitive Services incluye muchas API inteligentes que puede agregar al bot.

El ecosistema de Bot Framework está creciendo rápidamente. Para aprovecharlo, puede agregar los servicios que se incluyen en Cognitive Services o usar las API de proveedores de terceros para mejorar la inteligencia y la capacidad de los bots. El viaje que comienza con un bot muy simple puede conducir a muchos descubrimientos para usted y para sus usuarios. Los bots son en realidad las nuevas aplicaciones (o extensiones de aplicaciones existentes) y, gracias a su inteligencia superior, resultan realmente eficaces. Además, reducen el tiempo, el esfuerzo y el costo de desarrollo.

Conozca mis bots

He desarrollado bastantes bots durante los últimos meses, así que he decidido compartirlos con usted desde una práctica ubicación, que se indica en la Figura A. Écheles un vistazo y, si le sirven de inspiración, cree los suyos propios. (El vínculo que se proporciona en cada caso, agrega el bot a Skype).

Figura A Mi colección de bots

Bot  Descripción
Solitario (bit.ly/2jrzP7S) El Solitario se considera el juego de cartas más popular del mundo. Ahora, en lugar de iniciar una aplicación, puede usar su cliente de chat favorito, como Skype, para disfrutar del juego.
Active Fitness (bit.ly/2knZVbr) Busque rutas por todo el mundo: para correr, ir en bicicleta, pasear o esquiar, todo desde la red social de fitness más importante del mundo.
UNO (bit.ly/2k4AzyH) Juegue a este juego de cartas famoso en todo el mundo en Skype, Messenger o Telegram.
Freecell (bit.ly/2l0NM9b) Freecell es un excelente y desafiante juego de cartas con varios niveles de dificultad. Comience por los niveles básicos y aprenda a jugar.
Crazy Eights (bit.ly/2kY7EdN) Descubra este juego de cartas fácil de aprender.
Card Games Chest (bit.ly/2klXOCV) Aprenda a dominar algunos de los juegos de cartas más populares, como Solitario, UNO, Crazy Eights, 101, Freecell y Mau-Mau.

Kevin Ashley (@kashleytwit) es un arquitecto evangelizador de Microsoft. Es coautor de "Professional Windows 8 Programming" (Wrox, 2012) y programador de importantes aplicaciones y juegos, la más conocida Active Fitness (activefitness.co). A menudo presenta tecnología en diversos eventos, exhibiciones industriales y difusiones por web. Trabaja con empresas nuevas y socios, brindando asesoramiento sobre diseño de software, estrategia comercial y tecnológica, arquitectura y desarrollo. Siga su blog en kevinashley.com y su cuenta de Twitter en @kashleytwit.

Gracias al siguiente experto técnico de Microsoft por revisar este artículo: Mat Velloso