tag:blogger.com,1999:blog-89442566524335336472024-02-06T20:46:10.456-08:00C#er : IMagePrincipal architect Jeremy Likness at @ivisionatl covers the latest news and discussions about #JavaScript, #AngularJS, #Azure, #NodeJS, #Bootstrap, #Windows81 and more.Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comBlogger424125tag:blogger.com,1999:blog-8944256652433533647.post-17448957143389076862017-08-20T07:38:00.000-07:002017-08-20T07:38:09.314-07:00My Blog has a New Home!<p>
Yes! That's right. For more reasons than I can list here, I've packed up and moved on to a new blog. It's really easy to remember: <a href="https://blog.jeremylikness.com/">https://blog.jeremylikness.com/</a>.
<p>
There are a lot of reasons I moved, and I shared them all in <a href="https://blog.jeremylikness.com/reflecting-on-15-years-of-blogging-dc008ee71053">this blog post</a>.
<p>This site will remain online as an archive of older articles. If you would like to see an article migrated to the new site, use the contact form to contact me!
<p>Thanks,
<p>
<a href="http://jeremylikness.com/" title="Jeremy Likness"><img border="0" src="http://jeremylikness.com/signature.gif" alt="Jeremy Likness" title="Jeremy Likness"/></a><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-86112271184050049632017-08-15T05:19:00.000-07:002017-08-15T05:26:33.004-07:00Herding Cattle with the Azure Container Service (ACS)<p>Docker is an amazing tool that transforms how DevOps teams build software at scale. Containers can’t be treated like pets for Docker to effectively meet enterprise demands. The care, attention, and feeding simply doesn’t make sense when dealing with hundreds or even thousands of interconnected microservices. The herd of containers needs to be wrangled, or orchestrated, by a tool. </p><p><a href="https://www.slideshare.net/jeremylikness/herding-cattle-with-azure-container-service-acs" target="_blank"><img width="640" height="284" title="herding" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="herding" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGH7oioYhzF-JERQhYgnw7h8h4vw9Mcj4_ePah6wiU-fkw3MG4RBuffEqbCDdcaqzfiL51HA-Llxq1RBuZBhX6W_mx65IDYnzKW4_FZTBc1BpKNJScLBSrIzMjlO6s9R3OEu2C5zwUld23/?imgmax=800" border="0"></a></p><p>Although several tools exist, <a href="https://docs.microsoft.com/azure/container-service/" target="_blank">Azure Container Service</a> provides a single interface to set up complex orchestration clusters regardless of whether you prefer Mesos DC/OS, Docker Swarm, or Kubernetes. I recently <a href="https://www.meetup.com/Docker-Atlanta/events/241833081/" target="_blank">presented this talk</a> at the <a href="https://www.meetup.com/Docker-Atlanta/" target="_blank">Docker Atlanta Meetup</a> group. I covered what ACS is, walked through creating clusters for DCOS, Swarm, and Kubernetes, and demonstrated deploying Docker containers and scaling them out.</p><p>View the deck below, and check out the accompanying <a href="https://www.youtube.com/watch?v=POZYM_S8uzg" target="_blank">walkthrough video</a>.</p><p><iframe width="595" height="485" src="//www.slideshare.net/slideshow/embed_code/key/LJVlqF9Jb8rk9O" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" allowfullscreen="" style="border: 1px solid rgb(204, 204, 204); border-image: none; margin-bottom: 5px; max-width: 100%;"> </iframe> <div style="margin-bottom: 5px;"> <strong> <a title="Herding Cattle with Azure Container Service (ACS)" href="//www.slideshare.net/jeremylikness/herding-cattle-with-azure-container-service-acs" target="_blank">Herding Cattle with Azure Container Service (ACS)</a> </strong> from <strong><a href="https://www.slideshare.net/jeremylikness" target="_blank">Jeremy Likness</a></strong> </div><p>To learn more about Azure Container Service, read the <a href="https://docs.microsoft.com/azure/container-service/" target="_blank">official documentation</a>.</p><p>Are you running containers in production? I’d love to hear about your experience and tips in the comments below! </p><p>Regards,</p><p><img style="border: 0px currentcolor; border-image: none; background-image: none;" src="http://jeremylikness.com/signature.gif" border="0"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-10260748731897640672017-08-11T10:57:00.000-07:002017-08-11T11:08:09.138-07:00Docker Containers at Scale with Azure Web App on Linux<p>The Azure team recently announced a new feature that is currently in preview called <a href="https://docs.microsoft.com/azure/app-service-web/app-service-linux-intro" target="_blank">Azure Web App on Linux</a>. This feature enables you to host web apps natively on Linux. The service enables you to choose an initial size and number of instances for your hosts, then manually scale up and out or add automatic rules to respond to load. </p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitlRus2eUL-0ZQ440uzvtgCQ0NtwGmfBv3rk8Xt_kRJUGUDojc0-C936pbjy0_I9EpW5eoYkfITIYIBVZgDMNd8r-AEQYvYgJPckyQ2my9IHL9OaSk8HUwJLjkynvTi9uJoKvKiT3bQ5-M/s1600-h/azurecontainerwebapp%255B4%255D"><img width="650" height="513" title="azurecontainerwebapp" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="azurecontainerwebapp" src="https://lh3.googleusercontent.com/-t_suv-9Efp8/WY3vTnUTV7I/AAAAAAAAJQI/pabyvTATKQo0787yCJSJIewNL2skQ5pxQCHMYCw/azurecontainerwebapp_thumb%255B2%255D?imgmax=800" border="0"></a></p><p>It comes out of the box with support for several application stacks including <a href="https://docs.microsoft.com/azure/app-service-web/app-service-linux-using-nodejs-pm2" target="_blank">Node.js</a>, PHP, <a href="https://docs.microsoft.com/azure/app-service-web/app-service-linux-using-dotnetcore" target="_blank">.NET Core</a>, and <a href="https://docs.microsoft.com/azure/app-service-web/app-service-linux-ruby-get-started" target="_blank">Ruby</a>. </p><blockquote><p>Pssst. Lean a little closer. I have a little secret for you: it’s all based on <a href="https://docs.microsoft.com/azure/app-service-web/app-service-linux-using-custom-docker-image" target="_blank">Docker</a> containers.</p></blockquote><p>That’s right! What that means is even if your platform and language of choice aren’t listed in the “supported stacks,” you can publish anything you can containerize. To prove it, I’ve made a short five minute video. I demonstrate taking my <a href="https://github.com/JeremyLikness/docker-we-rise/tree/master/03-Hello-Small-Go-Small" target="_blank">little go app</a> that is available as a public <a href="https://hub.docker.com/r/jlikness/gosmall/" target="_blank">Docker Hub image</a> and deploying it to Azure, then scaling it out. Check it out: </p><p><iframe width="560" height="315" src="https://www.youtube.com/embed/nWfpwgHRfqk" frameborder="0" allowfullscreen=""></iframe></p><p>If you’re thinking, “Not another orchestrator” … think again. The goal is not to compete with mature orchestrators like <a href="https://docs.microsoft.com/azure/container-service/kubernetes/container-service-kubernetes-walkthrough" target="_blank">Kubernetes</a>. Instead, the web app provides a ton of features that make your life easier and streamline the DevOps experience, such as:</p><ul><li><a href="https://github.com/projectkudu/kudu" target="_blank">Kudu</a>, the deployment engine that will manage deployments for you from sources ranging from GitHub and Visual Studio Team Services to local git repositories</li><li>Shared storage to aggregate log files </li><li>SSH access to your containers </li><li>Auto-scaling </li></ul><p>You can even set up separate instances in different regions around the globe and load balance them using Azure’s <a href="https://docs.microsoft.com/azure/traffic-manager/traffic-manager-overview" target="_blank">Traffic Manager</a>. There are many more features to review that you can learn more about by reading the <a href="https://docs.microsoft.com/azure/app-service-web/app-service-linux-using-custom-docker-image" target="_blank">Azure Web App on Linux</a> documentation. If you have questions, comments, feedback, or corrections, don’t forget that the documentation is <em>open source</em> and <em>accepting pull requests!</em> </p><p>Thanks, </p><p><img style="border: 0px currentcolor; border-image: none; background-image: none;" src="http://jeremylikness.com/signature.gif" border="0"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-55096164454500710472017-07-21T12:54:00.000-07:002017-08-10T07:50:15.215-07:00Build and Deploy a .NET Core Web App from Linux to a Linux Web App Service on Azure<p>… and do it in less than ten minutes!</p><p><a href="https://lh3.googleusercontent.com/-ZHXteHa5HqQ/WXJb_A3yplI/AAAAAAAAImU/pz5H_Is7DOE1xf-nSGZteyF-m-r-iGyDQCHMYCw/s1600-h/netcorethumb%255B4%255D"><img width="650" height="366" title="netcorethumb" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="netcorethumb" src="https://lh3.googleusercontent.com/-_lyrVSYtuKg/WXJb_kErIgI/AAAAAAAAImY/r1sPdNE9KpMdWcVAFGtl92DmrbqiZloBwCHMYCw/netcorethumb_thumb%255B2%255D?imgmax=800" border="0"></a></p><p>I love <a href="https://docs.microsoft.com/aspnet/core/" target="_blank">.NET Core</a>. It allows me to apply the C# skills I’ve been using for over a decade now (combined with my experience with the .NET Framework and its myriad APIs) to cross-platform development. I can create lightweight, portable apps and websites and containerize them, run them on the familiar Windows-based IIS server or deploy them as scalable <a href="https://docs.microsoft.com/azure/app-service/" target="_blank">Azure App Service</a> endpoints. </p><p>Tools like <a href="https://code.visualstudio.com/" target="_blank">Visual Studio Code</a> and the <a href="https://docs.microsoft.com/cli/azure/install-azure-cli" target="_blank">Azure Command Line Interface (CLI)</a> make it possible to leverage a consistent experience regardless of the platform I’m developing on. Although I carry a Windows 10 Surface Book laptop around, I’m just as comfortable dropping to bash on Ubuntu to build an app in Linux. </p><p>This short video demonstrates just how straightforward it is to build and deploy a .NET Core app from Linux to an <a href="https://docs.microsoft.com/azure/app-service-web/app-service-linux-intro" target="_blank">Azure Web App on Linux</a>. </p><p><iframe width="650" height="460" src="https://www.youtube.com/embed/hqINEszeHg4" frameborder="0" allowfullscreen></iframe></p><p>There are three main steps: </p><ul><li>Build the app </li><li>Create and configure the App Service </li><li>Deploy the App Service</li></ul><p>To build the app, create the directory and use the .NET Core tool: </p><p><font face="Consolas">mkdir mymvc<br>cd mymvc<br>dotnet new mvc<br>dotnet restore<br>dotnet run</font><p>Next, create a resource group, an app service plan, and a web app. Configure the web app to run the correct Linux version and launch your app, and set it up for git-based deployment. You can capture the endpoint to deploy to in the same step. You may need to pick your own unique app name.<p><font face="Consolas">az group create -n my-linux-group -l westus<br></font><font face="Consolas"><br>
az appservice plan create -g my-linux-group -n my-linux-plan --is-linux -l westus<br><br>
az webapp create -n my-linux-app -p my-linux-plan -g my-linux-group<br><br>
az webapp config set -n my-linux-app -g my-linux-group --linux-fx-version "DOTNETCORE|1.1.0" --startup-file "dotnet mymvc.dll"<br><br>
url=$(az webapp deployment source config-local-git --name my-linux-app \<br>
--resource-group my-linux-group --query url --output tsv)<br><br>
echo $url</font><br></p>
<p>Finally, you need a way to deploy your files. There are several ways, but local git is a great option. You can publish your files and initalize the git repository, and then subsequent updates will only deploy the changes (you publish, then commit the changes and push). These steps initialize the repository and connect it to the remote endpoint and push the deployment files: <p><font face="Consolas">dotnet publish -c Release<br><br>
cd bin/Release/netcoreapp1.1/publish <br><br>
git init <br><br>
git add -A <br><br>
git commit -m "Initial Deployment"<br><br>
git remote add azure $url<br><br>
git push azure master</font></p><p>At this stage, you should have a Linux app up and running! Learn more by exploring the <a href="https://docs.microsoft.com/azure/app-service-web/app-service-web-overview" target="_blank">Web Apps overview</a>.<p><img style="border: 0px currentcolor; border-image: none; background-image: none;" src="http://jeremylikness.com/signature.gif" border="0"><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-14599958397672188022017-07-14T09:30:00.002-07:002017-07-14T09:33:30.735-07:00Cluster Management and Orchestration of Docker Containers at Scale with Azure Container Service<p>I recently recorded a <a href="https://cloudacademy.com/azure/introduction-to-azure-container-service-acs-course/" target="_blank">course</a> for <a href="https://www.cloudacademy.com/" target="_blank">Cloud Academy</a> to introduce the <a href="https://azure.microsoft.com/en-us/services/container-service/" target="_blank">Azure Container Service</a>. Containers have already transformed the way developers approach enterprise applications and are rapidly gaining momentum in production. To manage containers at scale requires an orchestrator, or a platform to manage the deployment, scaling, and resiliency of containers across clustered hosts. The Azure Container Service simplifies standing up and managing your orchestrator of choice in the Azure cloud.</p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXZIOgocjc1zBdjtNh6njNQQq11pJ0zdSilLlkrceG_zVFP7jXp6qkZj8LOkuPqxpti0xhHQM3M9JN8RxjzISfTWjtUNvBxYheY20Fo2e6fgYcjp8_QZsUlZtCjyQ_SsSb25vnVEwziBTV/s1600-h/cloudacademy%255B4%255D"><img width="650" height="362" title="cloudacademy" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="cloudacademy" src="https://lh3.googleusercontent.com/-IjOMr0IL7tU/WV-TtWRKJ9I/AAAAAAAAIXU/5PO5obyCW2Ua7Tqc8cItelS3fVguh2GrgCHMYCw/cloudacademy_thumb%255B2%255D?imgmax=800" border="0"></a></p><p>The video starts with an introduction and overview of containers and orchestrators, demonstrates how to set up a new environment using the Azure portal, then dives into creating everything you need to stand up the cluster, private networks, load balancers and other assets for each orchestrator using the <a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli" target="_blank">Azure Command Line Interface (CLI)</a>. In most cases you can stand up the assets needed, including <a href="https://azure.microsoft.com/en-us/services/virtual-machine-scale-sets/" target="_blank">virtual machine scale sets</a>, master nodes and private agents, with just two commands.</p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwHRXF77kmshvk1-urt4G0VkvyjmT7Zm-Yx2L9VoXWrEpDlAS8VgZL9DZh1U-LkK2UrBWKVbnwws2tLPBXQeh1nw-7QmSmoirP4Ss15Cl9KZgqZjZZQXydw3Z9bKtH-rGQ53Sh8XdkGW7H/s1600-h/intro%255B4%255D"><img width="650" height="366" title="intro" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="intro" src="https://lh3.googleusercontent.com/-cwwTOJDMqh8/WV-Tt15icZI/AAAAAAAAIXc/JuJv8_iBNgUrGHcPeo040mVJ9NA46sWKACHMYCw/intro_thumb%255B2%255D?imgmax=800" border="0"></a></p><p>In addition to SSH key generation, I walk through standing up each orchestrator, deploying a container, and scaling it out to multiple instances. </p><p>The orchestrators covered include:</p><ul><li><a href="https://kubernetes.io/" target="_blank">Kubernetes</a></li><li><a href="https://dcos.io/" target="_blank">DC/OS</a> with <a href="https://mesosphere.github.io/marathon/" target="_blank">Marathon</a></li><li><a href="https://docs.docker.com/swarm/" target="_blank">Docker Swarm</a></li></ul><p>Cloud Academy provides several subscription options and contains hours and hours of cloud-related content. You can access the course here: <a href="https://cloudacademy.com/azure/introduction-to-azure-container-service-acs-course/" target="_blank">Introduction to the Azure Container Service</a>. Check it out and let me know your thoughts! </p><p><img style="border: 0px currentcolor; border-image: none; background-image: none;" src="http://jeremylikness.com/signature.gif" border="0"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-52214730215461747722017-06-30T10:28:00.000-07:002017-06-30T10:28:09.430-07:00Create a Developer Build Workflow with Docker and Multi-Stage Builds<p>I meet with my application development team every week to review how everyone is doing, go through active projects, discuss revenue and track the sales pipeline. To facilitate the meeting, I wrote an <a href="https://angular.io/" target="_blank">Angular 2</a> application that interfaces with exported files and APIs to pull together the information in a central, cohesive format. Angular is changing rapidly and sometimes that can create conflicts. </p><p>The <a href="https://nodejs.org/en/" target="_blank">Node.js</a> package manager <a href="https://www.npmjs.com/" target="_blank">npm</a> uses <a href="https://github.com/npm/node-semver" target="_blank">semantic versioning</a>. This means some packages might specify a range or “greater than a version.” If someone pulls down the package after the dependent packages have been updated, different users may end up with different builds on their machines. I recently ran into this trying to get the application development project to build for a team member who is taking it over. We tried installing dependent packages, re-installing Node, updating npm, and several other options but the behavior on their machine just wasn’t the same as the behavior on mine.</p><p>That’s when it clicked. What is one of the main advantages of the Docker that I discuss when I <a href="http://csharperimage.jeremylikness.com/p/presentations.html">present at conferences</a>? The fact that “it works on my machine” is no longer a valid excuse. Instead, we use: </p><blockquote><p>“It works on Docker.” </p></blockquote><p>If you can get your container to run in Docker, it stands to reason it should run consistently on <em>any</em> Docker host.</p><p>The recent Docker release supports a concept called <a href="https://docs.docker.com/engine/userguide/eng-image/multistage-build/" target="_blank">multi-stage builds</a>. This allows you to create interim containers to perform work, then use output from those containers to build other images. This is perfect for building the sync project (and in the future means developers won’t even need Node on their machine to build it, although who doesn’t want Node?) </p><p>First, I created a <font face="Consolas">.dockerignore</font> file. I don’t use end-to-end testing and the build machine will install its own dependencies, so I ignored both of those folders.</p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-fuixBgJ43rI5S1EM_F1Xm4NVPyfhdEMNKofcOk4TqB8ZGywLxe236_Vx-lmYI9yM4el4t53OpMDsAOrxQMFFU3tnmdRUu39yNGEwlQNzDks5h-1rBk21b9Z-EepyKvnN225RL-o8vKo2/s1600-h/dockerignore%255B4%255D"><img width="483" height="242" title="dockerignore" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="dockerignore" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiG0kYwxCCFh_44uFZPWPTmYG2MDyR5NugzG4kvlILfR2Ebm3ldDOMOuIdijiJtdlf5CuxUcTrmAdq1mGHh6o-vswQAneuao2H1Ctzb4rcp15y0vHyQUbDoVtZu8EFK-BMpjABEFLWoBme/?imgmax=800" border="0"></a></p><p>Next, I got to work on the <font face="Consolas">Dockerfile</font>. </p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcQan3-GBU934PFd8zBuonlEQUABtlFiShNpgzO4Hc9DNO6C0uNNFhut3yIhIWjDCW7_4YorqTOOPh1EvStRbuZPA3r49YUtHYyvT0BgHgalt3zT99lXjZ1Gx29CrjQ-9pfAzqWgJeKDGP/s1600-h/dockerfile%255B4%255D"><img width="650" height="313" title="dockerfile" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="dockerfile" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8W5qFKvwNh6iTU7hiOp4SzBH5m8Mu497pmU5Rt7_Lv_mlafLauaEo0tCnRmvWUU2_-sfsIiCU0YjFDgOFhLSRi2U3yATAhm1j3d6e4iqW7JpOPZ59zZbUwFQGdgzCfsRngiNvIZlNqbjO/?imgmax=800" border="0"></a></p><p>The <a href="https://cli.angular.io/" target="_blank">Angular Command Line Interface (CLI)</a> uses Node, so it made sense to start with a <a href="https://hub.docker.com/_/node/" target="_blank">Node image</a>. I am giving this container the alias <em>build</em> so I can reference it later. On the image, I install the specific version of the CLI I am using. Then I create a directory, copy the Angular source to that directory, install dependencies and build for production. This creates a folder named <font face="Consolas">dist</font> on the container with the assets I need to run my application.</p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQinU1MS6pr9St9ctDfvKwrXQ1NaFD292iSFVORe1tpPHyUV604TlIXI-1xd14DvPddLZnLQBfKu7JAocB9C_0f-lmcpexGGjHZ0xjlRgzvqtGDDIv4fs9Ket38fq8CuMMMOLxtjOzItOq/s1600-h/dist%255B9%255D"><img width="534" height="442" title="dist" style="border-image: none; display: inline; background-image: none;" alt="dist" src="https://lh3.googleusercontent.com/-adyfGjiPkeE/WVaIR4DbAxI/AAAAAAAAINk/sKFxkSNVKkUF7_VYWPPuVhcUXRawDrqngCHMYCw/dist_thumb%255B7%255D?imgmax=800" border="0"></a></p><p>Next, in the same <font face="Consolas">Dockerfile</font> I continue with my target image. The app is run locally for the team so I don’t need massive scale, therefore I started with the simple and extremely small <a href="https://hub.docker.com/_/busybox/" target="_blank">busybox</a> image. </p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwDiHUNLwb1t9JSe2z6bPI9RvPQq3Sos-q1wgLNfq676yochEt7JXF9ezJNsQdN_ThaQxKoxEmE3GJSZY7eHp2RIMyiaGbux5EVgH6jUQ9IJP-BP8snCJ1MjoxY2ZoKruK_MC42zDlYtJ-/s1600-h/busybox%255B4%255D"><img width="650" height="239" title="busybox" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="busybox" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpdYXOTCrnKdqooRgJiST6tql044OuU4YrzWpQDENiNbeL3afLW9Olcc7LJ-VbSF_kvzs2JzMB6XQI8Y86M4ZjjZhMgdeeM8YSajdb7VDeFWDxXfHWjicWn4ljIf8-9_HFEeIy4euqOiq_/?imgmax=800" border="0"></a></p><p>I create a directory for the web, then copy the assets from the previous image (remember, I gave it the alias <em>build</em>) into the new directory. I expose the HTTP port and instruct the container to run the http daemon in the foreground (so the container keeps running) on port 80 with a home directory of <font face="Consolas">www</font>.</p><p>Next is a simple command I run from the root of the project to build the image:</p><p><font face="Consolas">docker build -t ng2appdev .</font></p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9n8mmq1dGb-oPRkyG9-rMxqD5Jl8GFe87cXDWIOXqYVrXB_Kz-wLPlxShOu9pdUXF2i0TVMhAH6ToZ_eY0x0J7WES2Pc7SzmvIey5XPzZt-1fVekX7LKsquplV1vkexM0LnXpqVl98nbR/s1600-h/docker-build%255B4%255D"><img width="650" height="410" title="docker-build" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="docker-build" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBGBPuZizaLj-vvlhUGQf_eSPoQXAqD2M3Ht_R7OhEMpNB_cU3zBJc6qtxw9Oe-ZuynfJWxgbyrI0kK53VoxXi023ZFVxAfc7pgpwSV1vo_0mdhMC1sWyX-Ua4ZPZnP_S06_YLu4O82Etn/?imgmax=800" border="0"></a></p><p>The first time takes a bit of time as it pulls the images and preps them, but eventually it successfully builds and generates an image that has everything needed to run the app. I can launch it like this:</p><p><font face="Consolas">docker run -d -p 80:80 ng2appdev</font></p><p>That instructs Docker to run the image I just created in “detached” mode (in the background) and expose port 80. Then I browse to localhost and the app is there, ready and waiting! The image doesn’t take up too much space, either, so it’s easy to pass around:</p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyrKBMP83mDmld80SF20unO0JNQme-ZR0OfHY_RkOUOcOirdKUknlTa_F9TVmo3OJ5CfHssSFj2f0YfDcsf7tqBa_kGaSKSuklF_Y-qz9SfMxh70nzrlCk6FSvRMGEvRYK1_xRmFr5dwQ5/s1600-h/image-size%255B4%255D"><img width="650" height="80" title="image-size" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image-size" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJZ26VLDI37stIIiri50Ebbmd9sapAIVW3aldyZs_2EtDJrrVHjJHYv1tv3XH8vNiJU_W-xoOK0MegT8N3rYdjt5iX5xIGPPFV6RzzudMpdGs-dTfsHxLhwoFshGdUoihf3EH17GNbLdYs/?imgmax=800" border="0"></a></p><p>In fact, why even make anyone bother with the build? To improve the process we can do two things:</p><p>1. Create an image called <font face="Consolas">ng2appdevbuilder</font> that has the CLI installed. That way we don’t have to reinstall it every time or worry about it becoming deprecated in the future. It encapsulates a stable, consistent build environment.</p><p>2. On a build machine, automate it to pull down the latest application source code and assets, use the build image to build the app, then publish the result. Trigger this each time the source code is changed.</p><p>Now anyone who wants to run the latest can simply pull the most recent image and go for it. That’s the power of Docker!</p><p><img style="border: 0px currentcolor; border-image: none; background-image: none;" src="http://jeremylikness.com/signature.gif" border="0"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-87101197592434249402017-06-10T09:05:00.000-07:002017-06-10T09:06:26.496-07:00Stuffing Angular into a Tiny Docker Container (< 2 MB)<p>I’ve been doing a lot of work with <a href="https://angular.io/" target="_blank">Angular</a> and <a href="https://www.docker.com/" target="_blank">Docker</a> lately. In one of my workshops I demonstrate how to take an Angular app and related services then package them as containers and leverage <a href="https://docs.docker.com/compose/">Docker Compose</a> to spin them up with a single command. You can read about a more involved example at <a href="http://csharperimage.jeremylikness.com/2017/04/build-and-deploy-mongodb-angular-nodejs.html">Build and Deploy a MongoDB Angular NodeJS App using nginx in Three Steps with Docker</a>.</p><p>Using the <a href="https://hub.docker.com/_/nginx/" target="_blank">nginx</a> container, my Angular images average several hundred megabytes in size (click to view full size).</p><p><a href="https://lh3.googleusercontent.com/-lO41v8AeUt8/WTwXoShYKCI/AAAAAAAAH8Q/Qj479aZVA74DvrRiBhZ0Uoxop8jqiE0TgCHM/s1600-h/bigimages%255B7%255D"><img width="644" height="58" title="bigimages" style="display: inline; background-image: none;" alt="bigimages" src="https://lh3.googleusercontent.com/-aRYQGGa9R8I/WTwXo9ot3CI/AAAAAAAAH8U/mzKVsggAh5YEQkPOJ8UWnu45eQVc3MO-wCHM/bigimages_thumb%255B5%255D?imgmax=800" border="0"></a></p><p>Microservices have transformed the way modern apps are architected. For example, Angular can produce a highly optimized production distribution of its assets as static files. The website for Angular can be incredibly simple because it relies on separate services and APIs to do the heavy lifting, and any browser-based logic is encapsulated in the JavaScript libraries that are included. </p><p>Therefore, standing up the front end should be a lot easier! In fact, even with a minimal web server, containers are easy to spin up and scale out, so load doesn’t necessarily have to be a concern of the web server now when it can be managed by the orchestrator. As an experiment, I set out to see how small I can make an Angular app. </p><p>If you have Docker installed, you can run the tiny Angular app yourself. Instructions are available at <a href="https://hub.docker.com/r/jlikness/tinyng/" target="_blank">this link</a>. </p><p>In searching for a solution I came across <a href="https://hub.docker.com/r/library/busybox/" target="_blank">BusyBox</a>, a set of Unix commands in an extremely small container that is around a megabyte in size. BusyBox contains <a href="https://wiki.openwrt.org/doc/howto/http.httpd" target="_blank">httpd</a>, an HTTP daemon. Let’s see how small we can make our Angular app! </p><p>The app we’ll target is the simple Angular app I built for <a href="https://www.musiccitycode.com/" target="_blank">Music City Code</a>. You can clone the repo from GitHub <a href="https://github.com/JeremyLikness/ng2-ts-music-city-code" target="_blank">here</a>. When you build the app, it creates a simple interactive fractal app using a bifurcation diagram. </p><p>Let’s build an optimized distribution of our Angular app. This generates about 400kb of assets.</p><p><a href="https://lh3.googleusercontent.com/-nY_eeRC-43E/WTwXpEW7kNI/AAAAAAAAH8Y/OkWbEq7qSIwAovxZI2C8mjsQ-sGTHsM9ACHM/s1600-h/ngbuild%255B3%255D"><img width="644" height="122" title="ngbuild" style="display: inline; background-image: none;" alt="ngbuild" src="https://lh3.googleusercontent.com/-bzul8HjKgYY/WTwXpkNlL0I/AAAAAAAAH8c/X96CryEo2qM1SVIE7d9pEcVO7V_XxTq1QCHM/ngbuild_thumb%255B1%255D?imgmax=800" border="0"></a></p><p>Next, create a <font face="Consolas">Dockerfile</font> with these contents:</p><p><font face="Consolas">from busybox:latest<br>
run mkdir /www <br>
copy /dist /www<br>
expose 80<br>
cmd ["httpd", "-f", "-p", "80", "-h", "/www"]</font></p><p>The steps are straightforward. It pulls down the latest busybox image, creates a directory, copies the Angular assets into the directory, exposes the web port and instructs the container to run the httpd daemon on startup. </p><p>Add a <font face="Consolas">.dockerignore</font> and ignore the <font face="Consolas">src</font>, <font face="Consolas">e2e</font>, and <font face="Consolas">node_modules</font> directories.</p><p>Let’s build our container: </p><p><a href="https://lh3.googleusercontent.com/-7k3jUO_08sY/WTwXp6xbg3I/AAAAAAAAH8g/XNLZvXHqi7kUktS823fuF_4anqjlYLJPQCHM/s1600-h/dockerbuild%255B3%255D"><img width="644" height="252" title="dockerbuild" style="display: inline; background-image: none;" alt="dockerbuild" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8cBrq7EQ_nDjExvOycubXdEtYdv7015CL6p3hXHieC8HRO8kDwkZKj_YR-E1OKw5pmikphUrOWZA4BkalM0CzITXcZzhbCE7nJUPBJacXSPE1IumCVsZUMcjCIWao5E2m3CVaJ7dBW4KF/?imgmax=800" border="0"></a></p><p>To see the image that was built, you can type:</p><p><font face="Consolas">docker images | grep "tinyng"</font><br>
</p><p>(Replace <font face="Consolas">grep</font> with <font face="Consolas">find</font> on Windows machines) and on my machine it is 1.57 MB.</p><p>Running it and browsing to localhost proves it is working:</p><p><font face="Consolas">docker run –d –p 80:80 jlikness/tinyng</font></p><p>So I push to Docker Hub, and confirm the size there:</p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTFMMo_XMpXhH0mvwkAGPUdsiM03QzekCpgazUlp3UCY-dE_ZQcKMb4wDbUWUxm6M7-g1EAmp5_QAwumKq9vERPmWqsO5mQPpHbSwTW5YdgvGeWUQvG5F4KCIYWoIW8bmalTkdJ96ouain/s1600-h/dockerhub%255B3%255D"><img width="644" height="241" title="dockerhub" style="display: inline; background-image: none;" alt="dockerhub" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhEFNe4BWwS-di_3_4bmMMRLdFVa08pd4wmccGOleq1r0h6lQMZ7Wvaj8fOkdDF75tki-4yzKgkdhXf7kfhenU_MkcHO2VdNYCH_JUnENOHlMzGvq-pqZlxU6cYgXbfHQJKwOIb4umxaBM/?imgmax=800" border="0"></a></p><p>The experiment is finished. Success! Of course now we have to try it under load and scale, but it’s good to know there is a path to optimize the size of your containers!</p><p><img style="border: 0px currentcolor; border-image: none; background-image: none;" src="http://jeremylikness.com/signature.gif" border="0"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-74421127682185579432017-06-07T05:34:00.000-07:002017-06-07T05:37:02.980-07:00Music City Code 2017<p>This was my first year to attend the <a href="https://www.musiccitycode.com/" target="_blank">Music City Code</a> conference in “the Music City” Nashville, Tennessee. It was held on the beautiful <a href="http://www.vanderbilt.edu/" target="_blank">Vanderbilt University</a> campus, where they advertise a 3-to-1 squirrel to student ratio. I imagine it was about 5-to-1 squirrels to conference attendees. </p> <p><a href="https://lh3.googleusercontent.com/-Wo3UvIkDL6Y/WTfvTsIgVAI/AAAAAAAAH1Y/yici3ufyw6sY6XsvlPsnVNm0gYSnDBcRQCHM/s1600-h/vanderbilt%255B4%255D"><img title="vanderbilt" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="vanderbilt" src="https://lh3.googleusercontent.com/-2mCbu_trGtU/WTfvT9RIjQI/AAAAAAAAH1c/4m4DFhUwgckfYvDK-mK_uTdF2NQ3eTLAACHM/vanderbilt_thumb%255B2%255D?imgmax=800" width="640" height="480"></a></p> <p>I presented two talks there, the last talk of the first day and the first talk of the last day. </p> <h2>Rapid Development with Angular and TypeScript</h2> <p>This is a talk focused on demonstrating just how powerful <a href="https://angular.io/" target="_blank">Angular</a>, <a href="http://www.typescriptlang.org/" target="_blank">TypeScript</a>, and the <a href="https://cli.angular.io/" target="_blank">Angular CLI</a> are to rapidly build apps. Don’t be scared by this 360 photo, if you can’t see the audience just scroll it around.</p> <p> <style type="text/css">.kuula7lpzw { width: 100%; height: 640px; }</style> <iframe class="kuula7lpzw" src="https://kuula.co/share/7lpzw?logo=0" frameborder="0" scrolling="no" allowfullscreen="true"></iframe></p> <p>The first half of the talk focused on the features Angular provides, as well as an overview of TypeScript. The second is a hands-on demo building an app using services, settings, rendering, data-binding, and a few other features.</p> <p>You can access the deck and source code <a href="https://github.com/JeremyLikness/ng2-ts-music-city-code" target="_blank">here</a>.</p> <h2>Contain Your Excitement</h2> <p>The next talk focused on containers. In true “<a href="http://www.imdb.com/title/tt1375666/" target="_blank">Inception</a>” style, the container talk itself can be run from a container. </p> <p> <style type="text/css">.kuula7lpb0 { width: 100%; height: 640px; }</style> <iframe class="kuula7lpb0" src="https://kuula.co/share/7lpB0?logo=0" frameborder="0" scrolling="no" allowfullscreen="true"></iframe></p> <p>The talk briefly covers the difference between “metal” in your data center and <a href="https://www.docker.com/" target="_blank">Docker</a> containers, then walks through building simple containers and evolves to multi-stage containers, using Docker compose, and an overview of orchestrators like <a href="https://www.docker.com/" target="_blank">Kubernetes</a>.</p> <p>As part of the talk, I took a 360 degree picture with my <a href="http://amzn.to/2sD1GTA" target="_blank">Samsung Gear 360</a> (I have the older model, there is a newer <a href="http://amzn.to/2sSD8VY" target="_blank">2017 version</a>). I updated the source with the embed link, then synced my changes to GitHub. This triggered an <a href="https://travis-ci.org/JeremyLikness/docker-contain-music-city" target="_blank">automated build</a> that prepared a Node.js environment, ran unit tests, then built and published the Docker image to demonstrate the continuous integration and deployment pipeline that is possible with containers.</p> <p>You can access the source code <a href="https://github.com/jeremylikness/docker-contain-music-city" target="_blank">here</a> and run the container from <a href="https://hub.docker.com/r/jlikness/docker-contain-mcc/" target="_blank">here</a>.</p> <h2>Parting Thoughts</h2> <p>As far as conferences go, this is one of my favorites. There were great people, terrific speakers, friendly and helpful volunteers, and a fun venue. The food was awesome and speakers were able to stay in the dormitories on campus which was a fun experience. I definitely look forward to coming back in future years!</p> <p><img style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; padding-right: 0px" border="0" src="http://jeremylikness.com/signature.gif"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-36078284639842975712017-04-07T12:16:00.000-07:002017-12-26T13:32:36.079-08:00Create a Serverless Angular App with Azure Functions and Blob Storage<h1>The article has moved. Click here for the latest: <a href="https://blog.jeremylikness.com/create-a-serverless-angular-app-with-azure-functions-and-blob-storage-20164c083c88">Create a Serverless Angujlar App with Azure Functions and Blob Storage</a>.</h1><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-92006981799031536992017-04-05T07:57:00.000-07:002018-01-05T03:47:02.844-08:00Celebrating Twenty Years of Open SourceThis article has been updated and moved to <a href="https://blog.jeremylikness.com/celebrating-twenty-years-of-open-source-d1fed4be6907" title="Celebrating 20 Years of Open Source">Celebrating 20 Years of Open Source</a>.<div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-28301634873304364862017-04-02T09:38:00.000-07:002017-04-02T09:39:51.790-07:00Build and Deploy a MongoDB Angular NodeJS App using nginx in Three Steps with Docker<p><a href="https://www.docker.com/" target="_blank">Docker</a> is a pretty amazing tool.</p> <p>To prove it, I want to show you how you can build, deploy, and stand-up an N-tier Angular app backed by MongoDB in just three steps. Literally. Without installing <em>any</em> prerequisites other than Docker itself. </p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_TJ4egEjFUkQC8PSokGFzFfqrLePY4rpBDB6iHHHFIFT71T9JmU6QR3aXI-7_2EcGi0o2TplBxRntsYply0KboKF1qQM1iED3aUmmfOZYf2qwAIrvjwAMHDBdayS4Z02BX1A-yV91Akdy/s1600-h/usdadiagram%25255B12%25255D.jpg"><img title="usdadiagram" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="usdadiagram" src="https://lh3.googleusercontent.com/-ESLcrePvkJc/WOEmwBwdgUI/AAAAAAAAGLg/XRJHHzTZiHY/usdadiagram_thumb%25255B8%25255D.jpg?imgmax=800" width="583" height="480"></a></p> <p>First, seeing is believing. Once you have Docker installed (OK, and <a href="https://git-scm.com/" target="_blank">git</a>, too), type the following commands:</p> <p><font face="Consolas">git clone https://github.com/JeremyLikness/usda-microservice.git</font></p> <p><font face="Consolas">cd usda-microservice</font></p> <p><font face="Consolas">docker-compose up</font></p> <p>It will take some time for everything to spin up, but once it does you should see several services start in the console. You’ll know the application is ready when you see it has imported the USDA database:</p> <p><a href="https://lh3.googleusercontent.com/-qYYdBlOwiAE/WOEmwjyMrnI/AAAAAAAAGLk/jL28NktoPtM/s1600-h/usdaimports%25255B4%25255D.jpg"><img title="usdaimports" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="usdaimports" src="https://lh3.googleusercontent.com/-6rye_jHsdSA/WOEmxL-Vx6I/AAAAAAAAGLo/2vDfnL1Tjlw/usdaimports_thumb%25255B2%25255D.jpg?imgmax=800" width="640" height="228"></a></p> <p>After the import you should be able to navigate to localhost and run the app. Here is an example of searching for the word “soy” and then tapping “info” on one of the results:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_Bt00GxS3z6nmLNkIjV8IA82-Vr3m0fyPZZU_8uw_P4lBRu4Y2RSwyjepijtNt76k-NZr5LaHgPDUF985-ai8_GaIJ_gMdbx93-OtzqmQv-5fiG3aOVQlovijD7cRiHpfRMTRaeXM6mSa/s1600-h/usdaweb%25255B4%25255D.jpg"><img title="usdaweb" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="usdaweb" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEje9q01wcOegnwfnv09ev9Gcd9nqgkCS1_FDzTc7jFk8PhKVWaQIPdlVVQWaKW-kxR_BxreieAtq1vjaa5A-45aHWvuldlBLnC-lyxpoBmUjAbBo2h4l34wmG8mz1mFySIrzgEcDWXDkDsp/?imgmax=800" width="640" height="356"></a></p> <p>On the console, you can see the queries in action: </p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiEZ29cTy1aYKrOlYN_zRH8mzTcOvlkhqyiE6bR6BqVGOBOS7sMpNJaqsI2-ALAeH27vHicsRAlVG5_PQ1O41qFCEb7BMtB31a2iNUiyFdQ2IrIzKccqo0Hl7RITnNLta1Ny0aEUaSniVW/s1600-h/usdasearch%25255B4%25255D.jpg"><img title="usdasearch" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="usdasearch" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjycrrIfLg43pImRszrd2u5Om-7bWnohNWJRqcURb8som13Mpecf7aVzTJBe3jcMC7OegUacP8ePLzNd43OON5VI6GPZYmYzFfc1-5Ix-B-73nVCNCyYNKzQE6GM9lKHw9W1EPlXulqklkz/?imgmax=800" width="640" height="360"></a></p> <p>How easy was that? </p> <p>Of course, you might find yourself asking, “What just happened?” To understand how the various steps were orchestrated, it all begins with the <a href="https://github.com/JeremyLikness/usda-microservice/blob/master/docker-compose.yml" target="_blank">docker-compose.yml</a> file.</p> <p>The file declares a set of <em>services </em>that work together to define the app. Services can depend on each other and often specify an <em>image</em> to use as a baseline for building a container, as well as a <em>Dockerfile</em> to describe how the container is built. Let’s take a look at what’s going on: </p> <p><strong>Seed</strong></p> <p>The <em>seed</em> service specifies a Dockerfile named <a href="https://github.com/JeremyLikness/usda-microservice/blob/master/Dockerfile-seed" target="_blank">Dockerfile-seed</a>. The entire purpose of this image is to import the USDA data from flat files along with some helper scripts, then expose the data through a volume so that they can be imported into the database. It is based on an existing lightweight Linux container called <a href="https://hub.docker.com/_/ubuntu/" target="_blank">Ubuntu</a>.</p> <p>Containers by default are black boxes. You cannot communicate with them and are unable to explore their contents. The <em>volume</em> command exposes a mounting point to share data. The file simply updates the container to the latest version, creates a directory, copies over a script and an archive, then unzips the archive and changes permissions.</p> <p><strong>db</strong></p> <p>The <em>db</em> service is the backend database. It inherits from the baseline <a href="https://hub.docker.com/_/mongo/" target="_blank">mongo</a> image that provides a pre-configured and ready-to-run instance of <a href="https://www.mongodb.com/" target="_blank">mongodb</a>. </p> <p>You’ll notice a command is specified to run the shell script <a href="https://github.com/JeremyLikness/usda-microservice/blob/master/seed.sh" target="_blank">seed.sh</a>. This is a bash script that does the following: </p> <ol> <li>Launch mongodb</li> <li>Wait until it is running</li> <li>Iterate through the food database files and import them into the database</li> <li>Swap to the foreground so it continues running and can be connected to</li></ol> <p>At this point, Docker created an interim container to stage data, then used that data to populate a mongo database that was created from the public, trusted registry and is now ready for connections and queries. </p> <p><strong>descriptions</strong></p> <p>The next container has a directory configured for the build (“./descriptions”), so you can view the <a href="https://github.com/JeremyLikness/usda-microservice/blob/master/descriptions/Dockerfile" target="_blank">Dockerfile</a> in that directory to discern its steps. This is an incredibly simple file. It leverages an image from <a href="https://hub.docker.com/_/node/" target="_blank">node</a> that contains a build trigger. This allows the image definition to specify how a derived image can be built. </p> <p>In this instance, the app is a Node app using <a href="https://www.npmjs.com/package/micro" target="_blank">micro</a>. The build steps simply copy the contents into the container, run an install to load dependent packages, then commit the image. This leaves you with a container that will run the microservice exposed on port 3000 using node.</p> <p>Going back to the compose file, there are two more lines called “links” and “ports” respectively. In this configuration, the mongodb container is not available outside of the host or even accessible from other containers. That is because no ports are exposed as part of its definition. </p> <p>The “link” directive allows the microservice to connect with the container running the database. This creates a secure, internal link – in other words, although the microservice can now see the database, the database is not available to any other containers that aren’t linked and not visible outside of the Docker host. </p> <p>On the other hand, because this service will be called from an Angular app hosted in a user’s web browser, it must be exposed outside of the host. The “port” directive maps the internal port 3000 to an external port 3000 so the microservice is accessible. </p> <p>This service exposes two functions: a list of all groups that the user can filter, and a list of descriptions of nutrients based on search text.</p> <p><strong>nutrients</strong></p> <p><em>Nutrients</em> is another microservice that is setup identical to <em>descriptions</em>. It exposes the individual nutrients for a description that was selected. The only difference in configuration is that because it runs on the same port (3000) internally, it is mapped to a new port (3001) externally to avoid a duplicate port conflict. </p> <p><strong>ngbuild</strong></p> <p>This image points to an Angular app and is used as an interim container to build the app (in production deployments it is more common to have a dedicated build box perform this step). I included this to demonstrate how powerful and flexible containers can be.</p> <p>Inside the <a href="https://github.com/JeremyLikness/usda-microservice/blob/master/usdaweb/Dockerfile" target="_blank">Dockerfile</a>, the script installs node and the node package manager, then the specific version of the <a href="https://cli.angular.io/" target="_blank">angular-cli</a> used to build the app. Once the Angular CLI is installed, a target directory is created. Dependent packages are installed using the node package manager, and the Angular CLI is called to build a production-ready image with ahead-of-time compilation of templates. This produces a highly optimized bundle. </p> <p>The compose file specifics a <em>volumes</em> directive that names “ng2”. This is a mount point to share storage between containers. The <em>ngbuild</em> service mounts “ng2” to “/src/dist” which is where the build is output.</p> <p><strong>web</strong></p> <p>Finally, the <em>web</em> service hosts the Angular app. There is no Dockerfile because it is completely based on an existing <a href="https://hub.docker.com/_/nginx/" target="_blank">nginx</a> image. The “ng2” mount points to “/usr/share/nginx/html” which is where the container serves HTML pages from by default. The “ng2” shared volume connects the output of the build from <em>ngbuild</em> to the input for the web server in <em>web</em>. </p> <p>This app uses the <a href="https://www.npmjs.com/package/micro-locator" target="_blank">micro-locator</a> service I created to help locate services in apps. The <a href="https://github.com/JeremyLikness/usda-microservice/blob/master/usdaweb/src/environments/environment.ts" target="_blank">environment.ts</a> file maps configuration to endpoints. This allows you to specify different end points for debug vs. production builds. In this case the root service is mapped to port 3000, while the nutrients is mapped to the root of 3001. </p> <p>Even though the services are running on different nodes, the micro-locator package allows the code to call a consistent set of endpoints. You can see this in the <a href="https://github.com/JeremyLikness/usda-microservice/blob/master/usdaweb/src/app/descriptions/descriptions.component.ts" target="_blank">descriptions component</a> that simply references “/descriptions” and “/groups” and uses the micro-locator service to resolve them in its constructor. </p> <p>They are mapped to the same service in configuration but if groups was later pulled out to a separate end point, the only thing you would need to change is the configuration of the locator itself. The end code remains the same.</p> <p>The standard web port 80 is exposed for access, and the service is set to depend on <em>descriptions</em> so it doesn’t get spun up until after the dependent microservices are.</p> <h2>Summary</h2> <p>The purpose of this project is to demonstrate the power and flexibility of containers. Specifically:</p> <ol> <li>Availability of existing, trusted images to quickly spin up instances of databases or node-based containers, for example</li> <li>Least privilege security by only allowing “opt-in” access to services and file systems</li> <li>The ability to compose services together and share common resources</li> <li>The ease of set up for a development environment</li> <li>The ability to build in a “clean” environment without having to install prerequisites on your own machine</li></ol> <p>Although these features make development and testing much easier, Docker also provides powerful features for managing production environments. These include the ability to scale services out on the fly, and plug into orchestrators like <a href="https://kubernetes.io/" target="_blank">Kubernetes</a> to scale across hosts for zero downtime and to manage controlled roll-outs (and roll-backs) of version changes.</p> <p>Happy containers!</p> <p><img style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; padding-right: 0px" border="0" src="http://jeremylikness.com/signature.gif"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-40366294134307044902017-01-09T11:41:00.001-08:002017-02-20T06:13:09.528-08:00Comprehensive End-to-End Angular 2 with Redux and Kendo UI DevOps Example<p>I know, the title is a mouthful. But it describes exactly what I’m sharing! Before and during the Christmas break I created a <a href="https://github.com/JeremyLikness/Angular2ReduxKendoUIHealthApp" target="_blank">project to illustrate</a> how to leverage <a href="https://github.com/reactjs/redux" target="_blank">Redux</a> in <a href="https://angular.io/" target="_blank">Angular 2</a> apps. As part of the process I integrated <a href="http://www.telerik.com/kendo-angular-ui/" target="_blank">Kendo UI</a> and created a full <a href="https://ivision.com/blog/devops-microservices-iot-beyond-hype/" target="_blank">DevOps</a> solution with continuous integration and automated gated deployments to a <a href="https://www.docker.com/" target="_blank">Docker</a> host on <a href="https://azure.microsoft.com/" target="_blank">Azure</a>.</p> <p>To start with, read about <a href="http://developer.telerik.com/topics/web-development/improving-state-app-redux/" target="_blank">Improving the State of your App with Redux</a>.</p> <p><a href="https://lh3.googleusercontent.com/-7BjhMj276A8/WHPnRgLXf-I/AAAAAAAAFaI/Vmx2wP9F1kg/s1600-h/reduxflow%25255B7%25255D.jpg"><img title="reduxflow" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="reduxflow" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg05l3-67xODMUV4ZSN9kWQ6w0bBx6cS4BgnyWCIf7MAf-q6hf2tEDwdnFgg7tfQ0tfq9Nk8nrYinPxnkPX_tYmz1hEIpHwj_3iMvwookHAv0PQye0VyLTU-JZYd_0OgWXEHcL19MO3W7H/?imgmax=800" width="585" height="445"></a></p> <p>After you get the gist of how and why the app was built, learn how I set up <a href="https://ivision.com/blog/devops-docker-containers-deployment-visual-studio-team-services/" target="_blank">DevOps Continuous Deployment with Visual Studio Team Services and Docker</a>.</p> <p><a href="https://lh3.googleusercontent.com/-r8DO1Xj1O84/WHPnSIo9MTI/AAAAAAAAFaQ/IgcGW2tLIK4/s1600-h/containerstack%25255B6%25255D.png"><img title="containerstack" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="containerstack" src="https://lh3.googleusercontent.com/-XLKF50rP8E4/WHPnST2uONI/AAAAAAAAFaU/BP0CQNnHm7k/containerstack_thumb%25255B4%25255D.png?imgmax=800" width="585" height="310"></a></p> <p>Finally, a common question related to Angular 2 is how to test it. On this blog, learn about <a href="http://csharperimage.jeremylikness.com/2016/12/integrating-angular-2-unit-tests-with.html">Integrating Angular 2 Unit Tests with Visual Studio Team Services</a> using PhantomJS and JUnit to report back test results.</p> <p><a href="https://lh3.googleusercontent.com/-Qrl6eKH40Vs/WHPnS7mhFQI/AAAAAAAAFaY/6KtjOd9PDLU/s1600-h/testresults%25255B8%25255D.png"><img title="testresults" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="testresults" src="https://lh3.googleusercontent.com/-f8fDW84m0IQ/WHPnTEC9YHI/AAAAAAAAFac/fFIwF0lqKZ8/testresults_thumb%25255B6%25255D.png?imgmax=800" width="585" height="592"></a></p> <p>Even if you don’t use VSTS for your automation, many of the processes and steps described in this triad of articles will help you build your own deployment pipeline. </p> <p>Happy DevOps in 2017!</p> <p><img style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; padding-right: 0px" border="0" src="http://jeremylikness.com/signature.gif"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-61091923598899024672016-12-24T12:33:00.000-08:002016-12-24T12:46:00.097-08:002016 in Review<p>I’ve heard a lot of complaints about 2016 in general, but for me it was an abundant year. Personally I enjoyed a challenge I gave myself to speak more often than 2015, and believe I succeeded by giving well over <a href="http://csharperimage.jeremylikness.com/p/presentations.html">one dozen talks</a> on topics ranging from Angular 2 and TypeScript to <a href="https://ivision.com/blog/devops-microservices-iot-beyond-hype/" target="_blank">DevOps</a>. </p> <p>This year I became a Samsung fan. I traded in my Windows Phone for a <a href="http://amzn.to/2irzw8i" target="_blank">Samsung Galaxy 7</a>. I also purchased the Oculus-powered <a href="http://amzn.to/2hUcRV7" target="_blank">Gear VR</a> and have enjoyed it more than I imagined. I still spend time in VR every week and find the immersive experience far more rewarding than the augmented reality of the HoloLens. </p> <p>I ditched my Microsoft Band 2 after having to replace it under warranty for the third time. I waited patiently and picked up a <a href="http://amzn.to/2irBxS0" target="_blank">Samsung Gear S3</a>. </p> <p><a href="https://lh3.googleusercontent.com/-YnARQDLNgf8/WF7X-hPIQqI/AAAAAAAAFQ4/11UrrSQ99qo/s1600-h/gears3-14.png"><img title="gears3-1" style="display: inline" alt="gears3-1" src="https://lh3.googleusercontent.com/-Y1SLFGj38mo/WF7X_LzKVEI/AAAAAAAAFQ8/-XmfkEqXxVI/gears3-1_thumb2.png?imgmax=800" width="600" height="800"></a></p> <p>After a lot of research I decided I didn’t need a hardcore fitness band, but preferred a smartwatch that had great fitness features. The Gear S3 looks sharp:</p> <p><a href="https://lh3.googleusercontent.com/-JvUEvP-s3Oc/WF7X_r_kZvI/AAAAAAAAFRA/iBHjVMognyg/s1600-h/gears3-24.png"><img title="gears3-2" style="display: inline" alt="gears3-2" src="https://lh3.googleusercontent.com/-DDodcl3CvGE/WF7YAP_Ki2I/AAAAAAAAFRE/8tY-373Ocno/gears3-2_thumb2.png?imgmax=800" width="600" height="800"></a></p> <p>It has a great battery life (over a day so I can always find time to charge), recharges wireless and fast, and has great functionality. For example, you’d think setting reminders using just your voice or answering the phone through the microphone and speaker in your watch are novelty items, but I’ve done both in practice and it’s helped me out in situations when I didn’t want to pull my phone from my pocket. </p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKSEA-ykzyNkasAMPvih2zq9R_vP1G7w0V-iP4r90SzeKt-B3vr6qowK-uukb2rftCA_ITn7hXMCR4tZfS4xnWDGV1JDpTod8FjjI1-U0ZOusLkR-6REbXL842GGzQDbNTe-jYeKkFlVC3/s1600-h/gears3-34.png"><img title="gears3-3" style="display: inline" alt="gears3-3" src="https://lh3.googleusercontent.com/-kDiBf0JGMeg/WF7YBM_ofmI/AAAAAAAAFRM/dQLW04smpbE/gears3-3_thumb2.png?imgmax=800" width="600" height="454"></a></p> <p>The fitness features are phenomenal. It has great detection for steps and flights of stairs, very accurate heart rate (I know because I monitor mine manually quite frequently), auto-detects exercise, and has a running mode that makes it easy to see your lap time, stride, and other stats “on the run.” </p> <p>Trust me, I didn’t receive any of these items as promotional gear and was surprised to find myself getting so many Samsung products. The most fun I had was with my <a href="http://amzn.to/2hUnQ0R" target="_blank">Gear 360</a>. This boasts two fish-eye lenses with slightly more than 180 degrees of view, so it can simultaneously capture all directions and digitally glue the seams. I purchased it to capture the summits of mountains we climbed over the summer, like our first 14,000 foot tall peak (click the images to scroll in 360 degrees):</p> <p><iframe height="400" src="https://kuula.co/share/7fS2T" frameborder="0" width="600" scrolling="no" allowfullscreen="true"></iframe></p> <p>…and the grueling half marathon hike up Pike’s Peak:</p> <p><iframe height="400" src="https://kuula.co/share/7fS2d" frameborder="0" width="600" scrolling="no" allowfullscreen="true"></iframe></p> <p>In general I was not surprised to see our project work pick up momentum with Angular 2. I was surprised to see the strides we made with Agile and adoption of DevOps. We were able to automate deployment for several large customers and closed out the year with a strong focus on containers (<a href="https://ivision.com/blog/devops-docker-containers-deployment-visual-studio-team-services/" target="_blank">Docker</a>), mobile (with both Ionic and <a href="https://www.xamarin.com/" target="_blank">Xamarin</a>), and mobile DevOps.</p> <h2>The Year of the Blog </h2> <p>This blog should get a new name because I haven’t posted nearly as much content related to C#. Most of my focus has been on front-end, JavaScript and TypeScript development, with a lot of Angular 2, as well as Agile and DevOps concerns. Total sessions and page views are down from last year, but I’m not surprised because I did not post nearly as frequently. Instead, I presented <a href="http://csharperimage.jeremylikness.com/p/presentations.html" target="_blank">dozens of talks</a>, published <a href="http://developer.telerik.com/author/jlikness/" target="_blank">several articles</a>, and focused heavily on building the <a href="https://ivision.com/services/technology/application-development/" target="_blank">app dev practice</a> at <a href="https://ivision.com/" target="_blank">iVision</a>.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicrJWTtuB8149cvos-FyOWj7k4GVnCKgqkz9PLZxnjk7_x0JbBzv88DAdjIPUz7jsJuDm3fxAhH2P8o-tV2mP2nfiXBUNgJgBX3mnbL_t3IEYfyARtoWaKLWUW-kr2uyegHGlzdLl55vNX/s1600-h/2016blog5.png"><img title="2016blog" style="display: inline" alt="2016blog" src="https://lh3.googleusercontent.com/-Xh_JD8s5WAE/WF7YBlPF_ZI/AAAAAAAAFRU/b3keILWScK4/2016blog_thumb3.png?imgmax=800" width="600" height="649"></a></p> <p>Top referrals to my personal blog were from <a href="https://twitter.com/jeremylikness" target="_blank">Twitter</a>, <a href="http://stackoverflow.com/users/228918/jeremy-likness" target="_blank">Stackoverflow</a>, a previous company I worked for and the <a href="https://dzone.com/users/975941/jeremy.likness.html" target="_blank">DZone</a>. </p> <p>Demographics remain similar, with a dominantly young, male audience, the majority from the U.S. followed by India, the United Kingdom, Germany, and Russia. </p> <p>Chrome continues to dominate the browsers that visit my site, edging up to 73% from last year’s 67%. Firefox holds second place at 11% and Internet Explorer holds a close tie with Safari at just around 5% each.</p> <p>Despite publishing several dozen posts this year, older articles still remain the most viewed. The top three were:</p> <ol> <li><a href="http://csharperimage.jeremylikness.com/2014/11/the-top-5-mistakes-angularjs-developers.html" target="_blank">The Top 5 Mistakes AngularJS Developers Make</a> (but when I give Angular talks, it seems like people are still making them) <li><a href="http://csharperimage.jeremylikness.com/2010/04/model-view-viewmodel-mvvm-explained.html" target="_blank">Model-View-ViewModel (MVVM) Explained</a> (that is a 6 year old article – also <a href="http://maromasdigitales.net/2010/05/patron-mvvm-explicado/" target="_blank">translated to Spanish</a>!) <li><a href="http://csharperimage.jeremylikness.com/2012/03/windows-8-icons-segoe-ui-symbol.html" target="_blank">Windows 8 Icons</a> (huh?!)</li></ol> <p>A goal of mine for 2017 is to be more consistent with this blog and balance my writing between work, this blog, and the various sites I freelance for.</p> <h2>The Year in GitHub </h2> <p>Last year I became really active with <a href="https://github.com/JeremyLikness" target="_blank">GitHub</a>. I’m finally used to and comfortable with git and do so much work with Node.js and other open source projects it was just a logical transition. </p> <p><a href="https://lh3.googleusercontent.com/-XxT7MYbMta4/WF7YCINIHHI/AAAAAAAAFRY/Suh1OF3P8T8/s1600-h/2016github25.png"><img title="2016github" style="display: inline" alt="2016github" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFlacX5-JRUy55muD-KT9KXw8yTif_hwh5fbLcg1b9M6_lpb3HKChnXGbE5cC_7Owx96rfhd6GS9Ie6meqWu50fvB5vCL0rVutvdfQkbiwJibAOUX6qL0Fi7MnqacPsCzMtQL1PzMBpdn2/?imgmax=800" width="600" height="158"></a></p> <p>I closed out the previous year explaining how dependency injection works with the <a href="https://github.com/JeremyLikness/jsInject" target="_blank">jsInject project</a> (I plan to package that for npm soon); rewrote my <a href="https://github.com/JeremyLikness/AngularHealthApp" target="_blank">Angular 1.x Health App</a> in <a href="https://github.com/JeremyLikness/Angular2HealthApp" target="_blank">Angular 2</a>, <a href="https://github.com/JeremyLikness/AngularES6HealthApp" target="_blank">ECMAScript 2015</a>, and with <a href="https://github.com/JeremyLikness/Angular2ReduxKendoUIHealthApp" target="_blank">Redux and Kendo UI</a>; ported my <a href="https://github.com/JeremyLikness/6502emulator" target="_blank">6502 emulator</a> to Angular 2 with TypeScript; wrote a <a href="https://github.com/JeremyLikness/redux-adventure" target="_blank">text-based adventure game</a>; created a full day <a href="https://github.com/JeremyLikness/ng2ts-workshop" target="_blank">Angular 2 and TypeScript workshop</a>; and recently published a simple <a href="https://github.com/JeremyLikness/micro-locator" target="_blank">microservices locator</a>. </p> <p>I’m looking forward to many more open source projects in 2017!</p> <h2>The Year in Twitter</h2> <p>This year was interesting on Twitter. I continued to gain steady followers but it was much more “two steps forward, one-and-a-half steps back” than previous years. I’m not sure if it’s due to the breadth of topics, typical attrition, or some other factor, but it has been slower growth. </p> <p><a href="https://twitter.com/jeremylikness" target="_blank"><img title="jeremytwitter" style="display: inline" alt="jeremytwitter" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-eLmGAV2e4Tx4auAEcUUpEFKzCk59Ia-q_7H3Ezo8sGP6_HzUxuC7IiHdQ-_S5Yvhp1gl8xY7oLonPejbKQyGW9vZSuculBFcBG78cnbBb10JlgOZkfJInIXLJ82jb8dW2nXtFYeO2qSA/?imgmax=800" width="600" height="778"></a></p> <p>To date, all of my Twitter growth has been organic. I haven’t applied to any “gain x followers” and do not follow others for a follow back. I try to keep the list of those I follow at just under 1,000 and prune the list based on signal-to-noise ratio, people I genuinely know and people with topics or feeds that I am passionate about.</p> <h3>Most Viewed</h3> <p>With no competition, <a href="https://angular.io/" target="_blank">Angular 2</a> was <em>the</em> topic on Twitter this year. All top views are related (even <a href="https://github.com/Reactive-Extensions/RxJS" target="_blank">RxJS</a> is popular due to its inclusion in the Angular 2 distribution).</p> <blockquote class="twitter-tweet" data-lang="en"> <p lang="en" dir="ltr">Building <a href="https://twitter.com/hashtag/Angularjs?src=hash">#Angularjs</a> 2.0 <a href="https://twitter.com/hashtag/Angular2?src=hash">#Angular2</a> components "on the fly": <a href="https://t.co/I83X5uETJD">https://t.co/I83X5uETJD</a> an exmaple with dialogs</p>— Jeremy Likness (@jeremylikness) <a href="https://twitter.com/jeremylikness/status/799394307950125056">November 17, 2016</a></blockquote><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script> <blockquote class="twitter-tweet" data-lang="en"> <p lang="en" dir="ltr">...and now <a href="https://twitter.com/hashtag/Angular2?src=hash">#Angular2</a> 2.2 is available <a href="https://t.co/JTaHT0eiPu">https://t.co/JTaHT0eiPu</a> <a href="https://twitter.com/hashtag/angularjs?src=hash">#angularjs</a> <a href="https://twitter.com/hashtag/ng2?src=hash">#ng2</a></p>— Jeremy Likness (@jeremylikness) <a href="https://twitter.com/jeremylikness/status/799023041867026433">November 16, 2016</a></blockquote><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script> <blockquote class="twitter-tweet" data-lang="en"> <p lang="en" dir="ltr">A simple guide to debugging <a href="https://twitter.com/hashtag/RxJS?src=hash">#RxJS</a> <a href="https://t.co/W1E8h1GojT">https://t.co/W1E8h1GojT</a></p>— Jeremy Likness (@jeremylikness) <a href="https://twitter.com/jeremylikness/status/808402387018936320">December 12, 2016</a></blockquote><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script> <h3>Most Liked</h3> <p>The most liked followed the most viewed closely with the exception of:</p> <blockquote class="twitter-tweet" data-lang="en"> <p lang="en" dir="ltr">Real-time applications using <a href="https://twitter.com/hashtag/ASPNETCore?src=hash">#ASPNETCore</a>, <a href="https://twitter.com/hashtag/SignalR?src=hash">#SignalR</a> & <a href="https://twitter.com/hashtag/AngularJs?src=hash">#AngularJs</a> <a href="https://t.co/PhJxAQoHVi">https://t.co/PhJxAQoHVi</a></p>— Jeremy Likness (@jeremylikness) <a href="https://twitter.com/jeremylikness/status/785488865217875968">October 10, 2016</a></blockquote><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script> <h3>Most Clicked</h3> <p>The top clicked tweets align with the top viewed and liked. The fifth most popular was this critique of Angular 2 which many told me "wasn't fair" but I like to post contrasting articles for balance in my feed:</p> <blockquote class="twitter-tweet" data-lang="en"> <p lang="en" dir="ltr">Although I don't agree with the title, <a href="https://twitter.com/hashtag/Angular2?src=hash">#Angular2</a> developers can learn from this in-depth critique <a href="https://t.co/stvD77MGPx">https://t.co/stvD77MGPx</a> Some valid points</p>— Jeremy Likness (@jeremylikness) <a href="https://twitter.com/jeremylikness/status/804707975541751808">December 2, 2016</a></blockquote><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script> <h2>2017 Predictions</h2> <p>What do I predict for 2017?</p> <p>Personally, I will continue to speak as often as I can. I love reaching the developer community and all of my talks are based on real world experience. I’ve found it helps to connect when you are able to relate technology in terms of “lessons learned” and case studies “in the real world.” </p> <p>I hope to continue to grow my knowledge in the DevOps space and believe we will see an exponential increase of containerized (Docker-based) workloads in 2017. With the introduction of <a href="https://www.microsoft.com/net/core" target="_blank">.NET Core</a> and <a href="http://blogs.microsoft.com/blog/2016/03/07/announcing-sql-server-on-linux/" target="_blank">SQL Server on Linux</a>, we’re also going to see many organizations shift from traditional Windows-based infrastructure to commodity Linux machines running as VM and Docker hosts. Finally I do believe in 2017 the “native vs. hybrid” debate will fade and it will truly become, “What is your development tool of choice?” as options like <a href="https://www.nativescript.org/" target="_blank">NativeScript</a> and Xamarin enable developers to write native mobile apps using the language and development environments of their choice.</p> <p>My last prediction? I think I’ll be using a <strong>lot </strong>of <a href="https://code.visualstudio.com/" target="_blank">Visual Studio Code</a> next year.</p> <p>I wish you a very Merry Christmas and Happy New Year. </p> <p>Until next time,</p> <p><img style="display: inline" src="http://jeremylikness.com/signature.gif"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-34496466269909442882016-12-08T11:32:00.000-08:002016-12-09T05:04:48.446-08:00Integrating Angular 2 Unit Tests with Visual Studio Team Services<p>DevOps focuses on continuous delivery of value by removing barriers between application development and operations teams. A crucial component of the DevOps pipeline is continuous integration (CI). CI is the process of automating a build and tests to ensure a stable code branch. Traditionally this has been difficult to achieve in web-centric and Single Page Applications (SPA) that focus on the front-end, but modern libraries and tools make it a lot easier to “chase the <a href="http://www.cio.com/article/2980298/it-strategy/what-makes-a-devops-unicorn.html" target="_blank">unicorns</a>.”</p> <p><a href="https://lh3.googleusercontent.com/-FL_Ce1oNm1s/WEm250QEC4I/AAAAAAAAFFg/AlcVMUSxCl0/s1600-h/junitvsts%25255B12%25255D.png"><img title="junitvsts" style="display: inline" alt="junitvsts" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisNWVb9R7AkVDpFhtohW1p-sYcQ6ZVtqyk3eG0192YoWSiqf6s1fI14Xp7OJKyuiSVeQ56vnxuzMY8gIv8CN5NjLngO_usFrzAkAL2YqjHDC-NgxmZRAs20wb5voBDxCSORcbZozVn3xpv/?imgmax=800" width="585" height="592"></a></p> <p>I recently published an application to GitHub that features <a href="https://github.com/JeremyLikness/Angular2ReduxKendoUIHealthApp" target="_blank">Angular 2, Redux, and Kendo UI</a>. It also continuously integrates and deploys to a <a href="https://www.docker.com/" target="_blank">Docker</a> host. You can <a href="http://jrldocker.cloudapp.net:8111/" target="_blank">view the running app here</a>. It is run as a Docker container, managed by a Docker host, on an Ubuntu (Linux) server hosted in <a href="https://azure.microsoft.com/" target="_blank">Azure</a>. </p> <p>Although the source is hosted on GitHub, I connected the repository to <a href="https://azure.microsoft.com/en-us/services/visual-studio-team-services/" target="_blank">Visual Studio Team Services</a> (VSTS) for continuous integration and deployment. The app has over sixty (60) automated tests that are run as part of integration. It is critical to ensure that all tests pass before the Docker image is created and deployed to production. It is also important to see the detailed results of tests so that broken builds can be quickly triaged and addressed. </p> <h2>Good Karma</h2> <p>I used the <a href="http://csharperimage.jeremylikness.com/2016/05/the-angular-2-cli-and-typescript.html">Angular Command Line Interface</a> to scaffold the project. Out of the box, the Angular-CLI leverages <a href="https://jasmine.github.io/" target="_blank">Jasmine</a> to define tests and <a href="http://karma-runner.github.io/" target="_blank">Karma</a> to as its test-running suite. A Jasmine test might be a simple unit test based on pure JavaScript: </p> <p><script src="https://gist.github.com/JeremyLikness/48914f51fb708ae4e45a0c8f5f4aa28d.js"></script></p> <p>Angular 2 provides a test service that enables integration-style tests that interact with actual web components: </p> <p><script src="https://gist.github.com/JeremyLikness/51b5432472d2b62746bcbc7b59ee436b.js"></script></p> <p>Either way, the tests “as configured” aren’t good enough for an automated build via VSTS for two reasons: </p> <p>1. They depend on a browser to host the tests (Chrome, by default) that isn’t available on the build server.</p> <p>2. They only generate output to the console and don’t create a file that can be parsed for test results. </p> <h2>The Phantom Browser</h2> <p>The first step is to get rid of the browser dependency. Fortunately, a project was created to provide a “headless browser” or one that runs without rendering “real” UI, and it is called <a href="http://phantomjs.org/" target="_blank">PhantomJS</a>. To include it in my project, I issued the following command: </p> <p><font face="Consolas">npm i phantomjs-prebuilt --save-dev</font></p> <p>This creates a development dependency on the pre-built version of PhantomJS so that the project can pull it down and install it as a dependency. It adds the reference to the project’s <a href="https://github.com/JeremyLikness/Angular2ReduxKendoUIHealthApp/blob/master/package.json" target="_blank">package.json</a> file. </p> <p>The next step is to add a launcher to Karma. These packages help link Karma to browsers so Karma is able to launch the host to run the tests. The Karma launcher is installed like this: </p> <p><font face="Consolas">npm i karma-phantomjs-launcher --save-dev</font></p> <p>Finally, you need to edit the <a href="https://github.com/JeremyLikness/Angular2ReduxKendoUIHealthApp/blob/master/karma.conf.js" target="_blank">karma.conf.js</a> configuration file to include the launcher: </p> <p><script src="https://gist.github.com/JeremyLikness/06141283c24265cfc1a0c9bd6c5b50fd.js"></script></p> <p>Now you verify the setup by running the tests through PhantomJS: </p> <p><font face="Consolas">ng test --browsers=PhantomJS</font></p> <p>You should see the same output you normally see from Chrome, with the exception that no external browser is launched.</p> <blockquote> <p>Note: some build machines may require you to install additional prerequisites for PhantomJS. For example, Ubuntu <a href="https://gist.github.com/julionc/7476620" target="_blank">requires additional font libraries to be installed</a>.</p></blockquote> <h2>JUnit of Measure</h2> <p>The next requirement is to generate output that can be parsed by the build. Karma uses reporters to provide test results, and ships with a “progress” reporter that writes test results out to the command line. </p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN1845C18zk55GxpPtIdzp3PTouwGkmHFu3Rnw5boH7YbeZv7FYB8uCRwwSoSpoUv7ZHW0lOSE-WP_MXiSjTxyCgdC7d9QFO4m11C_AHqI6uBgVCRKjfCa2czpX61lEqzxAKa5EhX653-1/s1600-h/testrun%25255B28%25255D.png"><img title="testrun" style="display: inline" alt="testrun" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjH5sZFLOZOC-ahNSR7Z5lmCJBPx4VSb_2I9QcR6oVfi0z5zpjmp807azSUkppqcQFwPJoa47dDEx0KPr6-DTEZ8_EfX83Hh9zmghlQ6kHBAPBHDRhfJf1Flo_T6iiIx_nQlT0f0z9E2KL_/?imgmax=800" width="585" height="250"></a></p> <p>By default, VSTS is able to process JavaScript unit tests in the <a href="http://junit.org/" target="_blank">JUnit</a> format. Karma has a JUnit reporter that can be installed: </p> <p><font face="Consolas">npm i karma-junit-reporter --save-dev</font></p> <p>This can be added to the Karma config file the same way the PhantomJS launcher was. Now you can run tests using the <font face="Consolas">--reporters=junit</font> flag and the test run will generate a file named <font face="Consolas">TESTS-browser_(platform).xml</font>. For example, a local run on Windows 10 creates <font face="Consolas">TESTS-Chrome_54.0.2840_(Windows_10_0.0.0).xml</font>. If you open the file, you’ll see XML that defines the various test cases, how long they ran, and even a structure that holds the console output.</p> <h2>Configuring VSTS</h2> <p>I assume you know how to configure builds in VSTS. If not, check out <a href="https://ivision.com/blog/devops-docker-containers-deployment-visual-studio-team-services/" target="_blank">the full CI/CD article</a>. The build steps I created look like this: </p> <p><a href="https://lh3.googleusercontent.com/-CDi9JyRGEpM/WEm28qf-3mI/AAAAAAAAFFw/XLoGsFraHU4/s1600-h/buildsteps%25255B5%25255D.png"><img title="buildsteps" style="display: inline" alt="buildsteps" src="https://lh3.googleusercontent.com/-sS8ejmgI03Y/WEm29GklRrI/AAAAAAAAFF0/k62tux4br8o/buildsteps_thumb%25255B3%25255D.png?imgmax=800" width="585" height="473"></a></p> <p>The first step ensures the Angular Command Line interface is installed on the environment. The package manager command is <font face="Consolas">install</font> and the arguments are:</p> <p><font face="Consolas">-g angular-cli@1.0.0-beta.20-4</font></p> <p>(This is the version the project was built with). The second step installs the dependencies for the project itself and just uses the <font face="Consolas">install</font> command with no arguments.</p> <p>With the Angular-CLI installed, we can now run a command to execute the tests and generate the output file. I use two reporters. The progress reporter allows me to see the progress of the test run in the console output for the build and will abort the build if any tests fail. The JUnit reporter writes the test results file. The tool is <font face="Consolas">ng</font> and the arguments:</p> <p><font face="Consolas">test --watch=false --single-run=true --reporters=junit,progress --browsers=PhantomJS</font></p> <p>The next step instructs the VSTS agent to read the test results file and integrate it into the build results. This is what the configuration looks like:</p> <p><a href="https://lh3.googleusercontent.com/-8bld_FC8LWE/WEm29gjLtOI/AAAAAAAAFF4/2a-WLPjNrcs/s1600-h/publishtest%25255B5%25255D.png"><img title="publishtest" style="display: inline" alt="publishtest" src="https://lh3.googleusercontent.com/-uaLXcaq3Vi0/WEm2-MwIm2I/AAAAAAAAFF8/FVjHx_Diw7Q/publishtest_thumb%25255B3%25255D.png?imgmax=800" width="585" height="346"></a></p> <p>Here is a snippet of the test run output: </p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpWH60cbk5kVRkioy7al9nlLL-Y9wdIkAL9FCq9Ox6SK2GYZBJ0LvJJCvGs2tBNtzeGN2gUvAC6wob8dwptS6IsgowF2LK-sojh_WwSDMaAufOVmZbjyC9sKXvGzVdIUXNOa_BYWTZq5_7/s1600-h/testrunoutput%25255B5%25255D.png"><img title="testrunoutput" style="display: inline" alt="testrunoutput" src="https://lh3.googleusercontent.com/-6ItFDPC_paM/WEm3ANMJH_I/AAAAAAAAFGE/CN4Qyyb4M8U/testrunoutput_thumb%25255B3%25255D.png?imgmax=800" width="585" height="489"></a></p> <p>That’s it! Now the automated build can create the Angular 2 production application <em>after </em>verifying tests successfully ran. The VSTS build log will contain specific test results and even allow you to set up a widget to chart pass/fail percentage over time. Release Management can then take the results of a successful build and deploy to production. For a more comprehensive overview of the CI/CD process, please read <a href="https://ivision.com/blog/devops-docker-containers-deployment-visual-studio-team-services/" target="_blank">DevOps: Continuous Deployment with Visual Studio Team Services and Docker</a>.</p> <p>Happy DevOps!</p> <p><img src="http://jeremylikness.com/signature.gif"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-80883451037322340582016-07-30T08:30:00.000-07:002016-07-30T08:36:09.364-07:00An Adventure in Redux: Building redux-adventure<p><a href="http://redux.js.org/" target="_blank">Redux</a> is a “predictable state container for JavaScript apps.” If you’re like me, reading about a new technology is nice but it takes a good project to really understand it. For some reason, when I hear “state machine” I immediately think of the <a href="http://inform-fiction.org/zmachine/standards/z1point1/index.html" target="_blank">Z-machine</a> that was created “on a coffee table in Pittsburgh in 1979” that revolutionized computer games in the early 80s by bringing text-based adventure games to myriad platforms.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTVk8wmYn7ukGDu2P1QOKjdXLRP6e6kmKa_UCqOLN2wQnGYDxbDBDu0HtB9_TpugYO0UcLTfnYmTRPmahkQ_MsIISC49RPCAki9OSMQv7MxWZ8gj5HKyPo87khPYUF-0OXuxxjPlUmBdLg/s1600-h/thumbnail%25255B5%25255D.gif"><img title="thumbnail" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="thumbnail" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggAletT-oCovaYvuTrEDbhzDVCEkTldOemaDqSdpwT2vMm-PBlwkSFrkwSdmvACm9k_NODm_nBAoTXOEx9Kfe5s3l2eRXN2YMzT64FDSYNW62kf35Q080LoY_G1J447zWIhmLqhrraFvJk/?imgmax=800" width="516" height="480"></a></p> <p>I originally thought of re-factoring my <a href="https://github.com/JeremyLikness/6502emulator" target="_blank">6502 emulator</a> to use Redux, but realized it would be a far bigger task to take on so I decided to build something from scratch instead. Borrowing from an app I wrote for a book I published a few years ago, I built <a href="https://github.com/JeremyLikness/redux-adventure" target="_blank">redux-adventure</a> using <a href="https://angular.io/" target="_blank">Angular 2</a> and <a href="http://www.typescriptlang.org/" target="_blank">TypeScript</a> with the <a href="http://developer.telerik.com/featured/rapid-cross-platform-development-angular-2-cli/" target="_blank">Angular-CLI</a>.</p> <h2>Redux Concepts</h2> <p>There are numerous tutorials online that cover Redux. One problem I find is that a lot tend to overcomplicate the description and throw graphs that make it look far more involved than it really is. Rather than re-inventing the wheel, I’ll share a simple description here and then walk through the app that uses it. </p> <p>Redux is a simple state management tool. Your application may transition through multiple states. At any given time you may raise an event, or create an action, that results in a new state. State is immutable, so actions will never modify the existing model that represents your state but instead will generate a new model. This is the concept that is sometimes difficult to understand. </p> <p>Redux keeps track of state for you, and offers three key services (there are other APIs, but I’m keeping this simple).</p> <ul> <li>The ability to <em>dispatch</em> an action, indicating a transition in state <li>A set of <em>reducers</em> that respond to an action by providing the new state <li>A <em>subscription</em> that receives a notification any time the state changes</li></ul><br/> <h2>The game</h2> <p>The <a href="https://jeremylikness.github.io/redux-adventure/" target="_blank">redux-adventure</a> game is fairly straightforward. You are dropped in a random room in a dungeon and must explore the dungeon to find various artifacts. You can look or travel in the four compass directions, and if there is an item you can get it to put it into your inventory. You win the game by retrieving all of the available items.</p> <h2>State</h2> <p>The state itself is really just a domain model represented by a plain-old JavaScript object (POJO). A “thing” or artifact has a name and a description. Then there are rooms that look like this: </p> <p><script src="https://gist.github.com/JeremyLikness/80cc8531c1f337bfe6c5301f6606b4ec.js"></script></p> <p>Notice that a room may contain more than one inventory item. It also keeps track of other rooms based on compass direction and walls where there are no rooms to navigate to.</p> <p>The world itself is represented by a <em>dungeon</em> class that contains rooms, the player’s inventory, the count of total items they must obtain, the current room, a console that contains the text displayed to the user, and a flag indicating whether or not the player has won.</p> <p><script src="https://gist.github.com/JeremyLikness/4ebe1c89e27046f9c89af939049a131d.js"></script></p> <p>There is also a <a href="https://github.com/JeremyLikness/redux-adventure/blob/master/src/app/world/dungeonMaster.ts" target="_blank">dungeonMaster</a> that generates the world from some seed information and randomly generates walls. Any classes or services with behavior have their own <a href="https://github.com/JeremyLikness/redux-adventure/blob/master/src/app/world/dungeonMaster.spec.ts" target="_blank">tests</a>. Now that we have the world defined, what can we do? </p> <h2>Actions</h2> <p>The user can type in any number of commands that are represented by the <a href="https://github.com/JeremyLikness/redux-adventure/blob/master/src/app/actions/ActionList.ts" target="_blank">action list</a>. Although an action may start as these commands, based on the current state they end up being translated into four key actions: </p> <ul> <li><em>Move</em>: updates the current room to the room the user has navigated to, and updates the console to indicate the movement and display the description of the new room <li><em>Get</em>: transfers inventory from the current room to the user <li><em>Text</em>: adds a line of text to the console <li><em>Won</em>: transfers the final item of inventory to the user, sets the won flag, and updates the console to indicate the user has won</li></ul> <p>The <a href="https://github.com/JeremyLikness/redux-adventure/blob/master/src/app/actions/createAction.ts" target="_blank">createAction</a> method is responsible for this logic. TypeScript allows me to write interfaces to make it more clear what an action inspects. Here is the “get” action’s interface: </p> <p><script src="https://gist.github.com/JeremyLikness/02c90cedd928ba3eb41adb9f34ee688f.js"></script></p> <p>And here is the code that takes the original action and transforms it into an internal one: </p> <p><script src="https://gist.github.com/JeremyLikness/cf861efa68da1d9f2d208b122c5c4439.js"></script></p> <p>Notice that one “incoming” action can translate to three “internal” actions: text with a snarky comment when there is nothing to get, an action to transfer the inventory to the user, and an action to indicate the user has won.</p> <p>The translation of actions is fully <a href="https://github.com/JeremyLikness/redux-adventure/blob/master/src/app/actions/creationAction.spec.ts" target="_blank">testable</a>. Note that to this point we’ve been working in pure TypeScript/JavaScript – none of this code depends on any external framework yet.</p> <h2>Reducers</h2> <p>Reducers may take awhile to get used to, but in essence they simply return a new state based on an action and ensure the existing state isn’t mutated. The easiest way to tackle reducers is from the “bottom up” meaning take the lower level properties or nested objects and handle their state, then compose them into higher levels. </p> <p>As an example, a room contains a set of inventory items. The “get” action transfers inventory to the user, so the <font face="Consolas">things</font> property of the room is updated with a new array that no longer contains the item. Here is the TypeScript code: </p> <p><script src="https://gist.github.com/JeremyLikness/587d7a30294e4f8b6eb710630320e1dc.js"></script></p> <p>If the ellipses notation is confusing, it’s part of a newer spec that allows for composition of items. It essentially represents a portion of the array. What is returned is a new array that no longer has the item. Here is the JavaScript: </p> <p><script src="https://gist.github.com/JeremyLikness/f6d11905688f6b3f00255619d1fdd80c.js"></script></p> <p>You can view the corresponding tests written in TypeScript <a href="https://github.com/JeremyLikness/redux-adventure/blob/master/src/app/reducers/reducer.things.spec.ts" target="_blank">here</a>. Notice that in the tests, I use <font face="Consolas">Object.freeze</font> to ensure that the original instances are not mutated. I freeze both the individual items and the list, and then test that the item is successfully removed.</p> <p>Another reducer will operate on the array of inventory items for the player. Instead of removing the item as it does from the room, it will return a new array that adds the item to the player’s inventory. </p> <p>The reducer for the room calls the reducer for the <font face="Consolas">things</font> property and returns a new room with properties copied over (and, in the case of navigating to the room, sets the <font face="Consolas">visited</font> flag).</p> <p><script src="https://gist.github.com/JeremyLikness/f4b280482456cb6e78ae0e3cb2230c3c.js"></script></p> <p>You can view the <a href="https://github.com/JeremyLikness/redux-adventure/blob/master/src/app/reducers/reducer.main.ts" target="_blank">main reducer</a> code to see the logic of handling various actions, and calling other reducers as well (i.e. main calls the reducer for the rooms list, and rooms calls the reducer for the individual room). </p> <p>In the end, the <a href="https://github.com/JeremyLikness/redux-adventure/blob/master/src/app/reducers/reducer.main.spec.ts" target="_blank">tests</a> simply validate that the state changes appropriately based on an action and doesn’t mutate the existing state. </p> <p>At this stage the entire game logic is complete – all state transitions through to a win are there, and we could write some simple AI to have a robot play the game and output its results. Everything is testable and we have no dependencies on any frameworks (including Redux) yet. </p> <p>This is a powerful way to build software, because now whether you decide to use Angular, React, plain JavaScript or any other framework, the main business logic and domain remains the same. The code doesn’t change, the tests are all valid and framework agnostic, and the only decision is how you render it.</p> <h2>The Redux Store</h2> <p>The purpose of Redux is to maintain the state in a store that handles the actions and applies the reducers. We’ve already done all of the legwork, all that’s left is to create the store, respond to changes in state, and dispatch actions as they occur.</p> <p>The root component of the Angular application handles all of this: </p> <p><script src="https://gist.github.com/JeremyLikness/f3d00edcabced5182dacec7cedc57fb1.js"></script></p> <p>Notice how simple the component is! It doesn’t have to handle any business logic. It just creates the store, refreshes a property when the state changes, and dispatches actions.</p> <p>The template is simple as well. It lists the console, provides a parser to receive user input if the game hasn’t been won yet, and renders a map of the rooms.</p> <p><script src="https://gist.github.com/JeremyLikness/8107dee3cdd7383801149b7384632c7a.js"></script></p> <p>With this approach, the components themselves have no business logic at all, but simply respond to the bound data. Let’s dig a little deeper to see.</p> <h2>Components</h2> <p>Approaching the application in this fashion makes it very easy to build components. For example, this is the console component. It does just two things: exposes a list of text, and responds to changes by setting properties on the <font face="Consolas">div</font> element so that it always scrolls the latest information into view:</p> <p><script src="https://gist.github.com/JeremyLikness/ef891c512c1cb4d3eea41593b5e82ea4.js"></script></p> <p>If you’re nervous about seeing HTML elements mixed in with the component, don’t worry! They are completely testable without the browser:</p> <p><script src="https://gist.github.com/JeremyLikness/c0b2d171b70a42e26dfc4cad2a6de73a.js"></script></p> <p>The parser component solely exists to take input and dispatch actions. The main component listens to the parser and uses the event emitter to dispatch actions to the Redux store (that code was listed earlier). The parser itself has an action to emit the input, and another action that auto-submits when the user hits ENTER from within the input box:</p> <p><script src="https://gist.github.com/JeremyLikness/de1c75c10f89253c47db8f198e88c04e.js"></script></p> <p>After playing the game I realized it would be a lot easier to test if I had a map, so I created the map component to render the grid and track progress. The <a href="https://github.com/JeremyLikness/redux-adventure/blob/master/src/app/map/map.component.spec.ts" target="_blank">map component</a> itself simply translates the list of rooms into a matrix for rendering cells. For each <a href="https://github.com/JeremyLikness/redux-adventure/blob/master/src/app/cell/cell.component.ts" target="_blank">cell</a>, a green square indicates where the user is, a white square is a visited cell (with walls indicated) and a black cell is a place on the map that hasn't been explored yet. </p> <p>Despite the heavy manipulation of styles to indicate background colors and walls, this component is also <a href="https://github.com/JeremyLikness/redux-adventure/blob/master/src/app/cell/cell.component.spec.ts" target="_blank">completely testable</a> without relying on the browser.<br></p> <h2>Conclusion</h2> <p>You can view the <a href="https://github.com/JeremyLikness/redux-adventure/tree/master/src" target="_blank">full source code</a> on GitHub and play the game <a href="https://jeremylikness.github.io/redux-adventure/" target="_blank">here</a>. Overall, building this was a great learning experience for me. Many of the articles I read had me slightly confused and left me with the feeling it was overcomplicating things, but having gone through the process I can clearly see the benefits of leveraging Redux for apps. </p> <p>In general, it enables me to build a domain using vanilla TypeScript/JavaScript and declare any logic necessary on the client in a consistent way by addressing actions and reducers. These are all completely testable, so I was able to design and validate the game logic without relying on any third party framework. </p> <p>Linking Redux was an easy step, and it made the logic for my components even easier. Instead of encapsulating services to drive the application, I was able to create a store, respond to changes to state within the store, and build every component as a completely testable, independent unit. </p> <p>What do you think? Are you using Redux in your apps? If you are, please use the comments below to share your thoughts. </p> <p><img style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; padding-right: 0px" border="0" src="http://jeremylikness.com/signature.gif"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-78997103839003155942016-07-21T04:32:00.001-07:002016-07-21T04:36:12.365-07:00Back to the ngFuture<p>Angular 2.0 is close to production ready release. Initially the community was in an uproar over the lack of backwards compatibility, but that has changed in recent months with the release of version 1.5 and several modules including ngUpgrade. In this talk, Jeremy Likness discusses the differences between major production versions of Angular, the options for migrating your apps to 2.0, and demonstrates how to get your apps back into the future with the tools that are available today.</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmSR7ugSLgcqOTKD6wQfGAyCDzgETZqrGiuC0UZ8h_SlXOlYTvogC71WKXmAdYXPl-7x__-R32Hb2m-12caaD0jFd5B6kG1Q-LAbjRSIxOAcD3LneKCxt1qFomMPIJ9a9DDdaWYpTVEdO9/s1600/ng2future.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmSR7ugSLgcqOTKD6wQfGAyCDzgETZqrGiuC0UZ8h_SlXOlYTvogC71WKXmAdYXPl-7x__-R32Hb2m-12caaD0jFd5B6kG1Q-LAbjRSIxOAcD3LneKCxt1qFomMPIJ9a9DDdaWYpTVEdO9/s1600/ng2future.jpg" /></a></div>
<p>Special thanks to the <a href="https://www.meetup.com/ATL-AngularJS/events/230687241/" target="_blank">Atlanta AngularJS Meetup</a> group for hosting this event! You can view the deck here:
<p><iframe src="//www.slideshare.net/slideshow/embed_code/key/tMaYAXb49uWF2P" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/jeremylikness/back-to-the-ng2-future" title="Back to the ng2 Future" target="_blank">Back to the ng2 Future</a> </strong> from <strong><a href="//www.slideshare.net/jeremylikness" target="_blank">Jeremy Likness</a></strong> </div></p>
<p>You can also <a href="http://www.slideshare.net/jeremylikness/back-to-the-ng2-future" target="_blank">Visit the GitHub repository</a> to download the code examples or run them live in your browser.
<p>As a fun technology aside, here's a 360 degree photo I took with my <a href="http://amzn.to/29X1zrC" target="_blank">Samsung Gear 360</a> at the Ponce City Market in downtown Atlanta right before I presented the talk (click the photo to be able to view in 360 and use your mouse or phone to scroll around the view).
<p><iframe src="https://www.facebook.com/plugins/post.php?href=https%3A%2F%2Fwww.facebook.com%2Fphoto.php%3Ffbid%3D10209987814076928%26set%3Da.1262420925625.2039170.1382780282%26type%3D3&width=500" width="500" height="589" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowTransparency="true"></iframe>
<p>Enjoy!
<p><a href="http://jeremylikness.com/" title="Jeremy Likness"><img border="0" src="http://jeremylikness.com/signature.gif" alt="Jeremy Likness" title="Jeremy Likness"/></a><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-29577774064533975942016-06-29T04:34:00.000-07:002016-06-29T04:34:30.270-07:00Learn the Angular 2 CLI Inside and Out<div dir="ltr" style="text-align: left;" trbidi="on">
Angular 2 represents a major step in the evolution of modern web front-end frameworks,but it comes with a price. From TypeScript compilation to running test scripts,bundling JavaScript, and following the Angular 2 Style Guide, "ng2 developers" are faced with myriad problems to solve and challenges to
overcome.
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="http://developer.telerik.com/wp-content/uploads/2016/04/angular_boilerplate_header.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://developer.telerik.com/wp-content/uploads/2016/04/angular_boilerplate_header.jpg" style="width: 580px;" /></a></div>
Fortunately, there exists a way to simplify the process of building Angular 2 applications. Whether your goal is to stand up a rapid prototype or build an enterprise-ready line of business application that is continuously deployed to the cloud, the Angular CLI is a tool that you don't want to code without.
<p>
» Read the full article: <a href="http://developer.telerik.com/featured/rapid-cross-platform-development-angular-2-cli/" target="_blank">Rapid Cross-Platform Development with the Angular 2 CLI</a>
<p><a href="http://jeremylikness.com/" title="Jeremy Likness"><img alt="Jeremy Likness" border="0" src="http://jeremylikness.com/signature.gif" title="Jeremy Likness" /></a><br />
<br />
</div>
<div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-25544765534888143842016-05-17T12:00:00.000-07:002016-05-18T06:09:16.041-07:00Tic-Tac-Toe in Angular 2 and TypeScript<p>I’ve built a lot of small apps and games over the years, often to either learn a new framework or platform, or to help teach it. It’s always fun to dig up old code and migrate it to new technologies. For example, I took the Silverlight C# code to generate a plasma effect from my <a href="http://csharperimage.jeremylikness.com/2010/12/old-school-silverlight-effects.html" target="_blank">Old School app</a> and <a href="https://jsfiddle.net/jeremylikness/kfrpuj2m/" target="_blank">ported it to JavaScript</a> with optimizations. I also recently built a <a href="https://jsfiddle.net/jeremylikness/wL5yx14t/" target="_blank">bifurcation diagram</a> with ReactJs (RxJS) and <font face="Consolas">div</font> tags.</p> <p>The other day I reviewed some older projects and came across an article I wrote as an <a href="http://www.codeproject.com/KB/silverlight/tictactoe.aspx" target="_blank">introduction to Silverlight</a>. I used a tic-tac-toe game and built the logic to enable a computer opponent. </p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisHnyBqStuCeQJ4GPIHPdtvjE6FE_sAHUkAMscBWGB-qsxTI_Cnbr7h-4a0SCS3TFWOOsGyoYjKNbDeAXIbWFqVe1N3gu2toZbU7bllZY1Pi6KA6mQalkGeN9i8k80bVwFDCjkKgrMlIfs/s1600-h/tictactoe%255B5%255D"><img title="tictactoe" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="tictactoe" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiua5pXV8lWAl2Bwq3vgdJyroe1y0LpdXr2arTxJxt9vfYO7gOYciDOB8qlu-jhtk-IyYY8hen4nA1WlmQz2ujwR6l4BitSd5NAQ8SU46YbN6AXageddjnAlHNCWRV8pqlOqOeQV42KCeah/?imgmax=800" width="587" height="768"></a></p> <p>I realized this would be a perfect project for <a href="https://angular.io/" target="_blank">Angular 2</a> so I proceeded to make the port. You can <a href="http://jeremylikness.github.io/tic-tac-toe-ng2/" target="_blank">play it here</a> to test it out. I did not build it responsive (shame on me, being lazy) so I may refactor it in the future to make it easier to play on phones. Tablets and computers should be fine.</p> <h2>Scaffolding</h2> <p>To create my project I used a combination of cross-platform tools including <a href="http://code.visualstudio.com/" target="_blank">Visual Studio Code</a> and <a href="https://nodejs.org/" target="_blank">Node.js</a>. I also used the <a href="https://github.com/angular/angular-cli" target="_blank">Angular-CLI</a> for just about everything. The first step is get to a Node.js command prompt, then install the Angular CLI and initialize the project:</p> <p><font face="Consolas">npm i angular-cli –g<br>ng new tic-tac-toe-ng2<br>cd tic-tac-toe-ng2<br>ng serve</font></p> <p>By now I had a working project that I could navigate to, run unit tests against:</p> <p><font face="Consolas">ng test</font> </p> <p>…and even run an end-to-end set of tests:</p> <p><font face="Consolas">ng e2e</font> </p> <p>Great! Now to start porting the code! </p> <h2>Quotes</h2> <p>The original game had some wonky quotes that would show up in each tile that isn’t clicked yet. It would also give you a different, random quote if you tried to tap on a cell while it was the computer’s turn. We’ll get to the computer strategy in a bit (I built in a random delay for the computer to “think”). </p> <p>A reusable unit of JavaScript code in Angular 2 is referred to as a “service” and we scaffold it like this:</p> <p><font face="Consolas">ng g service quotes</font> </p> <p>This will generate the service and the specification (tests) for the service. One great feature of Angular is that it addresses testing right out of the box. </p> <p>I really didn’t have many specifications, other than making sure I get an actual string from the service and that multiple calls randomly return all available quotes .</p> <p>(Note: For the test, I iterate a large number of times to check the quotes, but technically it’s not a “good” test because you could randomly miss a quote and the test will fail even though the service is doing what it is supposed to).</p> <p><script src="https://gist.github.com/JeremyLikness/52d62a4e0646ecabe1b5d0b253cd8ae6.js"></script></p> <p>The service itself just randomly sorts an array each time a quote is requested and returns the first element.</p> <p><script src="https://gist.github.com/JeremyLikness/4064f27b72cffb6a8d21680d614fb74d.js"></script></p> <p>I repeated that pattern for the “bad quotes” (i.e. when you click out of turn) and then turned my attention to individual cells on the tic-tac-toe board. </p> <h2>Cell and Game States</h2> <p>Thinking about the game, I determined there would be exactly three states for a cell to be in: </p> <p><font face="Consolas">export enum State {<br> None = 0,<br> X = 1,<br> O = 2<br>}</font> <p>Either “not played” or marked with an ‘X’ or an ‘O’. I created an interface for the data of a cell to represent where it is on the grid, the current state, and whether it is part of a winning row. <p><font face="Consolas">export interface ICell {<br> row: number;<br> col: number;<br> state: State;<br> winningCell: boolean;<br>}</font> <p>Finally, the game flow will either allow a turn, or end in a win or a draw. <p><font face="Consolas">export enum GameState {<br> XTurn = 0,<br> OTurn = 1,<br> Won = 2,<br> Draw = 3<br>}</font> <p>With these in place, I then built the component for an individual cell. <h2>The Cell </h2> <p>To scaffold a component I used the following syntax:</p> <p><font face="Consolas">ng g component cell </font></p> <p>This created a sub-directory with the related files (CSS, HTML, code-behind and test). In the CSS <a href="https://github.com/JeremyLikness/tic-tac-toe-ng2/blob/master/src/app/cell/cell.component.css" target="_blank">you can see</a> the styles to define the size (sorry, this one isn’t responsive for now, but that can be readily fixed), margins, etc. </p> <p>Components have their own specifications. For example, one parameter that is input to the cell is the row and column. In the test, we create a test component that wraps the tested component, then verify the data-binding is working correctly (note the bindings in the template should match what is picked up by the component): </p> <p><script src="https://gist.github.com/JeremyLikness/1b8008fcd76a2433e09893c48a73b8f9.js"></script></p> <p>The “builder” is defined <a href="https://github.com/JeremyLikness/tic-tac-toe-ng2/blob/master/src/app/cell/cell.component.spec.ts" target="_blank">earlier in the source</a> and spins up the instance of the test controller to host the component. This is all generated for you by the command line interface.</p> <p>The cell itself takes several inputs, specifically the row, column, state, and whether it is a winning cell.</p> <p><script src="https://gist.github.com/JeremyLikness/b0157a1dad32fc055fcad5147e48c538.js"></script></p> <p>It also exposes an event when it is tapped. The template uses these to display either a random quote, an ‘X’, an ‘O’, and also color the background if the cell is part of a winning row.</p> <p><script src="https://gist.github.com/JeremyLikness/c98cea49acada9671276f488791655d6.js"></script></p> <p>The logic triggered when it is tapped checks to make sure it hasn’t already been set and whether it is a valid turn (the valid turn property is bound, so it can be set for testing or bound to other logic for the running application). If it is not the user’s turn, a random quote is set on the square to react to the tap. </p> <p>Another interesting behavior to note is the way the cell reacts to changes.</p> <p><script src="https://gist.github.com/JeremyLikness/21a279d4d6dcb699ea52989ac724c2e7.js"></script></p> <p>Components can implement the <font face="Consolas">OnChanges</font> interface that will fire when the model mutates. This is useful for responding to change without setting up individual watches (as was the case in Angular 1.x). Instead of using a timer to update quotes as I did in the old Silverlight app, I decided that I could just update the quotes randomly when changes occur. </p> <h2>The Matrix</h2> <blockquote> <p>“The Matrix is everywhere. It is all around us. Even now, in this very room … it is the world that has been pulled over your eyes to blind you from the truth.” – Morpheus</p></blockquote> <p>OK, the tic-tac-toe matrix isn’t quite as interesting. The matrix service is what manages the game state. The state machine for the game allows alternating between turns and ends at a draw or win. It is illustrated like this: </p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4l80mChPOBhyphenhyphen-MTCOQhnDLi1w8z7LNOzLhjhjCyVCAfvYTlpNlRIqSLTsMPzveCzMdTzOL1bAz1irWktui8K7czEypzoyieR3-4mkiUjZmiQiwh8ROOCLUXz_txGdRJRDjLsg32jri8MZ/s1600-h/tictacstate%25255B4%25255D.png"><img title="tictacstate" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="tictacstate" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3xuAL4Zcg0c2IoYCS3egValnbU4VHEUnI4mDpeKpxVOHtleIPueeSNYtrh07fxiMmnovK5IPj5kQXtadyWffvaB_eGGR_Hv9Tyl6iEQoLTRr3EWfkROLDT26HHMyEYUngginYMRu1HaP2/?imgmax=800" width="580" height="682"></a></p> <p>This is captured through the <a href="https://github.com/JeremyLikness/tic-tac-toe-ng2/blob/master/src/app/matrix.service.spec.ts" target="_blank">specifications for the matrix service</a>. The service itself builds up a list of “winning rows” to make it easy to determine if a given row is a draw, a winning row, or still has open slots. </p> <p>Each time the state changes, the logic first checks to see if the game was won and whether the computer or the user won it: </p> <p><script src="https://gist.github.com/JeremyLikness/0fd44c6f8578b15d4e9a4683dc1e610a.js"></script></p> <p>Next, it checks to see if any slots are available. This is the “dumb logic” for a draw. I could have eliminated this code as it was the first pass at the algorithm, but I decided a two phase would be fine to illustrate as the second pass does a more intelligent look “row-by-row”. If it’s not a draw, it switches to the next turn.</p> <p><script src="https://gist.github.com/JeremyLikness/0d5c68e9eb20e779b60b764346236108.js"></script></p> <p>The main component binds to the matrix service and uses this to drive the state of the individual cells. </p> <h2>Strategies </h2> <p>To drive the computer’s moves, I created two strategies. The first strategy is a simple one and simply picks a random empty cell for the computer move. Notice it is a simple function that is exported. </p> <p><script src="https://gist.github.com/JeremyLikness/e411f82fa9e346946123bdf7bc498415.js"></script></p> <p>For the hard strategy, I devised a simple algorithm. Each row is assigned a point value based on the state of the row. The point values are listed here: </p> <ul> <li>Row is a draw (one from each) – 0 points <li>Row is empty – 1 point <li>Row has one of theirs – 10 points <li>Row has one of mine – 50 points <li>Row has two of theirs – 100 points <li>Row has two of mine – 1000 points </li></ul> <p>This is an aggressive (not defensive) strategy because there are more points assigned to building up a winning row than blocking the opponent’s. Each empty cell is assigned a weight based on the sum of all intersecting rows, and then the highest weighted cell wins. Here is a visualization where the computer is “O”: </p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLwQ_bwuV-i1bVggLfl6V2yP5k0I_QYR02EizBI98BWVKQvsAth9Zib0JkCShVGAV4kpP_VUsKPUNja5tlIrd3p6dVccgUcXOmuvd2_UNqxsXLgCUTfdqfBQnh5asFMUDtCi7liyw9K7l3/s1600-h/tictacstrategy%25255B4%25255D.png"><img title="tictacstrategy" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="tictacstrategy" src="https://lh3.googleusercontent.com/-JX66ST1ZBoQ/VzttAJrjwSI/AAAAAAAADtE/0JilKiZIlKU/tictacstrategy_thumb%25255B2%25255D.png?imgmax=800" width="256" height="305"></a></p> <p>The top grid shows the row values (first and last columns on the top represent the diagonals) and the bottom grid shows the computed values for the cell. Note the highest score is the cell that will win the game.</p> <p>The logic is encapsulated in the <a href="https://github.com/JeremyLikness/tic-tac-toe-ng2/blob/master/src/app/strategy-hard.ts" target="_blank">hard strategy function</a>. The pseudo-code follows: </p> <ol> <li>Create a matrix of cell ranks <li>Iterate each row. If the cell is occupied, set it’s weight to a negative value. <li>Sum the count of X and O values for the row. <li>Update the cell’s weight based on the logic described earlier. <li>Sort by weight. <li>Create a short array of the cells with the highest weight (in case multiple cells “tie”) <li>Pick a cell and populate it.</li></ol> <p>That’s it – a simple strategy that works well. </p> <h2>Putting it All Together</h2> <p>The <a href="https://github.com/JeremyLikness/tic-tac-toe-ng2/blob/master/src/app/tic-tac-toe-ng2.component.ts" target="_blank">main component</a> orchestrates everything. A flag is synchronized with the strategy service to run the selected algorithm, and the matrix is consulted for the first turn. (Note the <font face="Consolas">MatrixService</font> is bootstrapped with the main component so the same copy is available throughout). </p> <p>On initialization, it is determined whether the component is running with a “slow computer.” This is the default and uses a timeout to emulate time for the computer to decide it’s next move. It makes for more realistic gameplay. When set to false, the statements execute immediately to make it easier for <a href="https://github.com/JeremyLikness/tic-tac-toe-ng2/blob/master/src/app/tic-tac-toe-ng2.component.spec.ts" target="_blank">testing</a>.</p> <p>The remaining methods simply check for the game state and pass it through to properties on the component for data-binding, and advance the state. The user is responsible for tapping a cell to trigger their move. This is handled by the <font face="Consolas">stateChange</font> method: </p> <p><script src="https://gist.github.com/JeremyLikness/c7e9250c3661dc180d5dcfae07b3a5cf.js"></script></p> <p>The template the generates the cells iterates through the grid and binds the cell attributes to each <font face="Consolas">CellComponent</font>: </p> <p><script src="https://gist.github.com/JeremyLikness/3d576aa9e8c5868592fc769610fa5e69.js"></script></p> <p>The <font face="Consolas">updateStats</font> method queries the matrix to determine the game state. If it is the computer's turn, the <font face="Consolas">computerMove</font> method is called. This simply calls the strategy service to make the next move and passes control back to the user. That's pretty much it!<p><b>Bonus Opportunity</b>: if you like challenges, the AI in this is not perfect. You can take on a two-part challenge. First, the computer is absolutely beatable when you have the first turn. If you solve it, comment here and let us know the solution! My only hint is that it does not start with placing an X in the middle. Second, once you've done that, is there a better algorithm that can beat the winning strategy? <p>You can view the entire project (along with projects to install and run it locally) at the <a href="https://github.com/JeremyLikness/tic-tac-toe-ng2/" target="_blank">tic-tac-toe-ng2 repository</a>. I hope this helps illustrate building applications with Angular 2 and TypeScript using the Angular Command Line interface. </p> <p>Please share your thoughts and comments below, and if you get bored, <a href="http://jeremylikness.github.io/tic-tac-toe-ng2/" target="_blank">play some tic-tac-toe</a>!</p> <p>Until next time,</p> <p><img style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; padding-right: 0px" border="0" src="http://jeremylikness.com/signature.gif"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-57731367481026638172016-05-17T05:12:00.002-07:002016-05-23T16:54:44.319-07:00The Angular 2 CLI and TypeScript<p>AngularJS is the incredibly popular framework for building single-page web applications. Version 2.0 is a major leap from the 1.x version designed to address shortcomings in the original 5+ year old framework and to embrace modern browsers and language features. It is being written using TypeScript, a superset of JavaScript that allows you to build code using next generation features and compile it to JavaScript that will run on current browsers. Visual Studio Code is the perfect platform to explore Angular applications because it is free, open source, and cross-platform and supports advanced features such as extensions, code completion and IntelliSense. In this session Jeremy Likness goes hands-on to show you how to set up your environment and build your first application while teaching you about the advantages of the framework and language based on his years of in-the-field experience architecting enterprise Angular applications.</p>
<p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwVuxRhGzHbTHEwjClHVjXXrdVOOr3EtvA43aAi1ERLikapV-J_C5YqXgIMtpUHymez2Izan4hlJ3dTo_BN1Gku4XAZsYFunV4FaxJM5j73uVY2uLWHm1RWHXg5fHJNJ0oNkYIpvLQhIUY/s1600/ng2clitalk.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwVuxRhGzHbTHEwjClHVjXXrdVOOr3EtvA43aAi1ERLikapV-J_C5YqXgIMtpUHymez2Izan4hlJ3dTo_BN1Gku4XAZsYFunV4FaxJM5j73uVY2uLWHm1RWHXg5fHJNJ0oNkYIpvLQhIUY/s1600/ng2clitalk.jpg" style="width: 550px;"/></a></div>
<p>In this talk I focused on scaffolding the app using the <a href="https://github.com/angular/angular-cli" target="_blank">Angular-CLI</a> to rapidly build a reference app. Here is the video:</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/8GX5gKiLLfU" frameborder="0" allowfullscreen></iframe></p>
<p>The deck has most references, and stay tuned for a new post that will go into more detail with building a tic-tac-toe game with a computer opponent! Here is the deck:</p>
<iframe src="//www.slideshare.net/slideshow/embed_code/key/KOEeFAHAhBFpM0" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/jeremylikness/the-angularcli-for-angular-2-and-typescript" title="The Angular-CLI for Angular 2 and TypeScript" target="_blank">The Angular-CLI for Angular 2 and TypeScript</a> </strong> from <strong><a href="//www.slideshare.net/jeremylikness" target="_blank">Jeremy Likness</a></strong> </div>
<p><a href="http://jeremylikness.com/" title="Jeremy Likness"><img border="0" src="http://jeremylikness.com/signature.gif" alt="Jeremy Likness" title="Jeremy Likness"/></a><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-59851019654991418192016-04-24T08:31:00.001-07:002016-04-24T08:31:19.518-07:00The Three D’s of Modern Web Development<p>Modern web development using JavaScript has evolved over the past decade to embrace patterns and good practices that are implemented through various libraries and frameworks. Although it is easy to get caught up in the excitement of frameworks like <a href="http://angular.org/">AngularJS</a> or the <a href="http://docs.telerik.com/kendo-ui/framework/mvvm/overview">KendoUI implementation of MVVM</a> (that’s Model-View-ViewModel, which I’ll explain more about in an upcoming article), it is important to remember the fundamental patterns and repeatable practices that make development easier. In fact, it is difficult to make a qualified decision about your development stack without understanding “how” and “why” a particular tool, library, or framework may benefit the application and, more importantly, your team.</p> <p>I recently authored a series of articles for the <a href="http://developer.telerik.com" target="_blank">Telerik Developer Network</a> that covers what I believe are three fundamental concepts that have revolutionized modern web app development.</p> <p>You can read the series here:</p> <ol> <li><a href="http://developer.telerik.com/featured/three-ds-of-web-development-1-declarative-vs-imperative/" target="_blank">Declarative vs. Imperative</a></li> <li><a href="http://developer.telerik.com/featured/three-ds-of-web-development-data-binding/" target="_blank">Data-Binding</a></li> <li><a href="http://developer.telerik.com/featured/three-ds-web-development-3-dependency-injection/" target="_blank">Dependency Injection</a></li></ol> <p>The three D’s are just a few of the reasons why JavaScript development drives so many consumer and enterprise experiences today. Although the main point of this series was to demonstrate the maturity of front-end development and the reason why JavaScript development at enterprise scale is both relevant and feasible today, it is also the answer to a question I often receive. “Why use Angular 2 and TypeScript?” My answer is this: together, Angular and TypeScript provide a modern, fast, and practical implementation of the three D’s of modern web development.</p> <p>Regards,</p> <p><img style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; padding-right: 0px" border="0" src="http://jeremylikness.com/signature.gif"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-84963711288165231372016-03-23T16:39:00.001-07:002016-03-24T04:31:47.035-07:00TypeScript 1.8 to Future-Proof JavaScript Apps<p>There is no denying the trend to deliver critical business apps through the browser using Single Page Application frameworks that rely heavily on JavaScript. Traditionally frowned upon as a loosely typed language not fit for large scale development or teams, JavaScript is rapidly evolving with the latest ECMAScript 2015/6 specifications. TypeScript is a technology that can help teams future proof their applications and build them at scale. </p> <p>By serving as a superset of JavaScript and enabling definition files to describe existing JavaScript libraries, TypeScript can be integrated seamlessly into existing projects. It provides syntax that aligns with the current specifications and will compile to various versions of JavaScript and leverage different libraries that provide module support. Learn how TypeScript improves the development experience by providing development and compile-time checks, type safety, interfaces, true class inheritance, and other features that accelerate delivery and improve the quality and stability of Single Page Applications.</p> <p>Watch the full video from a recent webinar I gave with <a href="http://kliant.com/" target="_blank">Kliant</a> covering TypeScript 1.8: </p>
<p><video controls="controls" height="345" width="615" poster="https://lh3.googleusercontent.com/-AQFiIB4Yix4/VvMod2hchjI/AAAAAAAADBs/or1iDsvCmmo/typescript_thumb%25255B1%25255D.png?imgmax=800">
<source src="http://kliant.com/assets/files/2016-03-22_11.06_Webinar_with_Jeremy_Likness_-_TypeScript_to_Future_Proof_Enterprise_JavaScript_Apps_at_Scale.mp4" type="video/mp4">
</video></p> <p>You can download the code examples and deck <a href="https://github.com/jeremylikness/TypeScript2016Prez" target="_blank">here</a>.</p> <p>Until next time,</p> <p><img style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; padding-right: 0px" border="0" src="http://jeremylikness.com/signature.gif"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-67277109174285085672016-03-19T14:44:00.000-07:002016-03-20T08:41:55.776-07:00Lessons Learned (Re) Writing a 6502 Emulator in TypeScript with Angular 2 and RxJs<p>In preparation for an upcoming webinar I decided to build a sizeable Angular 2 project. I’ve always been <a href="http://csharperimage.jeremylikness.com/2013/07/30-years-of-hello-world.html" target="_blank">fascinated with the Commodore 64</a> and the 6502 chipset is not a tough one to emulate. I also wrote it the first time several years back, so I had a good baseline of code to draw from. Thus the <a href="https://github.com/JeremyLikness/6502emulator" target="_blank">Angular 2 6502 emulator</a> was born.</p> <p><a href="https://lh3.googleusercontent.com/-IQZBFh8jt4o/Vu3IAyEcn6I/AAAAAAAADAQ/xDoCpLal8ecYYbQuGi6fd7uoO49kPOsPgCHM/s1600-h/screenshot%255B6%255D"><img title="screenshot" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="screenshot" src="https://lh3.googleusercontent.com/-9TWPW3GMEH4/Vu3IBN0r9LI/AAAAAAAADAU/xQg4TQiHtnI1_z4qXUsSw7bJxqvzVLNFwCHM/screenshot_thumb%255B4%255D?imgmax=800" width="614" height="410"></a></p> <p>Want to see it in action? <a href="http://apps.jeremylikness.com/apps/6502ng2/" target="_blank">Here is the running version</a>.<p><strong>Building a Console that Works</strong></p> <p>The first thing I needed was a decent console to give information to the user. The console itself isn’t too difficult. A service holds an array of strings, splices them when it gets beyond a certain size, and exposes a method to clear them. </p> <p>Here is the basic code:</p> <p><script src="https://gist.github.com/JeremyLikness/e402370ae7a57a03723c.js"></script></p> <p>Now you may notice there is a new class (to some) for notifying subscribers when a console message is sent. Angular 2 relies heavily on <a href="https://github.com/Reactive-Extensions/RxJS" target="_blank">Reactive Extensions for JavaScript (RxJS)</a>. </p> <p><strong>RxJS</strong></p> <p>In a nutshell, this library provides a different mechanism for dealing with asynchronous workflows and streams. You essentially end up observing a collection and are handed off “items” like an iterator and then can deal with it as you choose. </p> <p>You can see that emitting an event is easy, but what does it look like consuming it? </p> <p><strong>Interacting with the DOM</strong></p> <p>The component for the console simply data-binds the console messages to a bunch of text contained inside of a div element. If that’s all it had to do there would be no need for an event emitter. Unfortunately because new items are appended at the bottom, the div can quickly fill up with scroll bars and new messages are no longer in view.</p> <p>Fixing this is simple. First, the component needs to know when the contents of the div may have changed (via the event fired from the service). Second, it simply needs to interact with the DOM element so it can scroll into view. </p> <p>How do we reference the element associated with an Angular component? Take a look at this source:</p> <p><script src="https://gist.github.com/JeremyLikness/3b546c84693e9854b0f7.js"></script></p> <p>There are just two steps needed to reference the element. First, import the ElementRef class. Second, include it on the constructor so it is injected. You probably noticed that the component doesn’t do anything with it in the constructor. This is because the constructor is called before the UI has been wired up and rendered, so there is nothing inside of the element. </p> <p>So how do you know when the element is ready?</p> <p><strong>Angular 2 Lifecycle</strong></p> <p>Angular 2 components have a lifecycle and if certain methods are present, they are called during a specific phase. I provided a <a href="http://jeremylikness.github.io/Ng2TypeScriptPrez/#slide-14" target="_blank">high level list</a> at an Angular 2 talk I gave. In this case, the component implements a method that is called after the view is initialized. Once initialized, it’s possible to grab the child div because it’s rendered. </p> <p>A nice feature of TypeScript is auto-completion and documentation. By casting the element to the HTMLDivElement type I get a clearly typed list of APIs available for that element. The component subscribes to the console events (notice it uses a de-bounce rate of 100ms so if a ton of messages are sent at once, it will still only fire 10 times a second to avoid locking the UI). When the event fires, a property on the div is set and that will force it to scroll to the most recent message.</p> <p>A similar lifecycle method is used in the main app to indicate everything is initialized.</p> <p><strong>Creating the Display</strong></p> <p>The next challenge was creating a graphical display. I decided to implement the emulator using a memory-mapped, palette-based display. This means a block of memory is reserved to represent “pixels” of the display, and when a value is set on a specific address, the number corresponds to a palette entry of red, green and blue values. </p> <p>If you’re curious you can see the code for the algorithm I use to <a href="https://github.com/JeremyLikness/6502emulator/blob/master/app/emulator/palette.ts" target="_blank">generate the palette</a>. It basically builds up a distinct set of red, green, and blue values and then sorts them based on their luminosity based on a well known equation. Each item has a hexadecimal rendition and the last five palette slots are manually built as shades of gray. </p> <p>The display service simply keeps track of a pixel buffer that represents the display, then makes a callback to the component when a value changes. </p> <p><script src="https://gist.github.com/JeremyLikness/7708a43a228112cbf0e0.js"></script></p> <p>The <a href="https://github.com/JeremyLikness/6502emulator/blob/master/app/components/display.ts" target="_blank">display component</a> is a little more involved. It holds an array of values that represent rectangles that will be drawn as a “pixel.” These are literally scalable vector graphics-based rectangles inside an svg element. The entries hold x and y offsets from the upper corner of the display, the width and height (you can adjust this if you like), and the current fill color for that pixel. </p> <p>The component sets a callback on the display service to be notified of any changes. In this case, a callback is used because it is up to 50x faster than using an event emitter (I tested this). The callback ensures the request is in the valid range of memory and is a byte of data, then cross-references the palette to set the proper fill value. </p> <p>Finally, this is all rendered by Angular as an array of rectangles. Angular’s dirty tracking will check when the fill is updated and update the attribute. Here is the HTML for the display:</p> <p><script src="https://gist.github.com/JeremyLikness/0065afcfc3da25916b9b.js"></script></p> <p><strong>The CPU State</strong></p> <p>The <a href="https://github.com/JeremyLikness/6502emulator/blob/master/app/emulator/cpu.ts" target="_blank">emulator CPU</a> provides the simplest possible mechanism for emulating the operation of instructions. It contains the memory registers, the stack, a program counter (the area of memory that the next machine instruction will be read from), and tracks things like how many instructions per second it is able to execute. </p> <p>I decided to take a straightforward approach, and have the CPU manage memory, registers, stack, and program counter but create “self-aware” operation classes that would actually “do work.” </p> <p>For that reason the CPU itself doesn’t have any logic like loading or adding accumulators. Instead, it knows how to look at memory, update memory (including triggering a call to the display service), set and reset flags, pop addresses and handle various modes for addressing memory. </p> <p>It has instructions to run, step through code line-by-line for the debug mode, and can be halted. When halted or in an error state, the only recovery is to reset it. Basically the workflow for the cpu is to look at the operation at the program counter, ask it to execute itself, then update the program counter and grab the next instruction.</p> <p>The executeBatch() function is where I did most of the optimization. Running the program until it stops would lock the UI, and running a single instruction per event loop was slow. The CPU therefore compromises by running up to 255 instructions before it uses setTimeout to allow other events to queue.</p> <p>(This is an area where using animation frames might make sense, but I haven’t explored that avenue yet). </p> <p>Angular 1.x users will note I can call setTimeout directly and not rely on a <a href="https://docs.angularjs.org/api/ng/service/$timeout#!" target="_blank">$timeout</a> service. Angular 2 is able to detect when I’ve modified the data model even from within an asynchronous function due to the magic of <a href="https://github.com/angular/zone.js" target="_blank">ZoneJS</a>. </p> <p><strong>Loading Op Codes</strong></p> <p>An operation is fairly simple. It exposes how it handles addresses, the numeric value of the instruction, the name, how many bytes the instruction and any parameters take up, and can compile itself to text. </p> <p>There is an execute method that uses the CPU to do work. </p> <p>Operation codes derive from a base class: </p> <p><script src="https://gist.github.com/JeremyLikness/47a5f9c8c8c51654799b.js"></script></p> <p>And then implement themselves like this:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjG2sSgde9v3UuI1UEfe1e-PjxZQFAA4lE2dtqw7xtaCw_k9gNgy6xxuTeol8iZH29-SBqFDvbQsqDaxVaC4z2IMyQHqbhozODa7ns2VasB-gUITZck_I2joB074CjkoUAZPdDh6m7VzdVc/s1600-h/opcode%25255B5%25255D.png"><img title="opcode" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="opcode" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcTSwOtyRq0TtJQgHFI659VT6sD-2g8i38L2QIATyRJXkMo8bd77_S276OChStrA7FhwGhPNwpLZSZPvTJ9HtEDRtZ3sEirOpew4SatwAFX1zu-TeRQpigPvCiCQ6FtfICQdk_xNOtdjoO/?imgmax=800" width="377" height="145"></a></p> <p>The example snippet is an operation that adds a value to the accumulator (a special memory register) with a value. It will set the carry bit if there is an overflow, and it is in immediate mode which means the byte after the instruction contains the value to add (as opposed to obtaining it from a memory location, for example). When executed, it uses the utility methods on the OpCodes class to add with carry and passes in the instance of the cpu and the address it is at. </p> <p>The OpCodes utility will pop the instruction, inspect the address mode, pull the value, perform the add, and update the program counter with the cpu’s help. </p> <p>Because each operation has multiple addressing modes, and there is one class per combination of op code and address mode, there end up being several hundred classes. This presents a challenge from the perspective of wiring up the op codes into an array unless they “self-register.” In my original emulator, that’s exactly what they did, but with modern TypeScript there’s an even better way!</p> <p><strong>TypeScript Decorators</strong></p> <p>TypeScript decorators are heavily used by Angular 2. I decided to create one of my own. First, I created an array of operations to export and make available to the CPU, compiler, and other components that need it. Next, I created a function to serve as a class decorator. It simply takes the target (which is the class, or more precisely the function constructor) then creates the instance and stores it in an array. </p> <p>With that simple step, because the signature is correct, I can now use that function as a decorator and simply adorn each class that should register as an op code with the @IsOpCode attribute. </p> <p><a href="https://github.com/JeremyLikness/6502emulator/blob/master/app/emulator/opCodes.ts" target="_blank">Take a look</a> and see for yourself! Now when I implement the other op codes I haven’t finished yet, they will be automatically registered if I decorate them. </p> <p><strong>The Compiler</strong></p> <p>Aside from the individual op code definitions, the most logic exists in the <a href="https://github.com/JeremyLikness/6502emulator/blob/master/app/emulator/compiler.ts" target="_blank">compiler class</a>. This is because it is a full two-pass assembly compiler that parses labels and handles both decimal and hexadecimal entries as well as label addition and memory syntax. </p> <p>The compiler has to be able to take a pass and lay out how much memory each instruction takes so it can assign memory addresses to labels, then use that for “label math” (when the programmer adds or subtracts and offset from a label), then parse the code and get the instructions and memory addresses written out correctly. </p> <p>Needless to say, a lot of regular expressions are involved. You can look at the source code linked earlier to see how I used interfaces and broke the compiler steps into methods to make it easier to organize all of the steps required. </p> <p><strong>The CPU Display </strong></p> <p>The CPU was the easiest component to build. It simply exposes the CPU service:</p> <p><script src="https://gist.github.com/JeremyLikness/9ecffda9936a217ec3a7.js"></script></p> <p>And then binds to values and cpu methods directly:</p> <p><script src="https://gist.github.com/JeremyLikness/de99ff99f0933f535f94.js"></script></p> <p>There is a compiler component that interacts with the compiler class, and uses forms to collect data. If you go beyond straight data-binding, forms are actually quite interesting.</p> <p><strong>Forms in Angular 2</strong></p> <p>The <a href="https://github.com/JeremyLikness/6502emulator/blob/master/app/components/compiler.ts" target="_blank">compiler component</a> uses Angular 2’s form builder to expose the form for entering code, loading code, and setting the program counter. The form builder is used to create a group of controls. Each has a name, an initial value, and a set of validators. In the case of the program counter, a “required” validator is combined with a customer validator that parses to ensure it is a valid hexadecimal address. </p> <p>You can see that in the “pcValidator” method. Passed validations return null, failed return … well, whatever you want <em>except</em> null. I reference the control group to create individual references for each control, so I can use the value of the control for compiling, setting the program counter, etc.</p> <p>The controls have their own method to update values (such as loading the decompiled code into the corresponding control). I also use it to load source code for some of the pre-built programs I included. Unlike Angular 1.x, the Http service uses RxJS to return its results.</p> <p><strong>HTTP in Angular 2</strong></p> <p>There are a few steps to interact with HTTP in Angular 2 apps. First, you must include a JavaScript file if you are using bundles and not loading all of Angular 2 at once. In your <a href="https://github.com/JeremyLikness/6502emulator/blob/master/app/app.ts" target="_blank">app bootstrapper</a> you’ll want to import HTTP_PROVIDERS and bootstrap them. </p> <p>The component will import Http and should also import the Rx library to handle the special observable results. After that, it’s fairly straightforward. </p> <p>The get call is issued and returns an observable that you can begin chaining methods onto. In this example, I’ve mapped the result to text (I’m not getting a JSON object but the entire contents of a text file) and then I subscribe. </p> <p>The subscription has methods for when the next item appears, when an exception is thrown, and when the observable stream reaches the end. I leverage this to grab the loaded data and set it onto the control and then send a console message when it’s loaded. </p> <p><strong>The Final Results</strong></p> <p>After everything is said and done I was very pleased with how quickly I was able to leverage the existing code and migrate it to Angular 2 and the more current version of TypeScript. A few things I noted along the way: </p> <ul> <li>Dynamic static properties like arrays aren’t really a good idea in the modular/asynchronous world – instead of having a static array for the op codes, I made an instance and exported it so it could be imported by other modules</li> <li>Interfaces are useful for annotations but not very useful for dependency injection in Angular 2 – I found if I didn’t want to use magic strings, I had to still reference the implementation and use the @Inject decorator to make it work if I wanted to declare variables by their interface type </li> <li>Performance surprised me (in a good way) </li></ul> <p>I’d like to elaborate on that last bullet. In the original implementation, I had a display service that explicitly held an array of svg elements and set the fill attribute on them directly when a value changed. With the Angular 2 version, I rely completely on Angular’s dirty tracking and let Angular re-render the element (or set the attribute) when the values change. Despite that difference, the improved data-binding is incredible and the new app keeps pace with the old one based on instructions per second. </p> <p>Over all it was a great and fun experience. I still have some op codes to add to the mix and my <a href="https://en.wikipedia.org/wiki/Binary-coded_decimal" target="_blank">binary coded decimal (BDC)</a> mode is broken, so if you want to tinker, <em>I do accept pull requests.</em> </p> <p>Until next time, </p> <p><img style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; padding-right: 0px" border="0" src="http://jeremylikness.com/signature.gif"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-34697588099096681052016-03-15T04:08:00.001-07:002016-03-16T05:25:08.081-07:00Angular 2 Change Detection and HTTP Services, ASP.NET Core Authentication, VS 2005 End of Life on Tue Mar 15 2016<p>Understand change detection in Angular 2, look at authentication in the cross-platform ASP.NET Core, sign up for a webinar to discuss the changes to .NET and understand how to create specialized HTTP services in Angular 2.</p> <ul> <li>Video: <a href="https://twitter.com/hashtag/Angular2?src=hash"><s>#</s><b>Angular2</b></a> change detection explained <a href="https://t.co/CvCrwjOjAi">http://ow.ly/ZqwMl </a><a href="https://twitter.com/hashtag/AngularJS?src=hash"><s>#</s><b>AngularJS</b></a> <a href="https://twitter.com/hashtag/NG2?src=hash"><s>#</s><b>NG2</b></a></li> <li>Video: first look at authentication in <a href="https://twitter.com/hashtag/ASPNET?src=hash"><s>#</s><b>ASPNET</b></a> <a href="https://twitter.com/hashtag/Core?src=hash"><s>#</s><b>Core</b></a> <a href="http://ow.ly/Zqwrl ">http://ow.ly/Zqwrl </a></li> <li>Join us for a <a href="https://twitter.com/hashtag/Telerik?src=hash"><s>#</s><b>Telerik</b></a> webinar on Apr 5th as <a href="https://twitter.com/jeremylikness"><s>@</s><b>jeremylikness</b></a> & I discuss the modern <a href="https://twitter.com/hashtag/ASPNet?src=hash"><s>#</s><b>ASPNet</b></a> tech stack .. <a href="https://t.co/wJj1YrzmNU">http://www.telerik.com/campaigns/devcraft/choosing-the-right-tech-stack …</a>. <a href="https://twitter.com/hashtag/FunTimes?src=hash"><s>#</s><b>FunTimes</b></a></li> <li>Perspective: support ending for <a href="https://twitter.com/hashtag/VisualStudio?src=hash"><s>#</s><b>VisualStudio</b></a> 2005 <a href="https://t.co/rf0GTSJc4p">http://ow.ly/Zqw9P </a>released before <a href="https://twitter.com/hashtag/Twitter?src=hash"><s>#</s><b>Twitter</b></a>, <a href="https://twitter.com/hashtag/jQuery?src=hash"><s>#</s><b>jQuery</b></a>, or even <a href="https://twitter.com/hashtag/XBox?src=hash"><s>#</s><b>XBox</b></a> (360) existed</li></ul> <p><blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">Creating specialized <a href="https://twitter.com/hashtag/Http?src=hash">#Http</a> clients in <a href="https://twitter.com/hashtag/Angular2?src=hash">#Angular2</a> <a href="https://t.co/s84usMSCu7">https://t.co/s84usMSCu7</a> <a href="https://twitter.com/hashtag/AngularJS?src=hash">#AngularJS</a> <a href="https://twitter.com/hashtag/NG2?src=hash">#NG2</a></p>— Jeremy Likness (@jeremylikness) <a href="https://twitter.com/jeremylikness/status/709362230752575490">March 14, 2016</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p> <p>Until next time,</p> <p><img style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; padding-right: 0px" border="0" src="http://jeremylikness.com/signature.gif"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-62922727752930038422016-03-09T05:15:00.001-08:002016-03-16T05:25:16.998-07:00Angular NG2, NodeJS on Raspberry Pi, Skype Collaboration and JavaScript on Wed Mar 9 2016<p>Angular 2 run blocks, a new level of collaboration, NodeJS on Raspberry Pi and a proposal for weak references in JavaScript.</p> <ul> <li>Creating a "run block" in <a href="https://twitter.com/hashtag/Angular2?src=hash"><s>#</s><b>Angular2</b></a> <a href="https://twitter.com/hashtag/AngularJS?src=hash"><s>#</s><b>AngularJS</b></a> 2 <a href="https://t.co/CqbvJlSrtn">http://ow.ly/ZcGVg </a><a href="https://twitter.com/hashtag/NG2?src=hash"><s>#</s><b>NG2</b></a> <li>Collaborate using <a href="https://twitter.com/hashtag/Skype?src=hash"><s>#</s><b>Skype</b></a> on <a href="https://twitter.com/hashtag/o365?src=hash"><s>#</s><b>o365</b></a> <a href="https://twitter.com/hashtag/office365?src=hash"><s>#</s><b>office365</b></a> and <a href="https://twitter.com/hashtag/oneDrive?src=hash"><s>#</s><b>oneDrive</b></a> <a href="http://ow.ly/ZcHaT ">http://ow.ly/ZcHaT </a> <li>The beginner's guide to installing <a href="https://twitter.com/hashtag/NodeJS?src=hash"><s>#</s><b>NodeJS</b></a> on a <a href="https://twitter.com/hashtag/RaspberryPi?src=hash"><s>#</s><b>RaspberryPi</b></a> <a href="http://ow.ly/ZcHLT ">http://ow.ly/ZcHLT </a></li></ul> <p> <blockquote class="twitter-tweet" data-lang="en"> <p lang="en" dir="ltr">The <a href="https://twitter.com/hashtag/JavaScript?src=hash">#JavaScript</a> proposal for ... weak references? <a href="https://t.co/iQyaQUg29c">https://t.co/iQyaQUg29c</a></p>— Jeremy Likness (@jeremylikness) <a href="https://twitter.com/jeremylikness/status/707295246930059265">March 8, 2016</a></blockquote><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script> <p>Until next time,</p> <p><img style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; padding-right: 0px; border-top-width: 0px" border="0" src="http://jeremylikness.com/signature.gif"></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.comtag:blogger.com,1999:blog-8944256652433533647.post-61856096888386973022016-02-28T15:46:00.000-08:002017-12-07T07:23:01.407-08:0030 Years of “Hello, World”<p>This post has moved! View the more recent version <a href="https://blog.jeremylikness.com/30-years-of-hello-world-6f2982d8ee83">here</a></p>
<p><a href="https://blog.jeremylikness.com/30-years-of-hello-world-6f2982d8ee83">https://blog.jeremylikness.com/30-years-of-hello-world-6f2982d8ee83</a></p><div class="blogger-post-footer">(c) 2011-2019 Jeremy Likness.</div>Jeremy Liknesshttp://www.blogger.com/profile/18407945801671553594noreply@blogger.com