Harvey Ramer - Florida-based Web DeveloperHarvey enjoys creating web applications with React, Node.js, and MongoDB. He writes about how worldviews, technology, business and relationship differences can become a collaborative asset.2023-05-22T00:00:00Zhttps://www.harveyramer.com/Harvey Ramerharvey@harveyramer.com
Installing the Azure CLI on the Linux Subsystem in Windows 11
2023-05-22T00:00:00Zhttps://www.harveyramer.com/article/azure-cli-windows-11-linux-subsystem/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706042280/azure-cli-windows-11-linux-subsystem.png" alt="azure-cli-windows-11-linux-subsystem" /></p>
<p>I recently obtained a Windows 11 laptop and immediately gravitated towards the powerful Windows Subsystem for Linux available through the command prompt. I have always preferred the Linux CLI and the open source tools available there over the Windows PowerShell ecosystem, and access to a Linux CLI within Windows is a huge win! We can configure our Azure development environment with ease via the Ubuntu CLI.</p>
<p>To access the Linux CLI in Windows 11, you may first need to install it. Thankfully, they’ve made this easy as well! Open a command prompt as an administrator and enter this command:</p>
<pre><code>wsl --install
</code></pre>
<p>When the subsystem finishes installing, you will be asked to restart your computer. At some point in the process, you will be asked to choose a password for your Linux machine. Don’t forget to save that password for reference! I prefer 1Password as a system for keeping my credentials safe.</p>
<h2>Customize Your Linux Distribution (If You Must)</h2>
<p>The default Linux OS is Ubuntu, which I kept. If you have a preference for another Linux distribution, you can specify it when installing WSL. To see the available distributions, run the command below in Windows Powershell.</p>
<pre><code>PS C:\Users\linuxguy> wsl -l -o
The following is a list of valid distributions that can be installed.
Install using 'wsl.exe --install <Distro>'.
NAME FRIENDLY NAME
Ubuntu Ubuntu
Debian Debian GNU/Linux
kali-linux Kali Linux Rolling
Ubuntu-18.04 Ubuntu 18.04 LTS
Ubuntu-20.04 Ubuntu 20.04 LTS
Ubuntu-22.04 Ubuntu 22.04 LTS
OracleLinux_7_9 Oracle Linux 7.9
OracleLinux_8_7 Oracle Linux 8.7
OracleLinux_9_1 Oracle Linux 9.1
SUSE-Linux-Enterprise-Server-15-SP4 SUSE Linux Enterprise Server 15 SP4
openSUSE-Leap-15.4 openSUSE Leap 15.4
openSUSE-Tumbleweed openSUSE Tumbleweed
</code></pre>
<p>Please customize at your own risk. This tutorial assumes you are using the default Ubuntu distribution.</p>
<h2>Installing Azure CLI</h2>
<p>Let’s get down to business! Next, select your WSL CLI.</p>
<p><img src="https://www.harveyramer.com/img/blog/select-wsl-cli.png" alt="Select the Ubuntu CLI in the Windows Subsystem for Linux" /></p>
<p>The Microsoft team has provided a <a href="https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-linux?pivots=apt#option-1-install-with-one-command">simple single command</a> to install the CLI. If you prefer a multi-step process to install the CLI, <a href="https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-linux?pivots=apt#option-2-step-by-step-installation-instructions">that option</a> is also available.</p>
<pre><code>curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
</code></pre>
<p>When that process is finished, type <code>az --version</code> in your Ubuntu command prompt, and you will see something like this:</p>
<pre><code>azure-cli 2.48.1
core 2.48.1
telemetry 1.0.8
Dependencies:
msal 1.20.0
azure-mgmt-resource 22.0.0
Python location '/opt/az/bin/python3'
Extensions directory '/home/linuxguy/.azure/cliextensions'
Python (Linux) 3.10.10 (main, Apr 25 2023, 04:23:10) [GCC 11.3.0]
Legal docs and information: aka.ms/AzureCliLegal
Your CLI is up-to-date.
</code></pre>
<h2>Log In to Azure Cloud</h2>
<p>To interact with your Azure resources, you need to authenticate the CLI client. In your Ubuntu CLI, type the command, <code>az login</code>. When you do, your browser will open and prompt you to authenticate. On success, you will be able to return to your CLI by closing the browser window.</p>
<p>When your <code>az login</code> command has completed, you will see a list of the resources available to you. To discover available commands, you can use <code>az find function</code> where <code>function</code> is a word for which you hope to discover a command. See the output for the <code>find</code> command below.</p>
<pre><code>Finding examples...
Here are the most common ways to use [function]:
Show function details. (autogenerated)
az functionapp function show --function-name MyFunctionName --name MyFunctionAppName --resource-group MyResourceGroup
Delete a function.
az functionapp function delete --resource-group MyResourceGroup --name MyFunctionAppName --function-name MyFunctionName
</code></pre>
<p>Hopefully, this tutorial will help you get started quickly. Please don’t hesitate to reach out if you have any questions.</p>
How to Get More Creative Work Done in a Day
2021-04-17T00:00:00Zhttps://www.harveyramer.com/article/how-to-get-more-creative-work-done/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706043722/how-to-get-more-creative-work-done.png" alt="how-to-get-more-creative-work-done" /></p>
<p><em>I’ll do that when I have more time.</em> We all say those words, but what do we really mean by them?</p>
<p>Productivity is hard, but the facts are simple. Every one of us has 24 hours available each day. And whether we realize it or not, we allocate those hours to the activities we value most. So perhaps when we say we need more time, we aren’t discussing time at all. Maybe we know deep down we are ignoring the things we value most. We have fallen into a routine of reacting to life instead of doing the work that matters most.</p>
<h2>Reactive or Proactive?</h2>
<p>Some jobs are reactive by nature. If you work as a support technician or an air traffic controller, reacting to others in real-time is what makes you successful. But if you are a knowledge worker, success depends on your creative output, and creativity thrives on proactive focus work. If you lose control of your time, you will not finish your work, and your income will be at risk.</p>
<h3>Solo Proactivity</h3>
<p>It’s not easy for me to make regular daily progress on creative work. Perhaps this is partly because circumstances often dictate that I work with left-over energy. I spend much of my day reacting to life’s demands. After all, if I am in a reactive mode much of the time, how can I expect to be productive? But this is, at least in part, a cop-out.</p>
<p>I can approach my day, regardless of my energy level, with a determined focus on the work that makes a difference. But this is where the energy-level argument is not a cop-out. When I am fatigued, my attention wanders more easily. Still, I can focus my tired mind by managing my environment and knowing my priorities.</p>
<h3>Proactivity with Teammates</h3>
<p>If you work with a team, consider negotiating an agreement to maintain silent hours. During those times, meetings and interruptions (except for true emergencies) should not interrupt focused work.</p>
<p>If your team’s culture doesn’t allow firm boundaries, consider being more proactive by blocking time on your calendar. Use those times to <em>meet with yourself</em>. Do the work that will move your company forward. As long as you are honest with others about your time management and your schedule facilitates collaboration, this will give you a win. It will boost your output, and what manager doesn’t like that?</p>
<h2>Nightly Reflection</h2>
<p>Constantly diverting your attention to other people’s agendas will rob you of productivity, but time and space to yourself won’t guarantee worthwhile work. You need to know your goals. Keep them short—a sentence or two. Ideally, set just one goal, but make it count. Our energy dissipates when we divide our attention.</p>
<p>Each evening, spend some time in reflection and planning before you fall asleep. This simple discipline will transform your mornings.</p>
<h3>Goal-Setting</h3>
<blockquote>
<p>“If you’re bored with life–you don’t get up every morning with a burning desire to do things–you don’t have enough goals.”<br />
–Lou Holtz</p>
</blockquote>
<p>Before I go to bed at night, I take a few moments to jot down, by hand, a goal for the next day. That goal stays in my mind, prompting me to get out of bed in the morning. Simple, measurable goals motivate you. If you are a writer, how many words do you plan to write? If you are a software developer, how many features or bug fixes will you complete? If you are in sales, how many calls will you make?</p>
<p>As you adopt a daily goal-setting routine, don’t start with lofty aspirations. Give yourself wins. Build the habit of making promises you are sure you can keep. Then as your goal-setting muscles improve, stretch yourself with specific, measurable goals. Push past your comfort zone.</p>
<p>Any approach you take to goal-setting is better than facing a new day without a plan. Be kind to yourself, but do not let passivity take hold of your work. We are here for a purpose, and we express that purpose through our daily work.</p>
<p><strong>Note:</strong> Set just one daily goal, but make it count. One clear daily goal will stop your attention from wandering and allow you to focus. Your drive to succeed will stay strong as you invest your energy where it counts. Avoid social media, email, and easy-but-trivial wins.</p>
<h3>Measuring Your Key Performance Indicators</h3>
<blockquote>
<p>“While a lag measure tells you if you’ve achieved the goal, a lead measure tells you if you are likely to achieve the goal.”<br />
—Stephen Covey</p>
</blockquote>
<p>Each day, I look back at the work I produced. Did I achieve my goals today?</p>
<p>Following Donald Miller’s advice in <em>Business Made Simple</em>, I create a weekly scorecard on a whiteboard in my office. I don’t track the results of my work; I measure what I control. Leading indicators are tasks we know will usually get results. Doing more of these things is always a good thing. Just to the right of my workstation is a list of the activities I believe will bring success. As I complete tasks, I record my work on the scorecard.</p>
<p>When I want to push past procrastination, I can turn my head a few inches and get the boost I need.</p>
<h2>Morning Meditation</h2>
<blockquote>
<p>“Satisfy us in the morning with your steadfast love,<br />
that we may rejoice and be glad all our days.”<br />
— Psalm 90:14 ESV</p>
</blockquote>
<p>Start each day with a simple routine that reflects your values. I begin my day with prayer. I need help from God to be effective. Then I read my Bible and a chapter from a book I hope will help me grow.</p>
<p>Before I start working, I evaluate my priorities and plan my work sessions.</p>
<h3>Know Your Priorities</h3>
<blockquote>
<p>“It is not a daily increase, but a daily decrease. Hack away at the inessentials.”<br />
― Bruce Lee</p>
</blockquote>
<p>Keep your work priorities in line with your goals. Donald Miller recommends using a simple one-page document to keep our priorities straight. List the top five priorities of your <em>team</em> along with your five <em>personal</em> primary responsibilities. Sharing your one-pager with your teammates helps align expectations and unlocks more productivity.</p>
<p>For projects that do not include a team, only focus on <em>your</em> priorities. Any work that does not advance your project is a waste of energy, and energy is scarce.</p>
<p>When I have a clear list of priorities, I am more effective and less frustrated. Over time, I can avoid discouragement.</p>
<h3>Plan Your Daily Work Sessions</h3>
<blockquote>
<p>“If you don’t know where you are going,<br />
you’ll end up someplace else.”<br />
― Yogi Berra</p>
</blockquote>
<p>Your daily work sessions bring your priorities to life. When you have a simple plan for each work session, you banish any worries from your mind. There is no need to wonder if you are fruitlessly frittering away your time and energy.</p>
<p>Do not use work sessions for tasks like taking your clothes to the dry cleaner or running to the grocery store. We must do those things, but they are not vital to our success. No one lists the punctual completion of such tasks as the reason for their success.</p>
<p>Resist the desire to plan more than four daily work sessions, and keep them under an hour long. Intense focus is exhausting, and short bursts of work followed by rest periods will maintain your energy. Packing your day full will overwhelm and discourage rather than motivate.</p>
<h2>Daily Execution</h2>
<h3>Track Your Time</h3>
<blockquote>
<p>“You can’t manage what you can’t measure.”<br />
— Peter Drucker</p>
</blockquote>
<p>Recently, I have been working through <em>The Mastery Journal</em> by John Lee Dumas. A critical piece of his execution strategy is time tracking. He recommends breaking up your daily tasks into four timed work sessions followed by brief rest periods. This method, called the <em>Pomodoro® Technique,</em> was created by Francesco Cirillo. It is so simple as to appear trivial. But it is far from trivial in its impact on productivity.</p>
<p>Before you begin your work session, get clear on your purpose. Let the <em>Pomodoro®</em> timer push you into action. Using this method short-circuits any procrastination that is hiding out in your subconscious. I use this method every day, and it gives my productivity a big boost.</p>
<h3>Block Distractions</h3>
<blockquote>
<p>“By prevailing over all obstacles and distractions, one may unfailingly arrive at his chosen goal or destination.”<br />
— Christopher Columbus</p>
</blockquote>
<p>Consistent self-control is hard to master. Clear goals and accountability systems reinforce it, but they are not enough on their own. When confronting a task that looks hard, we are easily distracted. Like water flowing downhill, our consciousness seeks the path of least resistance. So even when we intend to write an article, debug a piece of software, or learn a new skill, our minds wander at any invitation.</p>
<p>Sometimes we lie to ourselves. We say, <em>“Maybe just thinking about this problem is better than working on it.”</em> Then, we feel intelligent and stroke our ego. We think we are brave to confront such massive problems.</p>
<p>Be a fanatic about managing distractions. My computer has a <em>Do Not Disturb</em> mode I turn on while I am working. I do not want to let <strong>social media</strong> get my attention with its barrage of notifications. I love hearing from others and learn a great deal from what they share, but social media must not interrupt my work.</p>
<p>No matter what we do, we can never keep all distractions at bay. <strong>Text messages</strong> from coworkers, family, and friends can distract us at any time. Rather than blocking these distractions during work sessions, I allow myself to glance at incoming messages. I ask myself, “Is this urgent?” Then, I move on. Almost 100% of the time, the answer is, “No.”</p>
<p>Unless your job requires answering <strong>phone calls</strong>, ignore them during your focused work sessions. When you call me and get my voicemail prompt, it is because I am working. In my experience, if your message is urgent, you will leave a <strong>voicemail message.</strong> When my phone notifies me of a voicemail, I skim the transcript and return urgent calls immediately. Otherwise, work comes first.</p>
<h2>Does This Really Work?</h2>
<p>Yes, this works. It is simple to understand and apply but easily overlooked. When I am frustrated and discouraged, I usually discover I am neglecting this simple practice.</p>
<p>I am fascinated with ideas—complex ones are the best. Mentally turning over a fascinating concept is exhilarating. New insights delight me. That strength is also a weakness. It rarely contributes to getting work done. Some work requires deep reflection and analysis, and I am grateful for work that uses this skill. But I need external systems to hold myself accountable. Otherwise, my most important contributions will lie dormant. Try these ideas. Let me know how they change your life.</p>
Core Web Vitals for Business Owners Who Want to Keep Their Search Rankings
2021-04-09T00:00:00Zhttps://www.harveyramer.com/article/core-web-vitals-intro/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706043722/core-web-vitals-intro.png" alt="core-web-vitals-intro" /></p>
<p>Measuring a website’s user experience has always been a challenge. Which metrics should we measure, and what tools give us accurate information? To fix this problem, Google has introduced Core Web Vitals—the metrics they use to evaluate your website’s user experience.</p>
<p>Google is reporting these metrics in all of its monitoring and analytics tools. They want it to be easy for non-technical users to evaluate their website without recruiting technical help. That is a critical breakthrough, especially since in May 2021, web vitals began to influence your ranking<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/core-web-vitals-intro/#fn1" id="fnref1">[1]</a></sup> in the Google search results.</p>
<h2>What Are Core Web Vitals?</h2>
<p>Core Web Vitals are the statistics Google believes represent a quality web page user experience. They measure three aspects of performance:</p>
<ol>
<li>Loading (LCP - Largest Contentful Paint)</li>
<li>Interactivity (FID - First Input Delay)</li>
<li>Visual Stability (CLS - Cumulative Layout Shift)</li>
</ol>
<p>According to Google, websites should:</p>
<ol>
<li>Be finished with LCP (Largest Contentful Paint) in 2.5 seconds or less</li>
<li>Have a FID (First Input Delay) of fewer than 100 milliseconds</li>
<li>Maintain a CLS (Cumulative Layout Shift) of less than 0.1.</li>
</ol>
<h2>How Can I Assess My Website?</h2>
<p>The best tool for beginners is PageSpeed Insights<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/core-web-vitals-intro/#fn2" id="fnref2">[2]</a></sup>. It is easy to use, but it provides detailed technical information you can share with others.</p>
<p>Your initial website performance may be discouraging. But without taking a measurement, you’ll never know how to improve. After all, we can only improve what we measure.</p>
<p>Go ahead and test your website now. Congratulations! You’ve taken the first step toward a better user experience for your customers.</p>
<h2>How Can I Boost My Website’s Speed?</h2>
<p>While PageSpeed Insights is easy for non-technical people to use, improving your results requires expertise. The factors that affect performance include the following:</p>
<ul>
<li>Server load and computing power</li>
<li>Network speed and latency</li>
<li>The number of images, their size and optimization level</li>
<li>The amount of JavaScript and CSS, caching, and minification</li>
<li>Third-party scripts that may load slowly and prevent the site from loading</li>
<li>Embedded code that should be in external files for minification and asynchronous loading</li>
<li>Web fonts</li>
<li>Audio and video files</li>
<li>DNS lookups</li>
</ul>
<p>With your speed test results in hand, your IT resources can analyze them and prioritize the needed improvements. If you don’t have internal expertise, talk to a company like FlareMark. We are happy to help.</p>
<p>Google has shared some technical guidance<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/core-web-vitals-intro/#fn3" id="fnref3">[3]</a></sup> on ways to measure web vitals you may want to review before you begin.</p>
<h2>Will Poor Website Performance Hurt My Business?</h2>
<p>As I mentioned above, Google has been using Core Web Vitals as a ranking signal since May 2021. How much a site’s slowness hurts its search results is hard to say. Because Google values websites based on age and reputation, the ranking changes may roll out gradually. However, Google plans to highlight fast sites in the search results. Not having a “Fast Website” label may impede click-through even if you maintain an excellent search position.</p>
<blockquote>
<p>“… we plan to test a visual indicator that highlights pages in search results that have great page experience.”</p>
</blockquote>
<p>A new era of emphasis on page performance has arrived. And upgrading the server behind a poorly engineered website will not resolve the problem. Google measures everything from the server-side to the final animation in your web browser. It is time to get serious about website engineering from the back end to the front end if you want to stand out from the crowd. Performance is more important than ever for search engine optimization.</p>
<p>But how should you prioritize Core Web Vitals for your business?<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/core-web-vitals-intro/#fn4" id="fnref4">[4]</a></sup> It all depends on the user experience of your customers. This means what it takes to be fast will vary from company to company. If, for example, your business services rural customers who do not have a fast connection, your website may need to be considerably lighter than a tech company focused on a metropolitan region.</p>
<h2>What Should I Do Now?</h2>
<p>Web vitals is a critical part of your website’s success as of May 2021. The first step is to measure and report those statistics to your team. Then, recruit help to create to a more performant website. Making improvements in website performance is often complex, but you can get started today. Don’t wait until your rankings drop in the search engine results.</p>
<h2>Footnotes</h2>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="https://developers.google.com/search/blog/2020/11/timing-for-page-experience">Timing for bringing page experience to Google Search</a>. Google, November 10, 2020. <a href="https://www.harveyramer.com/article/core-web-vitals-intro/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Learn to make your web pages fast on all devices with <a href="https://developers.google.com/speed/pagespeed/insights/">PageSpeed Insights</a>. <a href="https://www.harveyramer.com/article/core-web-vitals-intro/#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p><a href="https://web.dev/vitals-measurement-getting-started/">Getting started with measuring Web Vitals</a>. Google, May 27, 2020. <a href="https://www.harveyramer.com/article/core-web-vitals-intro/#fnref3" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn4" class="footnote-item"><p><a href="https://web.dev/vitals-business-impact/">The business impact of Core Web Vitals</a>. Google, May 18, 2021. <a href="https://www.harveyramer.com/article/core-web-vitals-intro/#fnref4" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
3 Keys to a Useful Website That Actually Works
2021-03-15T00:00:00Zhttps://www.harveyramer.com/article/three-keys-to-a-website-that-works/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706042280/three-keys-to-a-website-that-works.png" alt="three-keys-to-a-website-that-works" /></p>
<p>It’s Monday morning, and Jane is taking her first sip of hot coffee when she is interrupted. She sees the incoming call on her business phone is from a neighboring county. “My friend just told me about your business, and I’d like to see what you can do for me,” says Bob, an ideal customer, “But first, I’d like to learn more. What is your website address?”</p>
<p>She’s been hearing it more and more often lately. So, Jane apologizes to Bob and calls a digital marketing company. It specializes in websites that look amazing, and she loves the first design she sees. After giving the project manager some basic information about her business, Jane goes about her routine Monday tasks. The following week, Jane’s new website launches, and she includes her new website in all her advertising and marketing outreach.</p>
<p>Now that she has a website, Jane makes more sales. However, she begins to suspect something is wrong when she looks at her website analytics. Not many people who visit her website stay more than 3 seconds. Worse, few people visit her website at all. “Maybe my website isn’t helping with my sales as much as I thought.” Jane’s initial boost in sales productivity may have come more from the confidence instilled by having a website than from the website itself. Jane wonders if there’s more she can do to make her website work for her business.</p>
<p>Jane’s website is optimized to create an immediate, visually appealing impression. Aesthetic appeal is a valuable prerequisite for a successful website, but it is not enough. Pretty moving pictures attract attention, but well-crafted messages spur users to action.</p>
<p>This story is fictional, but it reflects a growing trend with business websites. Busy web designers often overlook the fundamentals of the user’s experience and neglect search engine visibility in favor of flashy, easy-to-sell websites.</p>
<h2>What Should Jane Have Done Differently?</h2>
<p><strong>First,</strong> Jane never discussed the possibility of keyword research with her marketing company. Instead, she provided some basic information the designer used to generate a website. It is little more than a pamphlet describing her business.</p>
<h3>Search Engine Visibility</h3>
<p>A successful website uses research to find phrases your potential customers are already using when looking for a business like yours. Based on that research, we can write content around the highest impact phrases. Unless Jane’s website contains the keywords and phrases her customers use when searching, her valuable business will be invisible online.</p>
<p><strong>Second,</strong> Jane’s chosen web design company didn’t prioritize speed. Instead, they focused exclusively on visual impact.</p>
<h3>Fast Websites Get Results</h3>
<p>Jane’s website looks good, but it does not load quickly enough for Google to prioritize it as high-quality content. Google’s research shows that more than half<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/three-keys-to-a-website-that-works/#fn1" id="fnref1">[1]</a></sup> of mobile users abandon a page if it has not loaded in 3 seconds or less. Speed is an indicator of quality, and Google buries slow websites deep in their search results. Since Jane’s website is new, it hasn’t been around long enough to reassure the search algorithm it <em>really is</em> good.</p>
<p>To get herself out of this hole, Jane must work hard to make sure her site loads in under three seconds on a 4G connection. Jane’s customers demand it. Any perceptible wait time makes her customer more likely to leave without making a purchase. Even with a fast website, however, Jane’s troubles are not over.</p>
<p><strong>Third,</strong> she needs to work on her messaging. Since her website puts her business at the center, it needs a fundamental transformation.</p>
<h3>They’re Just Not That Into Your Business</h3>
<p>Jane’s website is all about her and what she does. Her business is the focal point of the website. But human beings are interested in themselves. Jane needs to position her business as a part of a transformation her customers desire. When that transformation is at the center of her message, she will see the engagement she needs. She can start by asking, “How does my business make customers’ lives better and give them new victories to share?”</p>
<h2>What Happens Next</h2>
<p>After Jane makes three simple changes, her business slowly improves. Search engines begin to pick up her content and bring visitors to her website. She reviews her website analytics and sees her average visit time increase. Her message is clear, and she has calls to action that draw visitors deeper into her website. There they learn more about her, build trust, and begin to buy from her. These simple-but-fundamental changes reap significant benefits.</p>
<ol>
<li>Invest in optimizing <strong>content</strong> for search engines,</li>
<li>boosting the <strong>speed</strong> of your website, and</li>
<li>focusing your <strong>message.</strong></li>
</ol>
<p>When the customer is at the center of all you do, you will get better results over time.</p>
<h2>Footnotes</h2>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>“For many sites this equates to a huge missed opportunity, especially when more than half of visits are abandoned if a mobile page takes over 3 seconds to load.” — <a href="https://developers.google.com/web/updates/2018/07/search-ads-speed">Speed is now a landing page factor for Google Search and Ads </a>. Google, 09/23/2019. <a href="https://www.harveyramer.com/article/three-keys-to-a-website-that-works/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
Choose Action Over Analysis
2020-12-06T00:00:00Zhttps://www.harveyramer.com/article/choose-action-over-analysis/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706043722/choose-action-over-analysis.png" alt="choose-action-over-analysis" /></p>
<p>Beside me are books filled with business advice and technological innovations. A laptop with an internet connection enables me to write this article. Mind-blowing discoveries and groundbreaking ideas are at my fingertips.</p>
<p>We live amid an information explosion<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/choose-action-over-analysis/#fn1" id="fnref1">[1]</a></sup>. We have more knowledge available to us now than at any other time in history. Yet, many of us fail to enjoy its benefits. Why is this?</p>
<blockquote>
<p>“You can’t stop the waves, but you can learn to surf.”<br />
— John Kabat-Zinn</p>
</blockquote>
<p>I cannot speak for everyone, but I have noticed a pattern in my own life. I am fascinated with ideas that have potential. I spend time and put forth significant effort learning how to apply those ideas. But instead of taking immediate action, I file away a new strategy or tactic for future use.</p>
<p>We became idea collectors in school, and our teachers cheered us on. Their lessons filled our heads with fascinating ideas, and they often demanded nothing of us in return except the ability to remember concepts for a test. As adults, we strive to keep up that work. We memorize more and more facts to deal with the unrelenting volume of ideas pouring into our lives. Like unrelenting breakers, the information rolls over us. Due to all this information overload<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/choose-action-over-analysis/#fn2" id="fnref2">[2]</a></sup>, some of us stop learning. We surrender.</p>
<p>There is an alternative. We commit to applying what we learn. We equate learning with action. We no longer seek to master the memorization of unapplied ideas.</p>
<blockquote>
<p>But be doers of the word, and not hearers only, deceiving yourselves.<br />
— James 1:22 ESV</p>
</blockquote>
<p>When an idea catches our attention, we ask, “Am I ready to apply this idea if it proves valuable?” If the answer is “No.” we move on to other things without regret.</p>
<p>We stop learning about everything others tell us we should do. Instead, we focus on the next valuable thing for our business or personal growth. We focus on learning those things that allow us to make progress toward our goal.</p>
<p>What is your next business challenge? Are you committed to taking action? Succeed by learning what you need to know to overcome it step by step. Get started by taking three steps to make your website work better<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/choose-action-over-analysis/#fn3" id="fnref3">[3]</a></sup> for your business.</p>
<h2>Footnotes</h2>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="https://en.wikipedia.org/wiki/Information_explosion">Information explosion</a>. Wikipedia, August 18, 2021. <a href="https://www.harveyramer.com/article/choose-action-over-analysis/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p><a href="https://en.wikipedia.org/wiki/Information_overload">Information overload</a>. Wikipedia, September 24, 2021. <a href="https://www.harveyramer.com/article/choose-action-over-analysis/#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p><a href="https://www.harveyramer.com/article/three-ways-to-boost-website-results/">3 Ways You Can Boost Your Website’s Results</a> <a href="https://www.harveyramer.com/article/choose-action-over-analysis/#fnref3" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
Your Business Is Better, But for Whom?
2020-11-12T00:00:00Zhttps://www.harveyramer.com/article/your-business-is-better/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706043723/your-business-is-better.png" alt="your-business-is-better" /></p>
<p>People are not alike. At least not in the way most of us believe. During the 2020 presidential election, pundits endlessly discussed the Latino vote, Black vote, College-educated White vote, and the Evangelical vote. Too late, it seems, everyone has discovered there is no such thing as a monolithic vote by everyone who looks similar—even when that similarity is profound.</p>
<p>As our culture fragments politically, it reveals a fact about human beings that has always been true but under-appreciated. We are weird. Each of us wired in ways that appear similar, but deceptively so. Yes, it is possible to write a great American novel or to create a blockbuster movie, but those are outliers. Finding a path to reach most of our culture is daunting for those with limited resources. Frankly, the mass market is already well-served. So how can your business find an audience of willing customers?</p>
<p>That brings us to the idea of “better.” Since human beings are so diverse, we are wise to proceed with caution on well-meaning recommendations from others. The idea of a better or best clothing boutique is passé. And there is not a digital marketing agency better than all the rest.</p>
<blockquote>
<p>When a marketer arrives and says, “This is better,” he’s wrong. He actually means, "This is better for someone and it might be better for you.<br />
— Seth Godin<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/your-business-is-better/#fn1" id="fnref1">[1]</a></sup></p>
</blockquote>
<p>Here is some good news. You can compete by finding a group of customers who, while diverse in other ways, prefer your approach to business. You are “better” for them. Your job is “to find a spot on the map with edges that (some) people want to find,” says Seth Godin. “Not a selfish, unique selling proposition done to maximize profit, but a generous beacon, a signal flare sent up so that people who are looking for you can easily find you. We’re this, not that.”</p>
<p>Our job as business owners is to create value for others by improving their lives using our knowledge, God-given abilities, and hard work. But that is not enough. To reach the edges of the map, to send up our signal flare, we must become storytellers. And our story must be uncomplicated and compelling.</p>
<blockquote>
<p>The fact is, pretty websites don’t sell things. Words sell things. And if we haven’t clarified our message, our customers won’t listen.<br />
— Donald Miller<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/your-business-is-better/#fn2" id="fnref2">[2]</a></sup></p>
</blockquote>
<p>Given the importance of a clarified story, every engagement with FlareMark begins with a conceptual branding process. We help you identify the central idea that will attract customers to your suite of products and services. With a clarified story to power our efforts, we design your logo, website, and other marketing collateral.</p>
<p>Your story is your beacon—your signal flare. To attract customers to your spot on the map, launch your signal flare and share your message.</p>
<p>Ethical marketers draw attention to your story; they don’t make it up. It’s yours. Only you can tell it.</p>
<h2>Footnotes</h2>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Godin, Seth. <em><a href="https://seths.blog/tim/">This Is Marketing</a>.</em> Portfolio, 2018. <a href="https://www.harveyramer.com/article/your-business-is-better/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Miller, Donald. <em><a href="https://buildingastorybrand.com/">Building a Story Brand</a>.</em> HarperCollins Leadership, 2017. <a href="https://www.harveyramer.com/article/your-business-is-better/#fnref2" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
Free and Easy Ways You Can Grow Your Business with a LinkedIn Page
2020-09-26T00:00:00Zhttps://www.harveyramer.com/article/free-easy-grow-linkedin/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706043722/free-easy-grow-linkedin.png" alt="free-easy-grow-linkedin" /></p>
<p>Few things are more gratifying and financially rewarding than a healthy, growing business. And one of the best platforms for business marketing growth is social media. Unlike anything else, it lets you meet your customers where they are and form personal connections before they make a buying decision.</p>
<p>LinkedIn is the premier social platform for business professionals. They voted it the most trusted social network in 2019<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fn1" id="fnref1">[1]</a></sup>. According to LinkedIn<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fn2" id="fnref2">[2]</a></sup>, their directory includes more than <strong>706 million users</strong> and <strong>50 million companies</strong>.</p>
<p>With such massive numbers, the platform deserves to be a vital part of your business marketing portfolio—especially if you are a B2B company. LinkedIn search lets your <strong>prospecting and sales teams</strong> find qualified leads from those <em>50 million companies</em> with ease.</p>
<p>The workplace trend of remote employment is here to stay<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fn3" id="fnref3">[3]</a></sup>. As remote work expands, virtual connections will become ever more powerful. As a business-focused social network, LinkedIn will become even more integral to the workplace. This fiscal year, <strong>revenue has grown 20%</strong> year over year, and <strong>content sharing is up 50%.</strong> Driven by the isolation of the pandemic, <strong>live video streaming has risen nearly 90%</strong> since March of 2020.</p>
<p>LinkedIn is booming, and businesses of all sizes should get active on the platform or miss out on a growth opportunity. Thankfully, there are free and easy ways you can build your personal brand<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fn4" id="fnref4">[4]</a></sup> and grow your business with LinkedIn.</p>
<blockquote>
<p>We’ve found that 50% of LinkedIn members are more likely to purchase from a company they engage with on LinkedIn.<br />
— <cite>Lana Khavinson<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fn5" id="fnref5">[5]</a></sup></cite></p>
</blockquote>
<h2>Create a LinkedIn Strategy</h2>
<p>But where should LinkedIn fit into your marketing strategy? Businesses new to social media should begin by sharing content via personal profile updates. Share high-quality content related to your skills and to the problem your business solves. Avoid off-topic discussions that may alienate customers your business can help. Your passionate conversations on personal issues belong to Facebook, not LinkedIn.</p>
<p>According to LinkedIn, consider sharing PowerPoints, PDFs, and Word Docs relevant to your customers. Share your blog posts, and photos of customers and smiling employees. Also share upcoming events, customer success stories, and relevant industry news.</p>
<h3>How Employees Can Multiply Your Impact</h3>
<p>As you share interesting content on LinkedIn, let your employees know about it. Many employees are happy to share and discuss content their employer is sharing. Employee engagement can multiply your impact on social media. Set employee expectations with a social media policy<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fn6" id="fnref6">[6]</a></sup>.</p>
<p>As your employees create content, <strong>@mention</strong> them, and re-share their posts. Everyone likes recognition. Use it to encourage social behavior that boosts the visibility of your employees and your business.</p>
<h3>How to Join the Conversation</h3>
<p>Joining LinkedIn is a bit like visiting a dinner party. Conversations are going on everywhere, and you are welcome to join in. Remember to add value and do more than share your blog posts.</p>
<p>Conversations spread through LinkedIn via <strong>#hashtags.</strong> Monitoring those hashtags can help you discover discussions already happening in the community. When you find one, connect by giving away genuinely helpful information. Your customers deserve a chance to try before they buy.</p>
<p>Sharing knowledge is an excellent way to promote your business, especially if you are a consultant. Generosity is memorable.</p>
<h3>Prove Your Expertise</h3>
<p>Thought leadership is perhaps an over-used buzzword, but it can open doors for your business. Over time, publish a few articles of approximately 2,000 words in length that go deep and show your expertise. Avoid showing off. Invite people to understand your area of expertise. Give them something for free to help them understand your unique value.</p>
<blockquote>
<p>Thought leadership is about sharing insights and ideas … that provoke new ways of thinking, spark discussions and debates, and inspire action.<br />
— <cite>LinkedIn<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fn7" id="fnref7">[7]</a></sup></cite></p>
</blockquote>
<p>The Sophisticated Marketer’s Guide to Thought Leadership defines a <strong>thought leader</strong> clearly. A thought leader knows their topic well enough to form “a clear, unique and defensible point of view about it.” They are willing to <strong>freely share</strong> that perspective.</p>
<p>Do you recall our earlier point about generosity?</p>
<h2>How to Create a LinkedIn Company Page</h2>
<p>On the LinkedIn site, click the <strong>Work</strong> menu and select <strong>Create a Company Page.</strong> LinkedIn then lets you get started with some helpful prompts appropriate for your business type.</p>
<p><img src="https://www.harveyramer.com/img/blog/create-a-company-page.png" alt="Getting Started with a LinkedIn Company Page" title="LinkedIn makes it easy to create a page." /></p>
<p>Then, follow the prompts to complete your page.</p>
<p><img src="https://www.harveyramer.com/img/blog/start-completing-your-company-page.png" alt="Complete Your LinkedIn Company Page" title="Follow the prompts." /></p>
<p>It is easy to do, but getting a few essential things right will help you get the most from your page.</p>
<h2>LinkedIn Company Page Best Practices</h2>
<h3>Link to Your Website</h3>
<p>Your LinkedIn page, when done well, will arouse curiosity in prospects your business can serve. Your Website URL in the <strong>About</strong> section is vital for that purpose.</p>
<h3>Create a Custom Button</h3>
<p>Your header section allows you to toggle on a Custom Button setting. When you enable a custom button, it will appear below your tagline in addition to the Follow button that is there by default.</p>
<p>Use every tool LinkedIn offers to engage customers with your brand. Turn that setting on and choose a relevant call to action with a link to your website.</p>
<p><img src="https://www.harveyramer.com/img/blog/linkedin-page-custom-button.png" alt="Create a custom button" title="Use every tool LinkedIn gives you." /></p>
<h3>Include Important Images</h3>
<p>Include your logo, but choose a relevant form for LinkedIn. You will need an adaptable variant of your logo to accommodate a square page logo format. Often a simple icon drawn from your logo works best. Think of the <strong>M</strong> from McDonald’s. A typical, wordy logo will not represent your brand very well as a page logo.</p>
<p><img src="https://www.harveyramer.com/img/blog/mcdonalds-linkedin-header.png" alt="McDonald's on LinkedIn" title="Notice the simple icon as page logo." /></p>
<p>Choose a cover image relevant to your brand. The McDonald’s example above repeats their iconic <strong>M</strong> in the cover image. These visual elements are the first view your customers will have of your brand on LinkedIn. Choose them with care.</p>
<h3>Wield Weighty Words</h3>
<h4>Tagline</h4>
<p>Just like your logo and cover images, your tagline is a strong representation of your brand. It works with your visual identity to orient customers to your business and your value proposition.</p>
<p>While making a powerful first impression, your tagline must attract visitors from search engines. Include keywords that set your business apart. Your 120-word tagline does a lot of work for your business. Take your time with it. Try variations until it includes your most powerful keywords and a relevant value proposition.</p>
<h4>About - Details that Convert</h4>
<p>LinkedIn offers a 2,000 character <strong>Description</strong> field in the <strong>About</strong> section. Write a detailed explanation of your company offerings. Like your tagline, it should include appropriate keywords to boost search engine traffic. The ample space allows more flexibility to speak more naturally about your business.</p>
<p>Here are some questions to consider answering:</p>
<ul>
<li>What are your products and services?</li>
<li>What is your unique value proposition?</li>
<li>Why should people follow your company page?</li>
<li>Who is your customer, and how can you help them?</li>
<li>What are your goals and vision?</li>
</ul>
<p>Marketing your business is <strong>not about you</strong> but <strong>about transformation</strong>—the improved life you offer your customers. So the About Us section is really about them, not about you. This idea will guide your writing toward an irresistible value proposition for your customers.</p>
<p>Ideally, your page will inform, convince, and invite new customers into your business.</p>
<h3>Community Engagement with Hashtags</h3>
<p>Your selection of hashtags will power your ongoing engagement with the LinkedIn community. LinkedIn watches for conversations using the hashtags you choose. When they find an applicable thread, LinkedIn will notify you and invite you to contribute.</p>
<p>Include your company name and brand names as hashtags. Hashtags are a tool others can use to spread the word about you in their posts.</p>
<p>Monitoring hashtags is an opportunity to learn from others. More importantly, those threads you discover are a platform to share your expertise.</p>
<h2>Promoting Your Page</h2>
<p>Doing the following things will encourage others to begin following your brand on LinkedIn. As this happens, the power of the platform to amplify your brand message will become apparent.</p>
<blockquote>
<p>According to eMarketer, 72% of US business professionals think LinkedIn is the most effective platform to exchange professional ideas and interests, and 77% consider it to be the social platform where they expect to see professional content.<br />
— <cite>Paige Weiners<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fn8" id="fnref8">[8]</a></sup></cite></p>
</blockquote>
<h3>Employment History</h3>
<p>Tell your employees about your new company page. Each employee should include their current work experience in their profile. When they do, their employment history will link to your company page. Employee profiles are vital tools to spread the word about your company.</p>
<h3>Community Hashtags</h3>
<p>As mentioned above, employees also can spread the word through status updates on their profiles. Tell them to use your custom hashtags when they do. Their updates will allow others to engage with your brand more effectively through those hashtags. As employees share hashtags, others will be able to see relevant updates with a single click on a hashtag.</p>
<h3>Invite Your Connections</h3>
<p>Invite people already connected to you on LinkedIn to follow your page. Look for potential customers and industry experts who would enjoy your page updates.</p>
<p>Each month LinkedIn adds new invitation credits. At last check, they allow you to invite 100 people each month. If you are relevant, you are not pushy. Offer a feast of value and invite others to the table.</p>
<h3>Link to Your Page from Your Website</h3>
<p>Your company website should link to your page. Think of inviting people to follow your LinkedIn page as something as valuable as an email newsletter sign-up. As people follow your page, LinkedIn lets you see them all.</p>
<p>If you would like to engage them in a sales conversation, you can consider a page follower a warm lead. Reach out to them on LinkedIn with a connection request like this:</p>
<p><em>I see you are following our company page and would like to connect to discuss how I can help you.</em></p>
<p>A natural sales conversation unfolds from connections like these.</p>
<h3>Link to Your Page from Your Email Signature</h3>
<p>A natural place to link to your LinkedIn page is from your email signature. I have included a link at the very end of my signature, but there are many options open to you. Do what is right for your brand.</p>
<p><img src="https://www.harveyramer.com/img/blog/linkedin-email-signature.png" alt="Email Signature with Link to LinkedIn" title="Use every opportunity. Don't overlook your email signature." /></p>
<h2>Publish Amazing Content</h2>
<p>Post content frequently. In the busy professional world, silence often means invisibility. If customers forget about you, they will not buy from you.</p>
<blockquote>
<p>Brands that post once a month gain followers six times faster than those that don’t. Companies that post weekly see two times the engagement. Brands that post once a day gain even more traction.<br />
— <cite>Katie Sehl<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fn9" id="fnref9">[9]</a></sup></cite></p>
</blockquote>
<p>Mention brands, industry leaders, hashtags, and engaging content created by others. Be generous. You can educate your customers by pointing out any resources they may have missed.</p>
<p>Find good times to post. Ideal times can vary by brand and industry, but there are general guidelines that can improve your effectiveness.</p>
<blockquote>
<p>HootSuite research finds the best times to post on LinkedIn are 7:45 a.m., 10:45 a.m., 12:45 p.m., and 5:45 p.m. EST. The best day for B2B brands is Wednesday. For B2C brands, Mondays and Wednesdays are best.<br />
— <cite>Katie Sehl<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fn9" id="fnref9:1">[9:1]</a></sup></cite></p>
</blockquote>
<h2>Grow Your Business with a LinkedIn Page</h2>
<p>The advice is easy to do, but it does take time and attention. Spend time. Engage your employees and stakeholders. When guided by your brand and vision, a LinkedIn page is a powerful extension of your marketing and sales efforts.</p>
<p>Engage with the <strong>706 million users</strong> and <strong>50 million companies</strong> on LinkedIn. You will help the businesses that need what you offer<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fn10" id="fnref10">[10]</a></sup> succeed and prosper as a result.</p>
<h2>Footnotes</h2>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="https://www.businessinsider.com/linkedin-pinterest-instagram-top-spots-2019-digital-trust-report-facebook-stays-last">LinkedIn, Pinterest, Instagram most trusted platforms; Facebook least</a> <a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p><a href="https://news.linkedin.com/about-us#1">About Us: LinkedIn</a> <a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p><a href="https://www.techrepublic.com/article/remote-work-is-here-to-stay-gartner-finds/">remote employment is here to stay</a> <a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fnref3" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn4" class="footnote-item"><p><a href="https://www.harveyramer.com/article/how-to-grow-linkedin/">9 Easy Ways You Can Boost Your LinkedIn Influence</a> <a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fnref4" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn5" class="footnote-item"><p><a href="https://business.linkedin.com/content/dam/business/marketing-solutions/global/en_US/campaigns/pdfs/Linkedin_SophGuide_020314.pdf">The Sophisticated Marketer’s Guide to LinkedIn</a> <a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fnref5" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn6" class="footnote-item"><p><a href="https://www.linkedin.com/business/marketing/blog/social-media-marketing/how-to-create-a-social-media-policy-that-empowers-employee-advocates">How to Create a Social Media Policy that Empowers Employee Advocacy</a> <a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fnref6" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn7" class="footnote-item"><p><a href="https://business.linkedin.com/content/dam/business/marketing-solutions/global/en_US/campaigns/pdfs/sophisticated-guide-thought-leadership.pdf">The Sophisticated Marketer’s Guide to Thought Leadership</a> <a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fnref7" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn8" class="footnote-item"><p><a href="https://www.bluefountainmedia.com/blog/grow-your-linkedin-business-page">10 Ways to Grow Your LinkedIn Business Page Organically</a> <a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fnref8" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn9" class="footnote-item"><p><a href="https://blog.hootsuite.com/linkedin-for-business/">How to Use LinkedIn for Business: A Step-by-Step Guide for Marketers</a> <a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fnref9" class="footnote-backref">↩︎</a> <a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fnref9:1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn10" class="footnote-item"><p><a href="https://www.harveyramer.com/article/your-business-is-better/">Your Business Is Better, But for Whom?</a> <a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/#fnref10" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
9 Easy Ways You Can Boost Your LinkedIn Influence
2020-09-14T00:00:00Zhttps://www.harveyramer.com/article/how-to-grow-linkedin/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706042280/how-to-grow-linkedin.png" alt="how-to-grow-linkedin" /></p>
<p>LinkedIn offers tools that can grow your brand. Building credibility with your customers, prospects, and employees is not difficult. Begin by following my recommendations to tune your LinkedIn profile for maximum results. Then go on to leverage a company page<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/how-to-grow-linkedin/#fn1" id="fnref1">[1]</a></sup> to amplify your professional brand.</p>
<p>These nine steps will expand your influence on LinkedIn:</p>
<ol>
<li>Use LinkedIn to define your professional brand</li>
<li>Add your work and education history</li>
<li>Tell others about your skills</li>
<li>Include a professional photo</li>
<li>Upload a background image</li>
<li>Write a compelling headline</li>
<li>Complete your <strong>About</strong> section</li>
<li>Customize your public web address</li>
<li>Build your connections</li>
</ol>
<h2>Start Using LinkedIn to Define Your Professional Brand</h2>
<p>Are you already on LinkedIn? Move along to the next point. If not, sign up to start using LinkedIn now. It is easy.</p>
<ol>
<li>Navigate to the <a href="https://www.linkedin.com/signup/cold-join">LinkedIn sign up</a> page.</li>
<li>Enter your email address and a password to authenticate you.</li>
<li>Submit the form by clicking <strong>Agree & Join.</strong></li>
<li>Follow the prompts to complete the process.</li>
</ol>
<p>LinkedIn will prompt you to import contacts from your computer as part of signing up. It feels like an invasion of privacy. Allowing LinkedIn to access your contacts will help you make better use of the platform. If you feel uncomfortable with that step, please skip it. You can import your contacts<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/how-to-grow-linkedin/#fn2" id="fnref2">[2]</a></sup> later if you wish.</p>
<p>With that finished, continue reading to define your professional brand on LinkedIn.</p>
<h2>Add Your Work and Education History</h2>
<p>Your work and education history is a vital part of your professional qualifications. Take the time to tell your complete story. Explain how each experience helped you <strong>develop skills</strong> related to your career.</p>
<ol>
<li>Add your entire history to your profile. A complete picture of your career will help others understand and connect with you. LinkedIn does not restrict its length.</li>
<li>Each part of your history should link to a relevant page. For example, you should reference the company page created by your employer. That link will allow others to find you through that page.</li>
<li>Use your resume as a template for your history. Your resume already contains much of your work and education history, so this will save some time. If you ever join the job search, recruiters will compare your resume and LinkedIn profile. Tell a consistent story.</li>
<li>Write complete sentences using active verbs to describe what you did in each role.</li>
<li>Include relevant keywords to allow others to find you based on your history.</li>
</ol>
<p>For more details on sharing your work history, read the article, <a href="https://www.linkedin.com/pulse/20140709061710-108230503-12-tips-to-improve-your-work-experience-section-on-linkedin/">12 Tips to Improve Your Work Experience Section on LinkedIn</a>.</p>
<h2>Tell Others about Your Skills</h2>
<p>Your skills are valuable keywords that make your profile discoverable. Customers for your business may want to verify your skills, especially if you own a consulting company. If you are an employee, recruiters will use your list of skills to search for potential hires. Your colleagues also want to network with others that have similar skills.</p>
<p>When your profile boasts a complete list of your skills, you open the door to those connections. Then, when others endorse your skills, they let the world know you are a qualified professional.</p>
<p>To add the <strong>Skills</strong> section to your profile,</p>
<ol>
<li>Click the <strong>Add profile section</strong> link below the profile banner.</li>
<li>Select <strong>Skills</strong> from the dropdown.</li>
<li>Input the name of a skill, then select it from the dropdown that appears.</li>
<li>Continue adding your skills until your list is complete.</li>
</ol>
<p>When you complete this step, browse a few profiles of your colleagues. Identify their top skills. To endorse them,</p>
<ol>
<li>Click the <strong>Plus</strong> icon beside a skill they have mastered.</li>
<li>Follow the prompts to enter details about your working relationship.</li>
<li>When you complete the endorsement, a <strong>Check Mark</strong> icon will be visible next to the endorsed skill.</li>
</ol>
<p><em>Reciprocity is a powerful thing.</em> After your endorsements, send a personal message asking them to endorse you in return.</p>
<p>If you want to research how the marketplace describes your skills, read <a href="https://mashable.com/archive/non-technical-skills-linkedin">The Expert Trick to Hone Your Skills Section on LinkedIn</a>.</p>
<h2>Include a Professional Photo</h2>
<p>Images are powerful. Use them on LinkedIn. Your photo should be professional, friendly, and authentically you. Put your best foot forward.</p>
<p>Professional photographers are worth the investment. That said, if you need to save money, there are alternatives. Loved ones can often capture candid-but-professional images.</p>
<p>Get a second opinion from someone you trust before posting an image on LinkedIn.</p>
<p>For more detailed tips, read <a href="https://blog.linkedin.com/2014/07/14/a-professional-photographers-guide-to-getting-the-right-linkedin-profile-photo">A Professional Photographer’s Guide to Getting the Right LinkedIn Profile Photo</a>.</p>
<h2>Upload a Background Image</h2>
<p>A background image appears behind your photo on LinkedIn. A well-chosen background graphic or photo shows off your personality, interests, or location. You may want to show off your favorite bike trails in the woods, your design portfolio, or even outdoor hunting photos.</p>
<p>Whatever amplifies your professional identity will help others get to know you.</p>
<p>To add your background image from your profile page,</p>
<ol>
<li>Click the <strong>Camera</strong> icon on the top right corner of your profile.</li>
<li>Click <strong>Upload photo</strong> to choose an image from your computer and then click <strong>Open.</strong></li>
<li>Click <strong>Apply</strong> to add your background image.</li>
</ol>
<p>For another point of view on background images, read <a href="https://www.linkedin.com/pulse/3-tips-optimal-linkedin-background-image-lindsey-stemann/">3 Tips for the Optimal LinkedIn Background Image</a>.</p>
<h2>Write a Compelling Headline</h2>
<p>Your headline is only 120 characters long. Use them well. Replace the default headline LinkedIn generates from your work history. Swap that out with something that makes you stand out. Make it about what you can do for others.</p>
<p>My LinkedIn headline is a work in progress. Today it is short and to the point: <em>Every business should stand out from the crowd. I can help.</em></p>
<p>Perhaps it should include more context and keywords describing how I can help. Maybe I should talk about web design, branding, and marketing—still, it is a good start. If you write something similar with a few more specifics, you will not go wrong.</p>
<p>There is much more to consider when writing a headline. Read <a href="https://www.forbes.com/sites/williamarruda/2018/05/08/how-to-write-the-perfect-headline-for-your-linkedin-profile/#176da8681e8a">How To Write The Perfect Headline For Your LinkedIn Profile</a> for more advice.</p>
<h2>Complete Your About Section</h2>
<p>The <strong>About</strong> section offers you an opportunity to sell yourself in 2,000 words. Use this section to tell your story. List your skills and valuable experiences. Use clear, short sentences with liberal paragraph breaks.</p>
<p>Experts recommend you think of this section as a biography. You may wish to share soft skills you would not include on your resume.</p>
<p>To learn more help, read <a href="https://executivecareerbrand.com/how-to-write-a-dazzling-linkedin-summary/">How to Write a Dazzling LinkedIn About Section</a>.</p>
<h2>Customize Your Public Web Address</h2>
<p>Every LinkedIn member can customize the web address for their profile page. Your custom web address will be readable and easy to share in print and on the web. Doing this says you are someone who pays attention to the details of professional life.</p>
<ol>
<li>Click the <strong>Me</strong> icon at the top of your LinkedIn homepage.</li>
<li>Click <strong>View profile.</strong></li>
<li>At the top right of the page, click <strong>Edit public profile & URL.</strong></li>
<li>Click the edit icon next to your public profile URL on the right.</li>
<li>Customize your URL and click <strong>Save.</strong></li>
</ol>
<p>For more on custom web addresses, read <a href="https://www.forbes.com/sites/lizryan/2015/06/09/how-to-create-your-custom-linkedin-profile-url-and-how-to-use-it/#c60a86d73c5f">How To Create Your Custom LinkedIn Profile URL And How To Use It</a>.</p>
<h2>Grow Your Connections</h2>
<p>Use LinkedIn search to <strong>find colleagues</strong>. Your past work and education experience are rich sources of relationships. Invite them to connect. LinkedIn recommends including a personal note to provide context for any connection request. A thoughtful comment creates goodwill and makes others more likely to respond.</p>
<p>Many influential people on LinkedIn are open to connection requests. They often welcome connections, even if you are not a personal friend. I have connected with authors, journalists, and consultants I respect. I sent them a note of thanks or asked for help. In return, they were happy to connect.</p>
<p>This openness to my requests has surprised me. Perhaps a thoughtful note goes a long way in relationship building. But it is likely more about them than me. I think their openness may be why the business world rewarded them with influence.</p>
<p>Before we wrap up, here are some more tips on building connections:</p>
<ol>
<li>Share high-quality content related to your skills. Set a schedule and stick to it.</li>
<li>Avoid off-topic posts. LinkedIn is not Facebook.</li>
<li>Mention<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/how-to-grow-linkedin/#fn3" id="fnref3">[3]</a></sup> colleagues to publicly congratulate them and the company.</li>
<li>Share professional wins like completed projects or promotions.</li>
<li>Find and contribute to groups related to your skills and interests.</li>
</ol>
<p>For more tips on building your LinkedIn connections, read <a href="https://www.socialmediaexaminer.com/5-ways-to-use-linkedin-groups-to-build-influential-connections/">5 Ways to Use LinkedIn Groups to Build Influential Connections</a>.</p>
<h2>Congratulations on Your Completed Profile</h2>
<p>This process was not complicated, but I am sure it felt like work. Thank you for your diligence. Your career will be more visible to others because of it.</p>
<p>Every day this month, find several valuable insights shared by your colleagues. Encourage them with comments and shares. We are no longer face-to-face, but we can still have a profound positive impact on each other.</p>
<p>As a business owner, make it a high priority to use LinkedIn effectively to grow your professional brand. As you clarify who you are and who you serve, your business will flourish<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/how-to-grow-linkedin/#fn4" id="fnref4">[4]</a></sup>.</p>
<h2>Footnotes</h2>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/">Free and Easy Ways You Can Grow Your Business with a LinkedIn Page</a> <a href="https://www.harveyramer.com/article/how-to-grow-linkedin/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p><a href="https://www.linkedin.com/help/linkedin/answer/2909/creating-and-uploading-a-contacts-file?lang=en">Creating and Uploading a Contacts File: LinkedIn</a> <a href="https://www.harveyramer.com/article/how-to-grow-linkedin/#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p><a href="https://www.linkedin.com/help/linkedin/answer/34936/mention-people-in-your-posts?lang=en">Mention People in Your Posts: LinkedIn</a> <a href="https://www.harveyramer.com/article/how-to-grow-linkedin/#fnref3" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn4" class="footnote-item"><p><a href="https://www.harveyramer.com/article/your-business-is-better/">Your Business Is Better, But for Whom?</a> <a href="https://www.harveyramer.com/article/how-to-grow-linkedin/#fnref4" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
3 Ways You Can Boost Your Website's Results
2020-09-02T00:00:00Zhttps://www.harveyramer.com/article/three-ways-to-boost-website-results/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706043722/three-ways-to-boost-website-results.png" alt="three-ways-to-boost-website-results" /></p>
<p>Every small business owner wants a thriving bottom line. Revenue is the life-blood of a business. A website should contribute to our sales efforts, but it is hard to attract customers online.</p>
<p>We enter this world invisible to everyone but those closest to us. We grow socially and form relationships—expanding our influence and visibility to others. People begin to know us, trust us, and listen to us. A few of us find new ways to be of service and start businesses.</p>
<p>Starting a business requires us to expand our influence even more. The alternative is to succumb to invisibility and close our doors.</p>
<p>Getting visitors to a website that tells the story of your business is vital. When your website works well, some of those visitors will become customers.</p>
<h2>What To Expect from Your Website</h2>
<p>According to a 2019 Bright Local<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/three-ways-to-boost-website-results/#fn1" id="fnref1">[1]</a></sup> study of more than 11,000 companies, business websites get <strong>50% of their visitors</strong> from search engine queries. This <em>organic</em> traffic does not cost business owners any money. <strong>37% of their visitors</strong> are <em>direct</em>, which means the user knew their web domain or followed a link in an email or text message. About <strong>10% of their visitors</strong> are <em>referrals</em> from a link embedded in another website. <strong>Only a small percentage</strong> of their visitors discover them on social media. Social media marketing, especially, has growth potential.</p>
<p>Most small businesses shun paid search advertising. That oversight may cost them. Even micro-enterprises can use it to attract a ready supply of ready-to-buy visitors. While we are bullish on search engine advertising, we recommend caution. Only when your website engages users will there be a return on investment. Your average sale value impacts the advertising strategy you choose. With a higher average sale value and profit margin, you have more room to experiment with paid search.</p>
<h2>3 Things To Do for Better Results</h2>
<p>An effective digital marketing strategy will include:</p>
<ol>
<li>Creating social media profiles<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/three-ways-to-boost-website-results/#fn2" id="fnref2">[2]</a></sup> and company pages <sup class="footnote-ref"><a href="https://www.harveyramer.com/article/three-ways-to-boost-website-results/#fn3" id="fnref3">[3]</a></sup></li>
<li>Clarifying taglines and calls to action</li>
<li>Ditching or defining technical terms</li>
</ol>
<h3>Get Active on Social Media</h3>
<p>Not every business will have the same success with a social media strategy. But it always works as an outreach tool. It lets you talk to future customers at scale before they visit your website.</p>
<p>Every small business can boost visibility with a free profile on LinkedIn, Instagram, Pinterest, and Twitter<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/three-ways-to-boost-website-results/#fn4" id="fnref4">[4]</a></sup>. Having business profiles does not mean you must invest equally in content creation on each platform. Despite limited engagement, social media profiles will have value. They let prospective customers find your business where they hang out.</p>
<p>A successful digital strategy does not demand the same amount of work on each platform. A business selling to other business owners may post on LinkedIn every day but rarely on Facebook, Instagram, or Twitter. Another company whose clientele is mainly female may invest heavily in their Pinterest presence.</p>
<p>Your brand, customer age, and product’s visual appeal will inform your platform choices. Make a social media plan and test each platform. Vary the content, format, and timing of posts. Learn from the engagement of users with content and adapt your approach.</p>
<h3>Clarify Your Tagline</h3>
<p>Most websites suffer from a lack of focus. Creative, catchy-but-empty phrases float over elegant-but-nondescript images. Popups interrupt the user, distracting them from learning about your business. Visitors to such websites do not stay long.</p>
<p>First, define a clear goal for your website’s home page. Not three goals or two goals—one goal is all your home page needs. Visitors form an opinion about your website within milliseconds of landing on a page. If they do not understand what the page is about, they will move on. We have found one of the best ways to focus on a home page’s purpose is to write, or rewrite, your business tagline.</p>
<p>Second, with a clear tagline in hand, remove distractions from your home page. Focus on the single goal you have identified. You may need to make some hard choices. One department may set their heart on sharing an ad for their fall sale. Another may want to make sure an image of their latest event is prominent. Internal business politics should not impact your home page. It is there for one reason—to serve your potential customer.</p>
<p>You may be able to have more than one call to action on your home page with good results. But never forget the primary goal of your page. This principle is central to all well-designed marketing tools.</p>
<h4>The Tagline Process</h4>
<p>Every business can improve its marketing with this exercise:</p>
<ol>
<li>Read Donald Miller’s article, <a href="http://buildingastorybrand.com/4-common-mistakes-to-avoid-with-your-tagline/">4 Common Mistakes to Avoid with Your Tagline</a></li>
<li>Learn how happy customers talk about your business
<ul>
<li>Read over customer testimonials you have collected</li>
<li>Have some conversations with a customer about what makes you unique and valuable</li>
</ul>
</li>
<li>Using the feedback you have gathered, write three or four versions of a tagline</li>
<li>The following day, try your hand at a few more taglines</li>
<li>Ask for feedback on the top two choices from a trusted customer or advisor</li>
<li>Use the winner on your home page</li>
</ol>
<h3>Ditch (or Define) Jargon and Simplify</h3>
<p>Your college professors may have rewarded you for using technical and complex language. Unlearn this pattern. Convoluted vocabulary may impress visitors, but it fails to call them to action. Worse, it drives them away from your business.</p>
<p>Here is how we write for the web:</p>
<ol>
<li>Keep sentences as short as possible</li>
<li>Replace or define jargon</li>
<li>Avoid empty words
<ul>
<li>Using <em>that</em> causes wordy sentences</li>
<li><em>Even</em> is a suspect term—replace it</li>
</ul>
</li>
<li>Prefer lists over commas</li>
<li>Use headings and subheadings for visual hierarchy</li>
<li>Do not forget the spell checker</li>
<li>When you stop writing, check and revise your writing with <a href="https://hemingwayapp.com/">Hemingway App</a></li>
<li>Before you publish, a grammar checker like <a href="https://www.grammarly.com/">Grammarly</a> can save you embarrassment.</li>
</ol>
<p>Using this process helps you write with clarity and power. Such writing guides a reader’s eye rather than frustrating them. Removing friction benefits your readers.</p>
<h2>Prefer Action Over Analysis</h2>
<p>This article contains time-tested, proven ways you can improve your website today. Take time to think it through. Don’t overthink it<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/three-ways-to-boost-website-results/#fn5" id="fnref5">[5]</a></sup>; test these ideas. See what works. You will have some wins when you do.</p>
<p>Most business websites fail to live up to their potential. Either they fail to attract visitors or repel the visitors who find them. If you get active on social media, clarify your tagline, and ditch jargon, you will begin to stand out from the rest.</p>
<h2>Footnotes</h2>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="https://www.brightlocal.com/research/google-analytics-for-local-businesses-study/">Google Analytics for Local Businesses Study</a> <a href="https://www.harveyramer.com/article/three-ways-to-boost-website-results/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p><a href="https://www.harveyramer.com/article/how-to-grow-linkedin/">9 Easy Ways You Can Boost Your LinkedIn Influence</a> <a href="https://www.harveyramer.com/article/three-ways-to-boost-website-results/#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p><a href="https://www.harveyramer.com/article/free-easy-grow-linkedin/">Free and Easy Ways You Can Grow Your Business with a LinkedIn Page</a> <a href="https://www.harveyramer.com/article/three-ways-to-boost-website-results/#fnref3" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn4" class="footnote-item"><p>Get started with <a href="https://www.linkedin.com/">LinkedIn</a>, <a href="https://www.facebook.com/business">Facebook</a>, <a href="https://business.instagram.com/">Instagram</a>, <a href="https://business.pinterest.com/">Pinterest</a>, and <a href="https://business.twitter.com/en/basics/create-a-twitter-business-profile.html">Twitter</a>. <a href="https://www.harveyramer.com/article/three-ways-to-boost-website-results/#fnref4" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn5" class="footnote-item"><p><a href="https://www.harveyramer.com/article/choose-action-over-analysis/">Choose Action Over Analysis</a> <a href="https://www.harveyramer.com/article/three-ways-to-boost-website-results/#fnref5" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
Focus on the Easy Bits: CI/CD with Azure and Github
2020-05-04T03:13:26Zhttps://www.harveyramer.com/article/cicd-azure-github/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706043723/focus-on-the-easy-bits-ci-cd-with-azure-and-github.png" alt="focus-on-the-easy-bits-ci-cd-with-azure-and-github" /></p>
<p>This tutorial will get you started with a basic CI/CD workflow using Github Actions to deploy a Web application to Azure.</p>
<h2>CI/CD Overview</h2>
<p>CI/CD is an acronym representing <em>continuous integration</em> and <em>continuous delivery</em>. According to CI/CD, the quality of software is correlated to how often it is deployed. If the deployment process is difficult, the quality of software will inevitably be low. If it is easy to make small changes and deploy them without much risk, software quality increases over time. It all starts with the practices and tools we use to create and manage software code.</p>
<h3>Basic Version Control Concepts</h3>
<ul>
<li><strong>Distributed Version Control</strong>: It is difficult to implement CI/CD without a distributed version control system <a href="https://en.wikipedia.org/wiki/Distributed_version_control">(DVCS)</a> such as <a href="https://git-scm.com/">Git</a>. Git fosters collaboration by allowing developers to make changes independently and reconcile those changes effectively. Older version control systems like <a href="https://subversion.apache.org/">SVN</a> are less flexible. Complicated merges often make deployment difficult.</li>
<li><strong>Trunk</strong>: the copy of files representing the latest deployable version of software</li>
<li><strong>Cut a Branch</strong>: Make a copy of the software that can be changed independently</li>
<li><strong>Feature Branch</strong>: A copy of the software created for the purpose of making and testing changes before integrating with trunk</li>
<li><strong>Pull Request</strong>: Tools such as <a href="https://github.com/">Github</a> and <a href="https://bitbucket.org/">Bitbucket</a> allow a developer to signal to their team that their work is completed and ready for review. On approval, a pull request is merged to trunk.</li>
<li><strong>Merge Conflict</strong>: Developers sometimes make changes to the same lines of code independently. This causes a conflict when a pull request requires a code merge.</li>
</ul>
<h3>Continuous Delivery</h3>
<p>Continuous delivery is a way of moving software changes to production. When it is implemented, software changes go live with a minimum manual intervention and very little deployment pain. Continuous delivery requires business practices such as <strong>building quality in</strong>, <strong>working in small batches</strong>, <strong>automating repetitive tasks</strong>, <strong>continuous improvement</strong>, <strong>sharing responsibility</strong> and <strong>collaborating across departments</strong>.<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/cicd-azure-github/#fn1" id="fnref1">[1]</a></sup></p>
<h3>Continuous Integration</h3>
<p>Continuous integration helps us achieve continuous delivery. It is a method of writing software that prevents rework and long-lived, divergent projects. To achieve continuous integration, break work into small batches. These batches should be completed in a day or less. The developer starts their work by cutting a feature branch. When she completes the work, she opens a pull request and invites team review, then merges the feature into trunk. This reduces errors, increases developer learning, and facilitates collaboration.</p>
<p>Testing is key to the success of continuous integration. This includes automated unit tests and automated deployment to a testing environment on merging a pull request to trunk. Not everything relies on automation, however. Developers must manually verify their changes in the testing environment when they are deployed.</p>
<p>This is often called <strong>trunk-based development</strong>.</p>
<blockquote>
<p>At the end of each development interval, we must have integrated, tested, working, and potentially shippable code, demonstrated in a production-like environment, <strong>created from trunk using a one-click process, and validated with automated tests</strong>.<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/cicd-azure-github/#fn2" id="fnref2">[2]</a></sup></p>
</blockquote>
<h3>Unit Tests</h3>
<p>Unit tests are simple programs that prove the program behaves predictably. A critical part of continuous integration is the assurance that if code is broken, unit tests will fail. This, in turn, means the deployment will fail. Broken code will not make it to production.</p>
<h2>Prerequisites</h2>
<ol>
<li><a href="https://dev.to/bdbch/setting-up-ssh-and-git-on-windows-10-2khk">Github account configured to use SSH</a></li>
<li>If you are unfamiliar with Node.js, please review the my COVID-19 Tracker tutorials:
<ul>
<li><a href="https://www.harveyramer.com/article/2020-04-09-start-here-to-make-a-useful-covid-19-tracker-with-node-js/">Start Here to Make a Useful COVID-19 Tracker with Node.js</a></li>
<li><a href="https://www.harveyramer.com/article/2020-04-10-making-an-even-more-useful-covid-19-tracker-with-node-js/">Making an Even-More-Useful COVID-19 Tracker with Node.js</a></li>
<li><a href="https://www.harveyramer.com/article/2020-04-26-get-the-drop-on-the-cloud-nodejs-and-azure/">Get the Drop on the Cloud: Node.js and Azure</a></li>
</ul>
</li>
<li>Install the Azure CLI
<ul>
<li><a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-windows?view=azure-cli-latest">On Windows</a></li>
<li><a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-macos?view=azure-cli-latest">On Mac</a></li>
<li><a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest">Others</a></li>
</ul>
</li>
<li>Log in to your Azure account in the CLI <code>az login</code></li>
</ol>
<h2>Manage the Code</h2>
<p>Since you want Github to deploy on your behalf, create your own repository for it.</p>
<pre><code class="language-shell-script">git clone git@github.com:harveyramer/covid-19-demo-express-js-app.git
cd covid-19-demo-express-js-app
</code></pre>
<p><img src="https://www.harveyramer.com/img/make-a-repository.png" alt="Make a Github Repository" title="Make a Github Repository" /></p>
<p>Name it whatever you wish, choose to make it public or private, and create your repository.</p>
<p>Replace the origin of this project (<a href="mailto:git@github.com">git@github.com</a>:harveyramer/covid-19-demo-express-js-app.git) with your own and push this code to your repository. Assuming your name is <strong>John Doe</strong> and you named your repository <strong>My Repository</strong>, your commands will be the following.</p>
<pre><code class="language-shell-script">git remote set-url origin git@github.com:johndoe/my-repository.git
git push
</code></pre>
<p>To check out the latest branch and install the project, execute the following commands.</p>
<pre><code class="language-shell-script">git checkout tutorial-3
npm install
</code></pre>
<h3>Run the Tests</h3>
<p>This project uses the <a href="https://jestjs.io/">Jest</a> unit testing framework to run two simple unit tests. One verifies that a <code>getData</code> function calls a specified API Url. The other checks to see that an HTML render function uses the data provided to it. Go ahead and run the unit tests to verify that this project is ready to deploy.</p>
<pre><code class="language-shell-script">npm run test
</code></pre>
<p><img src="https://www.harveyramer.com/img/unit-test-success.png" alt="Unit Test Success" title="Unit Test Success" /></p>
<h2>Configure Continuous Integration</h2>
<h3>Authorizing Azure</h3>
<p>At the outset of this tutorial, you logged in to Azure with the command <code>az login</code>. This redirected you to a browser and authorized your local command line to access resources on your behalf. Now you will create a <a href="https://docs.microsoft.com/en-us/cli/azure/create-an-azure-service-principal-azure-cli?view=azure-cli-latest">Service Principal</a> which will be used to authorize Github to deploy on your behalf. If you followed along on our <a href="https://www.harveyramer.com/article/2020-04-26-get-the-drop-on-the-cloud-nodejs-and-azure/">previous tutorial</a>, you already have an application running in Azure. Replace the tokens <code>{My App Name}</code>, <code>{My Azure Subscription Id}</code>, and <code>{My App Service Plan Id}</code> then execute the following command.</p>
<pre><code class="language-shell-script">// Your command will look like this:
// az ad sp create-for-rbac --name "covid19tutorial" --role contributor --scopes /subscriptions/7d806f61-8462-123456789-101112-985277452dd7/resourceGroups/appsvc_linux_centralus --sdk-auth
az ad sp create-for-rbac --name "{My App Name}" --role contributor --scopes /subscriptions/{My Azure Subscription Id}/resourceGroups/{My App Service Plan Id} --sdk-auth
</code></pre>
<p>The App Service blade in Azure provides all the information you need to configure and run the command above.</p>
<p><img src="https://www.harveyramer.com/img/data-for-your-app.png" alt="App Service Blade" title="The App Service Blade" /></p>
<p>When your Service Principal is created, a JSON object is output in the CLI.</p>
<ol>
<li>Copy the Service Principal object</li>
<li>In a Web browser, go to your Github repository</li>
<li>Navigate to your repository’s <em>Settings</em> page and select <em>Secrets</em> from the menu it provides.</li>
<li>In the <em>Secrets</em> view, select <strong>Add a new secret</strong>.</li>
<li>Name the secrete <code>AZURE_CREDENTIALS</code> and paste your JSON service principal into the <em>Value</em> field.</li>
<li>Add the secret.</li>
</ol>
<p><img src="https://www.harveyramer.com/img/adding-a-github-secret.png" alt="Adding a Github Secret" title="Adding a Github Secret" /></p>
<h3>Set Up a Github Workflow</h3>
<p>Open the workflow file at <code>.github/worflows/azure.yml</code> and change line 7. It should use the same Application Name you provided when creating the Service Principal.</p>
<p><img src="https://www.harveyramer.com/img/azure-yml.png" alt="Editing the Azure YAML file" title="Editing the Azure YAML file" /></p>
<h2>Deploy with Github Actions</h2>
<p>On pushing these code changes to the <strong>master</strong> branch, our Github workflow will kick off. To make that happen, we will push our code to Github and merge our changes to the <strong>master</strong> branch. To do that, we’ll be on the command line for a bit. Bear with me.</p>
<pre><code class="language-shell-script">git add .
git commit -m "Configuration changes for Github workflows."
git push
git checkout master
git pull origin tutorial-3
git push
</code></pre>
<p>Navigate to the Actions tab of your Github repository. If all is well, in about 5 minutes, your Web app will deploy to Azure.</p>
<p><img src="https://www.harveyramer.com/img/successful-deployment.png" alt="Successful deployment of Node.js to Azure with Github" title="Successful deployment of Node.js to Azure with Github" /></p>
<h3>Verify Deployment</h3>
<p>Open the <code>/src/views/about.pug</code> file and add the following line to the end of the file, then save it.</p>
<pre><code class="language-pug"> p Deployed by Github to Azure
</code></pre>
<p>Next, commit the change and push it up to master.</p>
<pre><code class="language-shell-script">git add .
git commit -m "Verify Github deployment."
git push
</code></pre>
<p>Check out your Actions tab to monitor deployment. On completion, visit your Web app’s About page (for example, <strong>*covid19tutorial-myname</strong>.azurewebsites.net/about*) to see the paragraph you just deployed.</p>
<p><img src="https://www.harveyramer.com/img/success-verification.png" alt="Successful deployment" title="Successful deployment" /></p>
<h2>Conclusion</h2>
<p>This tutorial introduced CI/CD concepts and showed an example of <em>Continuous Integration</em> by deploying changes made in a feature branch to Azure. We skipped over some other concepts such as <a href="https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests">Pull Requests</a>, <a href="https://docs.github.com/en/get-started/quickstart/fork-a-repo">forking Github repos</a>, and the <a href="https://blog.trello.com/microproductivity-break-tasks-into-smaller-steps">benefits of breaking large tasks into small chunks</a>. These, you are encouraged to investigate on your own.</p>
<h2>Extra Credit</h2>
<h3>Add an Environment Variable</h3>
<p>If you would like to run this project locally, you will need to add an environment variable. On line 6 of the <code>/src/index.js</code> file, you can see why. The <code>process.env</code> property holds all environment variables exposed to this program.</p>
<pre><code class="language-javascript">const port = process.env.PORT;
</code></pre>
<p>To expose a port to our application, create a <code>.env</code> file in the root of the project. Enter the following line into the file.</p>
<pre><code class="language-shell-script">PORT=3000
</code></pre>
<p>This completes our local configuration. Start the local server.</p>
<pre><code class="language-shell-script">npm run start
</code></pre>
<p>Verify the project is available at <code>http://localhost:3000</code>.</p>
<h2>Footnotes</h2>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Ferguson, Nicole Phd., Humble, Jez and Gene Kim. <em>Accelerate: Building High Performing Technology Organizations</em>. IT Revolution, 2018, p. 43 <a href="https://www.harveyramer.com/article/cicd-azure-github/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Kim, Gene., Jez Humble, Patrick Dubois, and John Willis. <em>The DevOps Handbook: How to Create World-Class Agility, Reliability, and Security in Technology Organizations</em>. IT Revolution, 2016, p. 149 <a href="https://www.harveyramer.com/article/cicd-azure-github/#fnref2" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
Get the Drop on the Cloud: Node.js and Azure
2020-04-26T04:45:00Zhttps://www.harveyramer.com/article/nodejs-azure/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706043723/get-the-drop-on-the-cloud-nodejs-and-azure.png" alt="get-the-drop-on-the-cloud-nodejs-and-azure" /></p>
<p>Deploying applications to the cloud can be intimidating. Don’t worry though, this guide will stick to the bare essentials. When you’ve finished here, you will have a web application running on Azure.</p>
<p>Take care of some things before you begin. The tools below will allow you to complete the tutorial work. There may be other VS Code extensions that will do the same job, so feel free to try any tools that make sense to you.</p>
<ol>
<li><a href="https://azure.microsoft.com/en-us/free/">Create a free Azure account</a></li>
<li><a href="https://code.visualstudio.com/docs/setup/setup-overview">Install Visual Studio Code (VS Code)</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-node-azure-pack">Add the Azure Tools Extension Pack</a> to Visual Studio Code</li>
<li><a href="https://www.harveyramer.com/article/2020-04-08-configure-a-nodejs-development-environment-on-windows-10/">Install NodeJS</a></li>
</ol>
<p><img src="https://www.harveyramer.com/img/installed-azure-tools.png" alt="Azure App Service Extension Installed" title="Azure App Service Extension Installed" /></p>
<h3>Log In to Azure</h3>
<p>In VS Code, open the command palette (<code>Ctrl+Shift+P</code>) and enter <code>> Azure: Sign In</code>. You will be prompted to log in via a browser window. When complete, you will see your subscriptions listed in your Azure panel.</p>
<p><img src="https://www.harveyramer.com/img/log-in-to-azure-vscode.png" alt="Signing in to Azure with VS Code" title="Signing in to Azure with VS Code" /></p>
<h2>Start Coding</h2>
<h3>Installing the COVID-19 Tracker</h3>
<p>For this project, use the COVID-19 Tracker project.<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/nodejs-azure/#fn1" id="fnref1">[1]</a></sup></p>
<ol>
<li>clone or download the repository (<code>git clone git@github.com:harveyramer/covid-19-demo-express-js-app.git</code>)</li>
<li>Navigate in your terminal to the root directory (<code>cd covid-19-demo-express-js-app</code>)</li>
<li>Check out this branch (<code>git checkout tutorial-2</code>)</li>
<li>Install the project (<code>npm install</code>)</li>
<li>Start the server (<code>npm start</code>)</li>
<li>Navigate to your project in a browser (<a href="http://localhost:3000/">http://localhost:3000</a>)</li>
</ol>
<h3>Preparing for Deployment</h3>
<p>Since Azure’s App Service uses dynamically configured <a href="https://docker-curriculum.com/">Docker containers</a>, you cannot specify a port in our code. Instead, rely on an <a href="https://medium.com/chingu/an-introduction-to-environment-variables-and-how-to-use-them-f602f66d15fa">environment variable</a>.</p>
<ol>
<li>Make sure your local server is not running (<code>Ctrl+C</code>).</li>
<li>Open the <code>src/index.js</code> file and update line 5.</li>
</ol>
<pre><code>const port = process.env.PORT
</code></pre>
<h2>Deploying to Azure App Service</h2>
<p>The extensions in the Azure Tools pack you installed make it easy to deploy a Web app. To show the Azure panel in VS Code, click on the Azure logo on the left. Then, click the <em>Deploy to Azure</em> arrow button in the App Service menu bar.</p>
<p><img src="https://www.harveyramer.com/img/deploy-to-azure.png" alt="Deploy to Azure App Service" title="Deploy to Azure App Service" /></p>
<p>The Azure App Service extension’s wizard will help you deploy your app.</p>
<ol>
<li>Select the <em>covid19-tracker</em> folder to zip and deploy</li>
<li>Choose <em>Create new Web App…</em></li>
<li>Next enter a unique name for your Web app. (<code>covid19tutorial-myname</code>)</li>
<li>Select runtime <em>Node 12 LTS</em></li>
<li>Wait a few minutes while Azure provisions the resources for your Web app</li>
<li>When asked, “Would you like to update your workspace configuration to run build commands on the target server?” Answer, <em>“Yes.”</em></li>
<li>To monitor the build process, show the output window.</li>
</ol>
<p><img src="https://www.harveyramer.com/img/show-build-output.png" alt="Show Azure deployment output window" title="Show Azure deployment output window" /></p>
<p>When deployment finishes, browse to your new website. It will use the unique name you specified, for example, <em><strong>covid19tutorial-myname</strong>.azurewebsites.net</em>. Your app will not respond and may display an application error. This is normal. We have one more configuration step.</p>
<h3>Add an Application Setting</h3>
<p>You will need to add an <em>Application Setting</em> to tell Azure App Service what version of Node.js to use.</p>
<ul>
<li>Expand your subscription, Web app, and right-click on <strong>Application Settings</strong></li>
<li>Choose <em>Add New Setting</em></li>
<li>For your setting key, enter <code>WEBSITE_NODE_DEFAULT_VERSION</code></li>
<li>For your setting value, enter <code>12-lts</code></li>
</ul>
<p><img src="https://www.harveyramer.com/img/add-application-setting.png" alt="Add WEBSITE_NODE_DEFAULT_VERSION application setting" title="Add WEBSITE_NODE_DEFAULT_VERSION application setting" /></p>
<p>Adding a new application setting causes the App Service to restart, which can take several minutes. If your Web app does not start in 10 minutes, see <a href="https://www.harveyramer.com/article/nodejs-azure/#troubleshooting">Troubleshooting</a> below.</p>
<h3>Monitoring your App with Logs</h3>
<p>Since it takes several minutes for your app to warm up after being deployed to Azure, it helps to monitor the Log Stream for your application. To do that, Expand your application’s <em>Logs (Read-only)</em> folder and click <em>Connect to Log Stream…</em> An output panel in the terminal will allow you to monitor your application’s progress.</p>
<p><img src="https://www.harveyramer.com/img/monitor-application-logs.png" alt="Web application log monitoring." /></p>
<p>When you see <em>Example app listening at <a href="http://localhost:8080/">http://localhost:8080</a></em> your app is warmed up and ready to take some requests.</p>
<h3>Success</h3>
<p>Your first deployment of a Web app with Node.js to Azure can be a bit tricky. When you succeed, your <a href="https://covid19tutorial.azurewebsites.net/">COVID-19 Tracker</a> will be live for the world to see. If you want to share it with friends, you may want to upgrade from the <a href="https://docs.microsoft.com/en-us/azure/app-service/app-service-plan-manage">free App Service Plan</a>, which only runs for an hour each day.</p>
<p><img src="https://www.harveyramer.com/img/your-deployed-web-app.png" alt="Your deployed Web app" title="Your deployed Web app" /></p>
<h3 id="troubleshooting">Troubleshooting</h3>
<p>If your deployment fails on the first try, as mine did, it is likely a timing issue. Some resources your Web app depends on were not provisioned when it tried to start.</p>
<p><img src="https://www.harveyramer.com/img/service-unavailable.png" alt="The service is unavailable" title="The service is unavailable" /></p>
<p>Make sure you have completed all the steps above. If your app still does not start after 10 minutes, either dig into Azure’s <a href="https://docs.microsoft.com/en-us/azure/app-service/app-service-web-nodejs-best-practices-and-troubleshoot-guide">Node.js troubleshooting documentation</a>, or use the nuclear option. I have found that deleting your Web Application and starting over resolves the problem.</p>
<h2>Footnotes</h2>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="https://www.harveyramer.com/article/2020-04-09-start-here-to-make-a-useful-covid-19-tracker-with-node-js/">Start Here to Make a Useful COVID-19 Tracker with Node.js</a> and <a href="https://www.harveyramer.com/article/2020-04-10-making-an-even-more-useful-covid-19-tracker-with-node-js/">Making an Even-More-Useful COVID-19 Tracker with Node.js</a> <a href="https://www.harveyramer.com/article/nodejs-azure/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
Stop Coding Under Stress: Avoiding Bugs & Catastrophes
- FEATURED
2020-04-20T04:05:51Zhttps://www.harveyramer.com/article/coding-stress-bugs-catastophes/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1709212982/stop-coding-under-stress-how-to-avoid-bugs-and-the-end-of-the-world.png" alt="stop-coding-under-stress-how-to-avoid-bugs-and-the-end-of-the-world" /></p>
<p>Software engineers spend most of their time sitting and thinking. Web developers do the same. So how can jobs like this be stressful? Vague requirements, unrealistic expectations, and a humorless outlook can put any programmer at risk.</p>
<p>The nasty effects of unmanaged stress are often discussed in the media<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn1" id="fnref1">[1]</a></sup> and scientific journals<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn2" id="fnref2">[2]</a></sup>, but many of us try to live as though it doesn’t exist. “Why am I irritable?” we ask, as excess cortisol floods through our bloodstream and our brain’s amygdala arouses a fight-or-flight reflex. Our heart starts thumping, beads of sweat form on our brow, and our minds shut out everything except the object of our fear.</p>
<p>Fight-or-flight may work when fleeing a grizzly bear (though experts advise against it<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn3" id="fnref3">[3]</a></sup>). But it fails us when the object of our stress is an abstract concept. To where must one flee to avoid a feeling of overwhelm?</p>
<p>As the demands of life overwhelm our ability to perform, we experience chronic stress<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn4" id="fnref4">[4]</a></sup>. Every day, the weight of our failure to meet the demands placed on us accumulates. Hormones that were helpful in the short-term become destructive as time goes on. These rogue hormones suppress the immune system and can even lead to heart disease.</p>
<p>You may object that stress is not bad for us. That is true. A moderate amount of stress spurs us to action. “You need some stress,” says Michael D. Watkins, “Without it, not much happens—you stay in bed munching chocolates.”<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn5" id="fnref5">[5]</a></sup> Unless we all want to be chocolate-munching bed-dwellers (which has a certain appeal) we need a bit of positive stress in our lives. We must learn to maximize positive stress and mitigate the negative side of stress.</p>
<h2>Stress and the Programmer at Work</h2>
<p>When I am having a bad day, my words may carry an unintended negative tone. I may overreact to the requests or critical feedback of others. These responses amplify stress for everyone around me. But far more worrisome things result from chronic stress on programmers at work.</p>
<p>Under prolonged stress, we can become pessimistic. This makes creative thinking and learning impossible. “Positive emotions are critical to learning, curiosity, and creative thought,” says usability expert Don Norman.<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn6" id="fnref6">[6]</a></sup> Without a sense of well-being a programmer’s drive to learn and grow will stagnate. Long-term, we become sub-par developers who write low-quality software.</p>
<p>“We have long known,” continues Norman, “that when people are anxious they tend to narrow their thought processes, concentrating upon aspects directly relevant to a problem.” This narrow thinking limits our approach to problem solving. As television detective Burl Loomis says on the show <em>The Good Cop</em>, “It’s been my experience, when a man has been stabbed in the chest that’s pretty much all he wants to talk about.”<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn7" id="fnref7">[7]</a></sup> There are moments of absolute clarity, when only one thing matters. But when we see only the immediate concerns of life, we stumble as we pursue elegant architecture, maintainable programs and bug fixes.</p>
<p>Context matters, and it can dramatically affect how we work as a team. I recall a day when a junior member on my team interrupted me with a question that intrigued me. I helped him work through the problem with as much speed as possible and got back to work. When we deployed his code to production, it became clear that he had introduced a bug. He had consulted with me before writing the code, and I had failed to direct him to a better solution. My tunnel vision caused me to ignore the context of another developer’s problem. When bugs make it past the development team and into production, customers feel the pain, and the cost of production bugs is high.</p>
<p>Stress can also cause a bad user experience in less obvious ways. A pressure-filled design process misses many of the nuances important to users. We forget to hold critical collaborative discussions that clarify issues. We overlook empathy for the user in favor of bottom-line thinking. The end result is far less than what should have been.</p>
<p>Few business leaders can test the security of a Web application. This creates another opportunity for stress to do some damage. Developers, under duress, sometimes sacrifice security for expediency. In their haste, they overlook architectural flaws and bugs in code that open our businesses to hackers. Software development and design teams need a safe place to innovate. Time to think through the impact of each design decision and line of code is essential for security.</p>
<p>With a healthy team we can predict the future and close security holes before we lose data to hackers. When criminals stole customer information<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn8" id="fnref8">[8]</a></sup> from a California property management company, they changed Web platforms to prevent future attacks. What prevented them from upgrading their out-of-date security measures before the attack? Stress may have been a contributing factor.</p>
<p>When stress takes hold, it propagates through misunderstanding and miscommunication. We can react to stress by withdrawing from others. We replace honest conversation with assumptions. We work feverishly to avoid disappointment but produce results no one requested. As we have seen, the cost of such behavior is high.</p>
<p>Managers should see missing communication from a team member as a warning sign. It never hurts to check in and see how a team member is feeling.</p>
<h2>Causes of Programmer Stress</h2>
<p><strong>We are always in a hurry.</strong> Pell-mell completion of half-considered work is a knife in the chest of creativity and a significant cause of stress. The more frenetic the pace, the greater the stress. And when rushed code gets into production, a bad user experience produces a bad developer experience. Managers then apply more pressure without realizing they are compounding the problem. This produces the result we fear: mediocrity and missed deadlines.</p>
<p>This adds to the frustration of a team of motivated software developers. As the time for a production release approaches, anxiety mounts. This unease, Nicole Ferguson says, “highlights the friction and disconnect that exist between the activities used to develop and test software and the work done to maintain and keep software operational.”<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn9" id="fnref9">[9]</a></sup> An effective manager can shield their team from such toxic unrealistic expectations.</p>
<p><strong>The pace of change</strong> is also a stressor, and change in software development tools, languages, and methods is unrelenting. Last year’s innovations belong in this year’s dustbin. Many of our mental models remain, but our tactics are in continual flux. We must keep up. We must always be learning. But time spent learning is inefficient. It requires experimentation and time for reflection.</p>
<p>We will never read all the technical articles, take all the courses, or try all the programming languages. Each new publication is a product vying for our attention. “Try this new framework.” “Check out this fancy new language!” “All the advertising, promotions and pressure employed to tempt us one way or another,” Simon Sinek says, “ultimately yields one consistent result: stress.” <sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn10" id="fnref10">[10]</a></sup> Filtering out the noise and focusing on what we need to know each day is a critical ability.</p>
<h2>Stressed? Write Good Code Anyway</h2>
<p><strong>Respond thoughtfully.</strong> In an environment prone to stress, how should software engineers respond? Though external stressors are unavoidable, we can slow down and react to them on our own schedule. “When you are on the receiving end of a sudden change,” Says Rabbi Daniel Lapin, “you are seldom under any obligation to respond while your soul is still coping with the initial stress.”<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn11" id="fnref11">[11]</a></sup> Take a moment, as much time as you need, before responding to shifts in priority. Don’t risk misunderstanding because you feel a need to respond in the moment.</p>
<p><strong>Insist on clarity.</strong> Which is better? An hour spent thinking, discussing, and writing, or an hour writing code? It’s a trick question. If I am clear on what I must do, I will choose the hour of writing code. But in the absence of clarity, an hour spent writing code is a profligate waste.</p>
<p>When given a task, my first job is to clarify the requirements for the work. Programmers, the people closest to the problem, are well-suited to plan effective solutions. I rarely receive tasks with enough clarity to warrant writing code immediately. We need time for research and planning. It may be nice to skip all that planning, but it would deprive us of using our strategic abilities.</p>
<p><strong>Manage “found work.”</strong> Planning the implementation details of a new feature often uncovers additional unplanned work. Agile software development acknowledges this problem and recommends breaking work into chunks that a team can complete in a short period of time (often two weeks). This “sprint” includes time for collaborative planning and estimation before work begins. During this process we discuss any found work, plan, and communicate changes to our stakeholders.</p>
<p>Traditional software development does not recognize the problem of found work. As one department throws specifications over the wall to another, consternation and change requests multiply. Effective communication mitigates the stress of traditional software development, but an agile approach to planning can simply bypass it.</p>
<p><strong>Take time to play.</strong> “Rule-busting innovation requires a sense of play, a sense of delight, a refusal to be corralled int a strict method,” says Marty Neumeier, “Design is a ‘ludic’ process, from the Latin LUDERE, meaning ‘to play’.”<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn12" id="fnref12">[12]</a></sup> Everyone who writes a line of code is a designer. From the formatting our code to the way we name our variables and methods, we either clarify or confuse the problem. And play helps us see the problem clearly.</p>
<p>Stress narrows our focus. Play opens up possibilities. Though it may be hard, a good response to stress and anxiety is to shrug it off. Step away from the keyboard. Take a brief walk or lean back in your chair and turn the problem over. Be kind to yourself and let your imagination play with a problem. When you can see more than one solution, it may be time to write some code.</p>
<p><strong>Take a walk.</strong> When pushing on an intractable problem makes your heart start racing and you feel a glimmer of desire to change careers, get up. Leave your desk and walk around a bit. You can walk around inside your office building. Look out a window. Step outside and get some sun on your face.</p>
<p>Whatever you do, change your frame of reference and let your subconscious work on the problem for a bit. You might gain an insight that lets you re-frame the problem in a way that is much more easily solved. You’ll save your heart the extra wear and tear as well.</p>
<p><strong>Learn strategically.</strong> We cannot learn it all. This is not a moral judgment, it is a brute fact. Cope with this reality by learning as much as you can on the job. Take a strategic approach to acquiring new skills and knowledge relevant to your work. Subscribe to technology podcasts, read articles and books, and talk to others in your field. Stay informed about the changes coming your way.</p>
<p>With your knowledge of emerging trends, build some relevant learning time into your work. Communicate this to your managers and stakeholders to manage their expectations. Learning adds to the scope of the project, but it is justified if the new technology gives your employer a strategic advantage.</p>
<p>Learning on the job is hard to balance. On one hand, we could pad every project with time to learn a new programming language or framework. On the other, we could put off learning and soldier on without new skills. The first approach leaves a trail of programming languages and frameworks used once and discarded. The second sticks us with out-of-date skills and frameworks that others have long since abandoned. How you find your balance depends on the culture and priorities of your company. Weigh any technology choice you make today against their impact on your entire team and your company’s software.</p>
<p>With some knowledge of your company’s needs you can plan to learn on your own time. This takes some of the burden of your professional development off your employer. Andy Hunt advises software engineers, “Model your knowledge portfolio with the same care you would manage a financial investment portfolio.”<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn13" id="fnref13">[13]</a></sup> So take steps each day to learn skills that will add value for your employer. Any learning you can do on your own time takes pressure off you and your team.</p>
<p><strong>Adjust Unrealistic Expectations</strong> Many of us are somewhat introverted. We prefer the neat structure of ideas to the messy web of interactions that make up human relationships. But we cannot avoid communication. If we insist on clarity, there will be many times we give potentially unwelcome news to our superiors. This is not a bad thing. Clear communication is part of every software engineer’s job.</p>
<p>Business stakeholders often give deadlines to their superiors to justify your next project without any knowledge of the details. As you plan your work, communicate about potential missed deadlines as soon as you become aware of them. Explain the likely delay so your stakeholders can justify the change with the company leadership. Otherwise, your concerns will backfire—making you seem hesitant and fearful rather than assertive and responsible.</p>
<p><strong>Forgive yourself.</strong> As professionals, we hold a high opinion of our abilities and expect a great deal of ourselves. We add to our stress when, if we fall short of our own internal standard, we berate ourselves. In most cases, no one else cares about your personal missed expectations. <em>Set goals. Work hard. Forgive yourself.</em></p>
<p><strong>Cultivate a Sense of Humor</strong> It’s easy to forgive yourself if you learn not to take yourself too seriously. For most of my life, I have been intense, driven, and self-critical. It’s hard to forgive myself if the weight of the world rests on my shoulders. But here’s something to remember: none of us bears our burdens alone. Team members, customers, friends, and loved ones who see our flaws continue to work with us, buy from us, spend time with us, and love us. Sometimes, we can join them in laughing at our mistakes. This helps us let go and move forward.</p>
<p>Letting go can make our work fun and our products fun to use. “Good design is often slightly funny,” says venture capitalist Paul Graham, “I think it’s because humor is related to strength. To have a sense of humor is to be strong: to keep one’s sense of humor is to shrug off misfortunes, and to lose one’s sense of humor is to be wounded by them. And so the mark—or at least the prerogative—of strength is not to take oneself too seriously.”<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fn14" id="fnref14">[14]</a></sup></p>
<h2>Save the World</h2>
<p>Stress management may not save the world, but it may save us from early aging and health problems. We can take a load off of our coworkers, customers, friends, and loved ones. And, managing or eliminating stress <em>can</em> save our lives.</p>
<p>Stress is a killer. One of my friends has experienced this in a profound way. During his career, he had several heart attacks due to stress. He says, “I now know stress almost killed me. Not sure how you can control yours, but you need to.” Take his words to heart. You might save the world—or at least <em>your world.</em></p>
<h2>Footnotes</h2>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="https://www.health.harvard.edu/mind-and-mood/protect-your-brain-from-stress">Protect Your Brain from Stress</a>. Harvard University, February 15, 2021. <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p><a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5137920/">The effects of chronic stress on health: new insights into the molecular mechanisms of brain–body communication</a>. Future Science OA, November 2015. <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p><a href="https://www.pbs.org/wnet/nature/the-good-the-bad-and-the-grizzly-what-to-do-if-you-encounter-a-bear/117/">What to Do if You Encounter a Bear</a>. PBS, September 8, 2009. <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref3" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn4" class="footnote-item"><p><a href="https://en.wikipedia.org/wiki/Chronic_stress">Chronic stress</a>. Wikipedia, July 26, 2021. <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref4" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn5" class="footnote-item"><p>Watkins, Michael D. <em>The First 90 Days</em>. Harvard Business Review Press, 2013, pp. 226-7. <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref5" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn6" class="footnote-item"><p>Norman, Don. <em>Emotional Design: Why We Love (or Hate) Everyday Things</em>. Basic Books, 2004, p. 19. <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref6" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn7" class="footnote-item"><p>“Who Killed the Guy on the Ski Lift?” <em>The Good Cop</em>, created by Andy Breckman, performance by Isaiah Whitlock Jr., season 1, episode 7. Andy Breckman Productions and Netflix, 2018. <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref7" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn8" class="footnote-item"><p><a href="https://www.infosecurity-magazine.com/news/data-thieves-hit-wolfeassociates/">Data Thieves Hit California Property Management Company</a>. InfoSecurity Magazine, April 6, 2020. <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref8" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn9" class="footnote-item"><p>Ferguson, Nicole Phd., Humble, Jez and Gene Kim. <em>Accelerate: Building High Performing Technology Organizations</em>. IT Revolution, 2018, p. 89 <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref9" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn10" class="footnote-item"><p>Sinek, Simon. <em>Start with Why: How Great Leaders Inspire Everyone to Take Action</em>. Portfolio/Penguin, 2009, p. 33. <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref10" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn11" class="footnote-item"><p>Lapin, Daniel. <em>Thou Shall Prosper</em>. John Wiley & Sons, Inc., 2010, pp. 218-9. <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref11" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn12" class="footnote-item"><p>Neumeier, Marty. <em>The Designful Company: How to Build a Culture of Nonstop Innovation</em>. New Riders, 2009, p. 48. <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref12" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn13" class="footnote-item"><p>Hunt, Andy. <em>Pragmatic Thinking & Learning: Refactor Your Wetware</em>. The Pragmatic Programmers, LLC., 2008, p. 133. <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref13" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn14" class="footnote-item"><p>Graham, Paul. <em>Hackers & Painters: Big Ideas from the Computer Age</em>. O’Reilly Media, Inc., 2004, pp. 135-6. <a href="https://www.harveyramer.com/article/coding-stress-bugs-catastophes/#fnref14" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
Making an Even-More-Useful COVID-19 Tracker with Node.js
2020-04-10T20:45:37Zhttps://www.harveyramer.com/article/covid-tracker-nodejs-2/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706043722/making-an-even-more-useful-covid-19-tracker-with-node-js.png" alt="making-an-even-more-useful-covid-19-tracker-with-node-js" /></p>
<p>Imagine an artist transferring the clutter of her studio directly to the canvas. When we query an API or database, we often transfer that clutter to the user interface. There is a better way.</p>
<p>In our previous tutorial, we <a href="https://www.harveyramer.com/article/2020-04-09-start-here-to-make-a-useful-covid-19-tracker-with-node-js/">created a COVID-19 Tracker</a>. The user interface was much like that cluttered artist studio. Rather than helping the user focus, we bombarded them with information. What can we do to make this information easier to digest?</p>
<p><img src="https://www.harveyramer.com/img/chrome_8yyl9m8idf.png" alt="Our cluttered user interface" title="Our cluttered user interface" /></p>
<h2>Prerequisites</h2>
<p>Before completing this tutorial, complete the <a href="https://www.harveyramer.com/article/2020-04-09-start-here-to-make-a-useful-covid-19-tracker-with-node-js/">first tutorial</a> or clone the <a href="https://github.com/harveyramer/covid-19-demo-express-js-app/tree/tutorial-1">Github repository for the tutorial</a>. You will start to see comments in the code examples. Comments allow developers to leave context for those who follow, but have no impact on the execution of code.</p>
<pre><code class="language-javascript">/*
Here is a block comment.
It spans multiple lines.
*/
// This is a single line comment.
</code></pre>
<h2>Providing Context and Focus</h2>
<p>There are some simple things we can do to get started.</p>
<ol>
<li>Provide summary information by displaying the global statistics</li>
<li>Allow our users to filter countries by name to reduce the feeling of information overload</li>
</ol>
<h2>Adding a Global Summary</h2>
<h3>New Data for Our Template</h3>
<p>The data our API call returns has both a <code>Countries</code> <em>array</em> and a <code>Global</code> <em>object</em>. You can learn more <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Basics">about JavaScript objects</a>. We need to pass all the data to our Home Page. Open the <strong>routes.js</strong> file and change the render call for the Home Page Route.</p>
<pre><code class="language-javascript">res.render("home", {
appName: "My COVID-19 Tracker",
pageName: "COVID-19 Cases",
data: response.data, // previously: response.data.Countries
});
</code></pre>
<p>Our Home Page view expects to be given an <em>array</em> of countries, and not an <em>object</em> containing Global data and an <em>array</em> of Countries. Replacing lines 5-6 of our <strong>home.pug</strong> file will keep it from breaking.</p>
<pre><code class="language-pug"> h2 By Country
.cards
// Our Countries array is now at data.Countries.
each val, index in data.Countries
</code></pre>
<p>This adds a new heading <strong>By Country</strong> and looks for the countries list inside the <strong>data</strong> object.</p>
<h3>Displaying the Global Summary</h3>
<p>To display the new Global Summary data, add a new section above the list of countries in the <strong>home.pug</strong> template.</p>
<pre><code class="language-pug"> .centered
h2 Global
.centered
.cards.large
.card
.row
.cases
.row
.new
h4 New Cases
.count #{data.Global.NewConfirmed}
.total
h4 Total Cases
.count #{data.Global.TotalConfirmed}
.deaths
.row
.new
h4 New Deaths
.count #{data.Global.NewDeaths}
.total
h4 Total Deaths
.count #{data.Global.TotalDeaths}
.recovered
.row
.new
h4 New Recovered
.count #{data.Global.NewRecovered}
.total
h4 Total Recovered
.count #{data.Global.TotalRecovered}
</code></pre>
<h3>Update Styles</h3>
<p>The country data in our previous tutorial was displayed using a FlexBox Grid. However, CSS also has a specification for grid layout that is more effective for our purposes. You can learn more about <a href="https://css-tricks.com/dont-overthink-flexbox-grids/">FlexBox Grid</a> and <a href="https://css-tricks.com/snippets/css/complete-guide-grid/">CSS Grid</a> to round out your skills.</p>
<p>Replace the entire contents of your <strong>style.css</strong> file with the code below and save your changes.</p>
<pre><code class="language-css">html,
body {
margin: 0;
padding: 0;
}
html {
font-size: 14px;
font-family: Arial, Helvetica, sans-serif;
}
.container {
width: 90%;
margin: 0 auto;
padding: 2rem 0;
}
section {
padding: 1rem;
}
.cards {
display: grid;
grid-template-columns: repeat(1, 1fr);
grid-auto-rows: auto;
grid-gap: 1rem;
}
.card {
flex: 1 0 500px;
box-sizing: border-box;
margin: 0.5rem 0.5rem;
padding: 1rem;
background-color: #e5e5e5;
border-radius: 0.5rem;
}
.row {
overflow: hidden;
}
.row > * {
width: 33.33%;
float: left;
}
.card h2 {
margin-top: 0;
}
.card h4 {
text-align: center;
margin: 0;
padding: 0.5rem 0.5rem;
}
.card .count {
font-weight: bold;
text-align: center;
padding: 0.25rem 0 1rem;
font-size: 1.25rem;
}
.card .new,
.card .total {
width: 48%;
margin-right: 2%;
padding: 0;
border-radius: 0.5rem;
border: 1px solid black;
box-sizing: border-box;
}
.card .new {
background-color: #fff;
}
.card .total {
color: #fff;
background-color: gray;
}
.card .deaths .total {
color: #fff;
background-color: black;
}
.card .recovered .total {
color: #fff;
background-color: green;
}
@media screen and (min-width: 60rem) {
.cards {
grid-template-columns: repeat(2, 1fr);
}
.cards.large {
grid-template-columns: repeat(1, 1fr);
}
}
@media screen and (min-width: 100rem) {
.cards {
grid-template-columns: repeat(3, 1fr);
}
.cards.large {
grid-template-columns: repeat(1, 1fr);
}
}
@media screen and (min-width: 140rem) {
.cards {
grid-template-columns: repeat(4, 1fr);
}
.cards.large {
grid-template-columns: repeat(2, 1fr);
}
}
.error {
font-size: 1.7em;
color: red;
}
/* Forms */
input {
font-size: 1.5rem;
padding: 0.8rem 1rem;
width: 18rem;
}
</code></pre>
<h3>Check Your Work</h3>
<p>Verify this change by starting your server (<code>npm start</code> in your Terminal) and navigating to <a href="http://localhost:3000/">http://localhost:3000</a>. If it is already running, restart it (<code>Ctrl+C</code> followed by <code>npm start</code>). The global data and list of countries from our previous tutorial should display.</p>
<p><img src="https://www.harveyramer.com/img/chrome_msr65echxo.png" alt="Global and country data" title="Global and country data" /></p>
<h3>Save Your Work</h3>
<p>In your Terminal save your changes with Git.</p>
<pre><code class="language-shell-script">git add .
git commit -m "Adding global summary data."
</code></pre>
<p><img src="https://www.harveyramer.com/img/code_b9hpp6nmfy.png" alt="Committing changes with Gid" title="Committing changes with Gid" /></p>
<h2>Filtering The List</h2>
<h3>Client Side JavaScript</h3>
<p>So far, we have been writing JavaScript to load data from an external API and render HTML in a browser. No JavaScript has executed in the context of the browser. It has been executed by Node.js and Express to produce our results. This is server side JavaScript.</p>
<p>When we filter our list of countries based on user input, we want to avoid the time it takes to query a remote data source. We already have our list. Let’s just choose what we display based on user input. All of this will happen inside the Web browser window. This is client side JavaScript.</p>
<p>Open the <strong>home.pug</strong> file and look for the line <code>h2 By Country</code> to make some changes. Change the lines below.</p>
<pre><code class="language-pug"> .centered
h2 By Country
.cards
// Our Countries array is now at data.Countries.
each val, index in data.Countries
.card
</code></pre>
<p>Your new Pug code will be a bit more complex.</p>
<pre><code class="language-pug"> .centered#countryList
h2 By Country
h3 Type to Filter
form(onSubmit="handleSubmit(event)")
input#needle(placeholder="Country name", onkeyup="handleKeyup(event)")
// This JavaScript will run in the Web browser.
script(type="text/javascript").
filter = (needle) => {
const cards = document.querySelectorAll('#countryList .card');
cards.forEach(el => {
const name = el.getAttribute('data-name').toLowerCase();
const isMatched = name && name.indexOf(needle) !== -1;
el.style.display = isMatched ? 'block' : 'none';
});
}
handleSubmit = (e) => {
e.preventDefault(); // Prevent the form from reloading the page. We're handling this with JavaScript.
};
handleKeyup = (e) => {
// Filter whenever content is entered.
const needle = e.target.value.toLowerCase(); // Get the filter value.
filter(needle);
};
.cards
// Our Countries array is now at data.Countries.
each val, index in data.Countries
.card(data-name=val.Country.toLowerCase())
</code></pre>
<p><strong>Note:</strong> A word of warning. If you haven’t discovered it yet, Pug uses semantic white space. Languages such as <a href="https://www.python.org/">Python</a> and <a href="https://coffeescript.org/">CoffeeScript</a> also follow this pattern. In these languages indention is of extreme importance. When a line is indented more than a previous line, it implies a parent/child relationship.</p>
<p>Some developers love using indention to describe relationships between objects. <a href="https://wiki.c2.com/?SyntacticallySignificantWhitespaceConsideredHarmful">Others feel it is harmful</a>. Below is an example to illustrate the parent/child concept.</p>
<pre><code class="language-pug">p Hello
span World
p Hello
span World
</code></pre>
<p>The Pug template is compiled to HTML.</p>
<pre><code class="language-html"><p>Hello <span>World</span></p>
<p>Hello</p>
<span>World</span>
</code></pre>
<p>The client side JavaScript illustrates some key concepts you will want to learn.</p>
<ol>
<li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events">Events and Event Handlers</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction">DOM Selectors</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach">Iterators</a></li>
</ol>
<p>Each of these concepts merits deep study. The most effective deep study is <em>play</em>. Look over the concepts and try them out. What do they do? How do they break? Learning requires the discovery of misconceptions. Mistakes are a must-have for effective growth.</p>
<h3>Check Your Changes</h3>
<p>Verify the client side filter you added by starting your server (<code>npm start</code> in your Terminal) and navigating to <a href="http://localhost:3000/">http://localhost:3000</a>. If it is already running, restart it (<code>Ctrl+C</code> followed by <code>npm start</code>). We should be able to enter text and see our list of countries filter.</p>
<p><img src="https://www.harveyramer.com/img/chrome_5bioa1ikxi.png" alt="Filtering countries" title="Filtering countries" /></p>
<h3>Save Your Changes</h3>
<p>In your Terminal save your changes with Git.</p>
<pre><code class="language-shell-script">git add .
git commit -m "Added country list filter."
</code></pre>
<h2>What We Have Learned</h2>
<p>Congratulations! You have built a Web application with both server side and client side JavaScript and learned some valuable skills!</p>
<ul>
<li>the importance of providing context and removing clutter</li>
<li>how data is passed between a router and view and accessed via properties</li>
<li>an overview of the options for rendering a grid view in CSS</li>
<li>the difference between server side and client side JavaScript</li>
<li>how different languages think about white space</li>
<li>an overview of JavaScript events, DOM selectors and iterators</li>
</ul>
<p>Hopefully your COVID-19 tracker is working well. A <a href="https://github.com/harveyramer/covid-19-demo-express-js-app/tree/tutorial-2">complete archive of code for this Web app</a> is available on Github.</p>
Start Here to Make a Useful COVID-19 Tracker with Node.js
2020-04-09T16:57:36Zhttps://www.harveyramer.com/article/covid-tracker-nodejs/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706043722/start-here-to-make-a-useful-covid-19-tracker-with-node-js.png" alt="start-here-to-make-a-useful-covid-19-tracker-with-node-js" /></p>
<p>If you’ve been wanting to learn Node.js, why not let pandemic worries spur you to action? Let’s build a Web application to display the latest COVID-19 statistics. Never fear, we’ll make it simple and fun.</p>
<p>Before beginning this tutorial, you will need <a href="https://nodejs.org/">Node.js</a>, <a href="https://www.npmjs.com/">NPM</a>, <a href="https://git-scm.com/">Git</a>, and<a href="https://code.visualstudio.com/">Visual Studio Code</a> installed on your computer. If you need help, use my tutorial on <a href="https://www.harveyramer.com/article/2020-04-08-configure-a-nodejs-development-environment-on-windows-10/">configuring a development environment</a>.</p>
<h2>Getting Started</h2>
<p>Open your Terminal (Windows users type <code>cmd</code> in your Start Menu to find it). Make a directory for your new app, and open it in Visual Studio Code.</p>
<pre><code class="language-shell-script">mkdir covid19-tracker
cd covid19-tracker
code .
</code></pre>
<p>In Visual Studio Code, open the terminal (<code>Ctrl+` </code>) to initialize your new project.</p>
<p><img src="https://www.harveyramer.com/img/code_qck1owdhjr.png" alt="Open the Terminal in Visual Studio Code" title="Open the Terminal in Visual Studio Code" /></p>
<pre><code class="language-javascript">npm init -y
git init
</code></pre>
<p><img src="https://www.harveyramer.com/img/code_vr7kovcecm.png" alt="Initializing a new Node.js project" title="Initializing a new Node.js project" /></p>
<h2>Install Express.js, Axios, and Pug</h2>
<p>Now that we’ve initialized the project, we’ll install some dependencies with the Visual Studio Code terminal.</p>
<ul>
<li><a href="https://expressjs.com/">Express</a>is a simple-to-use JavaScript framework used for API and Web application development. We will use it to handle our HTTP requests and direct URL routes to our Node.js functions.</li>
<li><a href="https://github.com/axios/axios">Axios</a> is a powerful tool for making requests to other servers. We will use Axios to retrieve our COVID-19 data from a public API.</li>
<li><a href="https://pugjs.org/api/getting-started.html">Pug</a> compiles data to HTML. It will be useful.</li>
</ul>
<pre><code class="language-javascript">npm install express axios pug --save
</code></pre>
<p><img src="https://www.harveyramer.com/img/code_cpv5ebkavw.png" alt="Installing express and axios" title="Installing express and axios" /></p>
<h2>Hello World</h2>
<p>Create an empty <strong>index.js</strong> file in the terminal.</p>
<pre><code class="language-shell-script">mkdir src
cd src
echo "" > index.js
</code></pre>
<p>This command will display some errors as it creates your file, but it will succeed. This is a handy shortcut for creating files in code. It may come in handy later. You will see your new <code>src</code> directory and file in the File Explorer.</p>
<p>Open your empty <strong>index.js</strong> file and let’s start writing some code!</p>
<h3>Our First Code</h3>
<p>Copy and paste (Ctrl+C Ctrl+V) the following code, and save your <strong>index.js</strong> file.</p>
<pre><code class="language-javascript">const express = require("express");
const app = express();
const port = 3000;
app.get("/", (req, res) => res.send("Hello World!"));
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`));
</code></pre>
<p>Next, open the <strong>package.json</strong> file and add <code>"start": "node src/index",</code> to the <code>scripts</code> block. The result should look like this:</p>
<pre><code class="language-json">{
"name": "covid19-tracker",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node src/index",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.19.2",
"express": "^4.17.1"
}
}
</code></pre>
<p>Remember to save both your <strong>index.js</strong> and <strong>package.json</strong> files.</p>
<h3>Test the Hello World App</h3>
<p>In the Visual Studio Terminal, start the Express server via the NPM script we created.</p>
<pre><code class="language-javascript">npm start
</code></pre>
<p><img src="https://www.harveyramer.com/img/chrome_lgnp0rdpe8.png" alt="Running server" title="Running server" /></p>
<p>Open <a href="http://localhost:3000/">http://localhost:3000</a> in your browser.</p>
<p><img src="https://www.harveyramer.com/img/chrome_bqk5uaxq7h.png" alt="Hello World in browser" title="Hello World in browser" /></p>
<p>Ok. Now that you’ve tested your app, let’s shut down your server. In the terminal, <code>Ctrl+C</code> and your server will stop running.</p>
<h3>Handle Two Different Routes</h3>
<p>In your <code>src</code> directory, create a file named <strong>routes.js</strong>. In your terminal, if you are already in the <code>src</code> directory, do this.</p>
<pre><code class="language-shell-script">echo "" > routes.js
</code></pre>
<p>Next, open your <strong>routes.js</strong> file, and paste this code:</p>
<pre><code class="language-javascript">var express = require("express");
var router = express.Router();
// Home page route.
router.get("/", function (req, res) {
res.send('Hello World. Learn <a href="/about">about this app</a>');
});
// About page route.
router.get("/about", function (req, res) {
res.send('About this COVID-19 Tracker. Go <a href="/">home</a>');
});
module.exports = router;
</code></pre>
<p>As you can see, this defines two routes. One at <code>/</code> and the other at <code>/about</code>. Open <strong>index.js</strong> and make the following changes.</p>
<pre><code class="language-javascript">const express = require("express");
const routes = require("./routes");
const app = express();
const port = 3000;
app.use("/", routes);
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`));
</code></pre>
<p>Above, we are importing our new <strong>routes.js</strong> file as a module. We have also configured the application to use our <strong>routes.js</strong> module with an <code>app.use</code> function call. To test these changes we will start our server again.</p>
<pre><code class="language-javascript">npm start
</code></pre>
<p>Open <a href="http://localhost:3000/">http://localhost:3000</a> in your browser and click the <strong>about this app</strong> link to load the <strong>About</strong> page. These simple pages demonstrate a fully-functioning Web server responding to HTTP requests. This the foundation on which the Web is built!</p>
<p><img src="https://www.harveyramer.com/img/chrome_r6cetpk0lp.png" alt="Our grown-up Hello World app with multiple routes" title="Our grown-up Hello World app with multiple routes" /></p>
<h2>Housekeeping: Versioning Our Code</h2>
<p>Before we move on to write some exciting code, let’s commit our files to Git so we can make changes without losing any of our past work. In Visual Studio Code Terminal make sure you are in the root of your project. The path in your terminal should look something like <code>C:\Users\hramer\covid19-tracker</code> and not like <code>C:\Users\hramer\covid19-tracker\src</code>. If it looks like the latter, <code>cd..</code> will fix your problem.</p>
<p>Let’s commit our code changes.</p>
<pre><code class="language-shell-script">git add .
git commit -m "A hello world Web app"
</code></pre>
<p><img src="https://www.harveyramer.com/img/code_e8crgvguuy.png" alt="Adding files to Git" title="Adding files to Git" /></p>
<h2>COVID-19 Tracker</h2>
<p>We have created the framework we need to build our COVID-19 Tracker. Let’s build the real thing! First, we should make this look more like a real Web app. In Visual Studio Code Terminal, let’s use a library called Pug to help us manage our HTML. We used NPM to install Pug when we started this tutorial.</p>
<p>You can learn more about <a href="https://pugjs.org/api/getting-started.html">getting started with Pug</a>. Let’s add our Pug views: one for each page, and a layout helper to manage the code shared by both views.</p>
<pre><code class="language-shell-script">cd src
mdkir views
cd views
echo "" > home.pug
echo "" > about.pug
echo "" > layout.pug
cd..
mkdir public
cd public
echo "" > style.css
cd..
</code></pre>
<p>You should see your new Pug files in the <code>src/views</code> directory, and an empty <strong>style.css</strong> file in the <code>src/public</code> directory. Copy the code below into your <strong>style.css</strong> file and save it.</p>
<pre><code class="language-html,">body {
margin: 0;
padding: 0;
}
html {
font-size: 14px;
font-family: Arial, Helvetica, sans-serif;
}
.container {
width: 90%;
margin: 0 auto;
padding: 2rem 0;
}
section {
padding: 1rem;
}
.cards {
display: flex;
flex-wrap: wrap;
}
.card {
flex: 1 0 500px;
box-sizing: border-box;
margin: 1rem 0.25em;
padding: 0.5rem 1rem 1rem;
background-color: #e5e5e5;
border-radius: 0.5rem;
}
.row {
overflow: hidden;
}
.row > * {
width: 33.33%;
float: left;
}
.card h4 {
margin: 0;
}
.card .count {
font-weight: bold;
text-align: center;
padding: 1rem 0;
font-size: 1.25rem;
}
.card .new,
.card .total {
width: 48%;
margin-right: 2%;
padding: 1rem;
border-radius: 0.5rem;
border: 1px solid black;
box-sizing: border-box;
}
.card .new {
background-color: #fff;
}
.card .total {
color: #fff;
background-color: #000;
}
.card .recovered .total {
color: #fff;
background-color: green;
}
@media screen and (min-width: 70em) {
.card {
max-width: calc(50% - 1em);
}
}
@media screen and (min-width: 110em) {
.card {
max-width: calc(25% - 1em);
}
}
</code></pre>
<p>Copy the code below into your <strong>layout.pug</strong> file and save it.</p>
<pre><code class="language-pug">html
head
title #{appName}
style
include ../public/style.css
body
.container
h1 #{pageName}
block content
p This page doesn't have any content yet.
</code></pre>
<p>Copy the code below into your <strong>about.pug</strong> file and save it.</p>
<pre><code class="language-pug">extends layout
block content
p This COVID-19 Tracker uses the publicly available REST API provided by
a(href='https://www.covid19api.com') covid19api.com
p Visit the
a(href='/') home page
</code></pre>
<p>Copy the code below into you <strong>home.pug</strong> file and save it.</p>
<pre><code class="language-pug">extends layout
block content
.centered
.cards
.card
h2 Afghanistan
.row
.cases
h3 Confirmed Cases
.row
.new
h4 New
.count 6
.total
h4 Total
.count 24
.deaths
h3 Deaths
.row
.new
h4 New
.count 1
.total
h4 Total
.count 3
.recovered
h3 Recovered
.row
.new
h4 New
.count 1
.total
h4 Total
.count 3
.card
h3 United States
.row
.cases
h3 Confirmed Cases
.row
.new
h4 New
.count 6
.total
h4 Total
.count 24
.deaths
h3 Deaths
.row
.new
h4 New
.count 1
.total
h4 Total
.count 3
.recovered
h3 Recovered
.row
.new
h4 New
.count 1
.total
h4 Total
.count 3
.card
h3 Germany
.row
.cases
h3 Confirmed
.row
.new
h4 New
.count 6
.total
h4 Total
.count 24
.deaths
h3 Deaths
.row
.new
h4 New
.count 1
.total
h4 Total
.count 3
.recovered
h3 Recovered
.row
.new
h4 New
.count 1
.total
h4 Total
.count 3
p Visit the
a(href='/about') about page
</code></pre>
<p>There is quite a bit going on in these files, feel free to investigate to your heart’s content. We are going on to bigger things. To validate your work, stop your server if it’s running (Ctrl+C in the Visual Studio Code Terminal) and restart it (<code>npm start</code>). When you browse to <a href="http://localhost:3000/">localhost:3000</a>, you should see something like the view below.</p>
<p><img src="https://www.harveyramer.com/img/chrome_sxmi7gwakd.png" alt="Static data mocking up the user interface" title="Static data mocking up the user interface" /></p>
<p>This COVID-19 data is static. We added it inside the <strong>home.pug</strong> file. Next we will get real data from an API. It is time to preserve all of this hard work. Navigate to the root directory of your project (see above, Housekeeping: Versioning Our Code).</p>
<pre><code class="language-shell-script">git add .
git commit -m "Static files mocking up our COVID-19 data"
</code></pre>
<h2>Getting Ready for Real Data</h2>
<p>Open the <strong>routes.js</strong> file and replace the Home Page Route with this code.</p>
<pre><code class="language-javascript">// Home page route.
router.get("/", (req, res) => {
const countries = [
{
Country: "ALA Aland Islands",
CountryCode: "AX",
Slug: "ala-aland-islands",
NewConfirmed: 0,
TotalConfirmed: 0,
NewDeaths: 0,
TotalDeaths: 0,
NewRecovered: 0,
TotalRecovered: 0,
Date: "2020-04-09T23:21:34Z",
},
{
Country: "Afghanistan",
CountryCode: "AF",
Slug: "afghanistan",
NewConfirmed: 21,
TotalConfirmed: 444,
NewDeaths: 0,
TotalDeaths: 14,
NewRecovered: 11,
TotalRecovered: 29,
Date: "2020-04-09T23:21:34Z",
},
{
Country: "Albania",
CountryCode: "AL",
Slug: "albania",
NewConfirmed: 17,
TotalConfirmed: 400,
NewDeaths: 0,
TotalDeaths: 22,
NewRecovered: 23,
TotalRecovered: 154,
Date: "2020-04-09T23:21:34Z",
},
{
Country: "Algeria",
CountryCode: "DZ",
Slug: "algeria",
NewConfirmed: 104,
TotalConfirmed: 1572,
NewDeaths: 12,
TotalDeaths: 205,
NewRecovered: 124,
TotalRecovered: 237,
Date: "2020-04-09T23:21:34Z",
},
];
res.render("home", {
appName: "My COVID-19 Tracker",
pageName: "COVID-19 Cases",
data: countries,
});
});
</code></pre>
<p>In the <strong>routes.js</strong> file we are creating an <em>array</em> of country objects. You can learn more <a href="https://www.javascripttutorial.net/javascript-array/">about JavaScript arrays</a>. Each object has the properties, <em>Country</em>, <em>CountryCode</em>, <em>Slug</em>, <em>NewConfirmed</em>, <em>TotalConfirmed</em>, <em>NewDeaths</em>, <em>TotalDeaths</em>, <em>NewRecovered</em>, <em>TotalRecovered</em>, and <em>Date</em>. We will use most of these properties in our view.</p>
<p>Now we need to update the <strong>home.pug</strong> file to take this list of data instead of our hard-coded one. Replace the contents of that file with the code below.</p>
<pre><code class="language-pug">extends layout
block content
.centered
.cards
each val, index in data
.card
h2 #{val.Country}
i As of #{val.Date.split('T')[0]}
.row
.cases
h3 Confirmed
.row
.new
h4 New
.count #{val.NewConfirmed}
.total
h4 Total
.count #{val.TotalConfirmed}
.deaths
h3 Deaths
.row
.new
h4 New
.count #{val.NewDeaths}
.total
h4 Total
.count #{val.TotalDeaths}
.recovered
h3 Recovered
.row
.new
h4 New
.count #{val.NewRecovered}
.total
h4 Total
.count #{val.TotalRecovered}
p Visit the
a(href='/about') about page
</code></pre>
<p>The view created in <strong>home.pug</strong> now uses <strong><em>iteration</em></strong> to loop over each of the records in the country list we passed to it in <strong>routes.js</strong>.</p>
<h2>Loading Data from the COVID-19 API</h2>
<p>We are almost done with our COVID-19 Dashboard.</p>
<p>Open the <strong>routes.js</strong> file, and replace the entire Home Page Route (including that big <em>countries</em> array) with the following code.</p>
<pre><code class="language-javascript">// Home page route.
router.get("/", (req, res) => {
const apiUrl = "https://api.covid19api.com/summary";
const countries = axios
.get(apiUrl)
.then((response) => {
res.render("home", {
appName: "My COVID-19 Tracker",
pageName: "COVID-19 Cases",
data: response.data.Countries,
});
})
.catch(function (err) {
return console.error(err);
});
});
</code></pre>
<p>This code makes an asynchronous call to the COVID-19 API and returns the data for our view. When you restart your server and browse to <a href="http://localhost:3000/">localhost:3000</a>, you should see something like this.</p>
<p><img src="https://www.harveyramer.com/img/chrome_8yyl9m8idf.png" alt="A list of COVID-19 cases by country" title="A list of COVID-19 cases by country" /></p>
<h2>What We Have Learned</h2>
<p>In this tutorial, you learned a bit about</p>
<ul>
<li>installing Node.js packages via NPM</li>
<li>using Git to version code</li>
<li>using Express.js as a Web server</li>
<li>styling HTML with CSS</li>
<li>compiling HTML with dynamic data via Pug</li>
<li>requesting data from an API with Axios</li>
</ul>
<p>You may have found interesting jumping-off-places to learn more, and I hope you did. You should have your first Web application running. To improve the utility of this demonstration application, make a list of things, and give it a try. Keep coding. It’s always a challenge, but it gets easier. <a href="https://github.com/harveyramer/covid-19-demo-express-js-app">A complete archive of code for this Web app</a> is available on Github. When you’re ready, move on to the next tutorial to <a href="https://www.harveyramer.com/article/2020-04-10-making-an-even-more-useful-covid-19-tracker-with-node-js/">add interactivity to your COVID-19 tracker</a>.</p>
Configure a Node.js Development Environment on Windows 10
2020-04-08T22:36:23Zhttps://www.harveyramer.com/article/nodejs-windows10/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706043722/configure-a-nodejs-development-environment-on-windows-10.png" alt="configure-a-nodejs-development-environment-on-windows-10" /></p>
<h2>Overview</h2>
<p>If you want to learn to write code, setting up a development environment can be a barrier to entry. This tutorial offers a simple way to install the tools you need to start working with Node.js on Windows 10.</p>
<p class="alert">When a simple command should produce an output of a certain type, you will see:<br />
<code>command</code> → <code>output</code>.</p>
<h2>Install Chocolatey: the Windows Package Manager</h2>
<p class="alert danger">I no longer recommend Chocolatey due to security and maintenance concerns. Please consider alternatives. One I have used with success is <a href="https://github.com/coreybutler/nvm-windows">NVM-Windows</a>. If you choose that option, you can skip to <a href="https://www.harveyramer.com/article/nodejs-windows10/#install-node">Install Node</a>.</p>
<p><a href="https://chocolatey.org/">Chocolatey</a> allows us to download and install open source packages from the Web. Chocolatey is as secure as the practices of the user. Mitigate risk by downloading known safe packages for your development machine. We will use <a href="https://docs.microsoft.com/en-us/powershell/scripting/overview?view=powershell-7">Windows PowerShell</a> to install Chocolatey. Enter <code>PowerShell</code> in your Windows Start Menu and choose “Run as Administrator” from the menu.</p>
<p><img src="https://www.harveyramer.com/img/sc5ox6zxr9.png" alt="Run PowerShell as administrator." /></p>
<p>In your PowerShell terminal, enter the command:</p>
<pre><code class="language-powershell">Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
</code></pre>
<p>Expect output like this:</p>
<p><img src="https://www.harveyramer.com/img/powershell_Wb8r3lS2bU.png" alt="PowerShell output." /></p>
<h2>Install Node Version Manager (NVM)</h2>
<p>Now we can use our Chocolatey Package Manager to download and install <a href="https://github.com/nvm-sh/nvm/blob/master/README.md">NVM</a>! It is common to work on projects that require different versions of Node.js. If we installed Node.js directly, switching between such projects would present a conundrum. But NVM will make that an easy problem to solve.</p>
<p>This time, use Windows Terminal. Type `cmd` in the Windows Start Menu and choose “Run as Administrator”. To install NVM, enter the following command and verify your results.</p>
<pre><code class="language-shell-script">choco install -y nvm
</code></pre>
<p><img src="https://www.harveyramer.com/img/cmd_4rbXM91m6u.png" alt="Installing NVM with Chocolatey." /></p>
<p>Close that terminal window and open a new one (again, as Administrator). This allows the terminal to look up environment information and see our newly installed package manager.</p>
<p>Try the command <code>nvm version</code> → <code>1.1.7</code>. If you get a numeric version result, we’re good! Let’s install Node.js next.</p>
<h2 id="install-node">Install Node.js</h2>
<p>Now we can use NVM to download and install <a href="https://nodejs.org/en/about/">Node.js</a>! Open the Windows Terminal again (you should not need Administrator privileges). Enter the following command and verify your results.</p>
<pre><code class="language-javascript">nvm install node@13.12.0
</code></pre>
<p><img src="https://www.harveyramer.com/img/cmd_pN3qtBIZHC.png" alt="Install Node with NVM." /></p>
<p>Before celebrating too much, let’s set our default Node.js version with the command, <code>nvm use 13.12.0</code>. Then, validate your install. If you are able to see the version for node and npm, you are ready to write code on Node.js!</p>
<p><code>node -v</code> → <code>v13.12.0</code></p>
<p><code>npm -v</code> → <code>6.14.4</code></p>
<h2>Hello World</h2>
<p>In your Windows Terminal, enter <code>node</code>. This will launch the Node REPL terminal, then test a <code>console.log</code> statement.</p>
<pre><code class="language-javascript">console.log("Hello World!");
</code></pre>
<p>Your “Hello World” statement will be printed to the terminal. Then, exit the REPL, by entering <code>.exit</code>.</p>
<p><img src="https://www.harveyramer.com/img/cmd_SHOGeflu9a.png" alt="Hello World!" title="Hello World!" /></p>
<h2>Add More Versions of Node.js (optional)</h2>
<p>As I mentioned earlier, it is common to contribute to multiple Node.js projects requiring different versions of Node.js. For example, you could choose to write your own project in Node.js version <strong>13.12.0</strong>, but need to help another developer working on a project using Node.js <strong>12.16.2</strong>. This will help you with that problem. To add another version of Node, open Windows Terminal.</p>
<pre><code class="language-javascript">nvm install node@12.16.2
nvm use 12.16.2
</code></pre>
<p>Validate your newest install.</p>
<p><code>node -v</code> → <code>v12.16.2</code></p>
<p><code>npm -v</code> → <code>6.14.4</code></p>
<p>To switch back to version 13, after this, we would once again use the command: <code>nvm use 13.12.0</code>. At any time, you can see your locally installed versions of Node.js with <code>nvm ls</code>.</p>
<p><img src="https://www.harveyramer.com/img/cmd_RycmFqBtls.png" alt="See local Node.js versions" title="See local Node.js versions" /></p>
<h2>Install Git</h2>
<p>In most cases, you will write code that requires version control. For that purpose, nothing works better than Git. Let’s do that before we wrap up. It will be easy. I promise.</p>
<p><a href="https://git-scm.com/download/win">Download the latest installer</a> from the Git website (download should start automatically). When the download completes, install using the defaults. No fuss. We can configure Git later. You’ll finish in a flash.</p>
<p><img src="https://www.harveyramer.com/img/Git-2.26.0-64-bit.tmp_gcNQ427NNs.png" alt="Happy install dialog" /></p>
<p>When the installation completes. Open a new Windows Terminal and enter the command <code>git --version</code> → <code>git version 2.26.0.windows.1</code>. If you see a version as described, Git is configured correctly.</p>
<h2>Install Visual Studio Code</h2>
<p>Visual Studio Code is my preferred development environment for Node.js. There are many excellent guides on <a href="https://code.visualstudio.com/docs/introvideos/basics">getting started</a>. In short, download the latest binary of <a href="https://code.visualstudio.com/">Visual Studio Code</a> for windows.</p>
<p><img src="https://www.harveyramer.com/img/chrome_9n74ygwamo.png" alt="Downloading Visual Studio Code" title="Downloading Visual Studio Code" /></p>
<p>When the download completes, install using the defaults. No fuss. You only have one final thing to do. Visit the <a href="https://marketplace.visualstudio.com/VSCode">Visual Studio Code Marketplace</a>, and install intellisense and the extension pack for Node.js.</p>
<ul>
<li><a href="https://marketplace.visualstudio.com/items?itemName=leizongmin.node-module-intellisense">Node.js Modules Intellisense</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=waderyan.nodejs-extension-pack">Node.js Extension Pack</a></li>
</ul>
<p><img src="https://www.harveyramer.com/img/chrome_rtjxzfmak7.png" alt="Install Node.js Modules Intellisense" title="Install Node.js Modules Intellisense" /></p>
<p><img src="https://www.harveyramer.com/img/chrome_1klnojkfy0.png" alt="Install Node.js Extension Pack" title="Install Node.js Extension Pack" /></p>
<p>When those are both installed, restart Visual Studio Code and poke around on to get a sense of the tools available to you.</p>
<h2>You’re Finished!</h2>
<p>You have configured NVM to manage two versions of Node.js. You installed Git to make sure you never lose any of your code changes. To top it off, you added and configured your own code editor. Congratulations!</p>
<p>Ready for a new challenge? <a href="https://www.harveyramer.com/article/2020-04-09-start-here-to-make-a-useful-covid-19-tracker-with-node-js/">Start Here to Make a Useful COVID-19 Tracker with Node.js</a>.</p>
How To Quickly Deploy an Angular Application with AWS CDK
2020-01-16T03:27:29Zhttps://www.harveyramer.com/article/angular-aws-cdk/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706042281/how-to-quickly-deploy-an-angular-application-with-aws-cdk.png" alt="how-to-quickly-deploy-an-angular-application-with-aws-cdk" /></p>
<p>At re:Invent 2019, I saw The AWS Cloud Development Kit (CDK) and learned how it removes the pain of deploying resources to the AWS cloud. I was curious. So I decided to experiment with the CDK using TypeScript. My goal was simple: to deploy a static site on AWS. But I wanted to make it a bit more interesting by including an Angular application. I bootstrapped a vanilla Angular install any developer could use and deploy.</p>
<h2>Why Not Use Native CloudFormation?</h2>
<p><img src="https://www.harveyramer.com/img/cloudformation-sticker-sm.png" alt="CloudFormation Sticker" /></p>
<p>CloudFormation is a powerful way to manage infrastructure as code. But it is not designed for human writers. Large teams use powerful enterprise tools to manage AWS infrastructure. But smaller teams sometimes do not have the expertise or resources to use those tools. For such teams, Amazon CDK brings a familiar feel to infrastructure as code.</p>
<p>In short, there is nothing wrong with CloudFormation. But maintaining CloudFormation templates is unwieldy for small development teams. CDK for the win!</p>
<h2>A CDK Overview</h2>
<p>At the heart of CDK is a library of Constructs<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/angular-aws-cdk/#fn1" id="fnref1">[1]</a></sup>. These structural building blocks represent cloud components. Constructs contain all the information needed to generate a valid CloudFormation template. Developers compose constructs to define higher level components, much like application code.</p>
<h2>Trying It Out for Yourself</h2>
<p>If you want test CDK for your own Angular projects,<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/angular-aws-cdk/#fn2" id="fnref2">[2]</a></sup> I have simplified the process with a <a href="https://github.com/harveyramer/deploy-angular-with-cdk">Github repo.</a></p>
<ol>
<li>Clone the repo</li>
<li>Follow the instructions in the Readme file</li>
<li>Enjoy your static site hosted on S3 with CloudFront and Route53 DNS.</li>
</ol>
<p>Using this project, you will have an Angular application hosted on S3 in an hour or two. The initial deployment takes about 30 minutes to provision AWS infrastructure.</p>
<h2>Footnotes</h2>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="https://docs.aws.amazon.com/cdk/latest/guide/constructs.html">AWS CDK Library of Constructs</a> <a href="https://www.harveyramer.com/article/angular-aws-cdk/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p><a href="https://twitter.com/intent/user?screen_name=emeshbi">Elad Ben-Israel</a> from AWS offers a CDK Intro Workshop in <a href="https://cdkworkshop.com/20-typescript.html">TypeScript</a>, <a href="https://cdkworkshop.com/30-python.html">Python</a>, <a href="https://cdkworkshop.com/40-dotnet.html">.NET</a>, and <a href="https://cdkworkshop.com/50-java.html">Java</a>. Use his workshop to learn more about how to use CDK to manage your AWS infrastructure as code. <a href="https://www.harveyramer.com/article/angular-aws-cdk/#fnref2" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
3 High-Quality Lessons from a Failed Startup
2020-01-06T21:26:17Zhttps://www.harveyramer.com/article/3-lessons-failed-startup/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706043722/3-high-quality-lessons-from-a-failed-startup.png" alt="3-high-quality-lessons-from-a-failed-startup" /></p>
<p class="lede">May of 2018 was an exciting month. I joined a small team focused on removing the pain from a complex business process involving multiple stakeholders. Despite the startup’s failure, I learned three important lessons.</p>
<h2>Your First Customer Is Everything</h2>
<p>Our initial conversations with customers were promising. Everyone agreed the problem we were addressing was painful indeed. Energized by this discovery, we built a tool that would enable our customers to remove most of the pain we had identified.</p>
<p>We had exciting potential customer conversations and even ran a pilot project. Then we launched. The phone did not ring. The website did not generate the leads we expected. <em>Sales did not materialize.</em></p>
<p class="callout">A customer is someone who gives you money.</p>
<p>Everyone in the company knew we needed to make sales, but we had difficulty recruiting our first paying customer. Instead of collecting money, we had encouraging conversations with warm leads and ran too long on the slightest hint of interest they showed. The Lean Startup<sup class="footnote-ref"><a href="https://www.harveyramer.com/article/3-lessons-failed-startup/#fn1" id="fnref1">[1]</a></sup> method <em>might</em> have helped us get customers fully on board, but this lesson is harder to learn than it might seem.</p>
<ol>
<li>Everything starts with vision and ends with a customer</li>
<li>How long a project needs to be vision-led depends in part on its complexity</li>
<li>Selling to a customer means putting our best foot forward</li>
<li>It is difficult to determine when you’re ready to sell, because software is never finished</li>
</ol>
<h2>Vision Is Vital</h2>
<p>It is easy to pin the blame of missing the market on visionary leadership, but the reality is that most startups fail. The cost of shaky or unclear vision is high. Our startup had a remedy for a real pain point. Our tactics aligned with our vision. Our team was a success because of clear vision.</p>
<ol>
<li>We incrementally improved our product to match the vision</li>
<li>We optimized for adaptability to respond to what we learned as our vision clarified</li>
<li>We worked as a unit in alignment to our purpose</li>
</ol>
<p class="callout">Vision is indispensable, but it needs give way to the voice of the customer.</p>
<p>Without vision, paralysis-by-analysis rules the day. Fear of failure haunts every decision. I would rather follow a visionary leader than a timid, fearful one.</p>
<p><strong>Visionary leaders need competent voices to interrupt their vision with reality.</strong> This is not the fault of those with vision. Followers need to know when to run with a vision, and when to ask questions and challenge assumptions. This is a difficult balance—wisdom is required.</p>
<h2>The Team Is (Also) Everything</h2>
<p>Let’s get to the heart it all. A business is a team of people working toward producing revenue through value creation. Teams bond with clear vision, and our sense of purpose brought us together. Teams collaborate to reach goals. Teams connect us with life-long relationships and knowledge that enriches us.</p>
<p>We found and hired people who shared the vision and gave every ounce of their talent to realize it. That was a success!</p>
<p class="callout">There is nothing better than knowing your team has your back.</p>
<p>I am humbled to have been part of a company whose leadership believed in and supported their team. Each team member played an important part, and they are some of the finest human beings I have ever known. <strong>After it all ends, all we have is friendship.</strong></p>
<h2>Footnotes</h2>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>“Startup success can be engineered by following the process, which means it can be learned, which means it can be taught.” — <a href="http://theleanstartup.com/principles">The Lean Startup Methodology</a>. <a href="https://www.harveyramer.com/article/3-lessons-failed-startup/#fnref1" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
About This Website
2020-01-06T20:01:19Zhttps://www.harveyramer.com/article/2020-01-06-welcome/
<p><img src="https://res.cloudinary.com/harveyramer/image/upload/v1706042280/welcome.png" alt="welcome" /></p>
<h2>I Am a Florida-Based Web Developer</h2>
<p>Though it seems like only a few years ago, it has been about 20 years since I graduated from school with a degree in visual communications. As the cliche goes, life is what happens when you’re making other plans. I didn’t work as a designer for long. My customers wanted websites, not brochures. More was required.</p>
<p>Responding to what my customers wanted, I began designing websites. I focused on aesthetics and portfolio-building code, but soon I learned what mattered to my customers. They wanted new customers and relationship-forming opportunities. A website needed to extend their business—to produce revenue.</p>
<p>Websites needed interactive features like contact forms and e-commerce, so yet again, I needed new skills. I learned to use PHP and JavaScript build more engaging websites on top of open source tools, especially WordPress.</p>
<h2>What to Expect</h2>
<p>As time allows, I will add content to this website. I plan to write on Christian worldview issues related to theology and philosophy, technology, business, and even relationships. I tend to be clumsy in relating to others, so I hope to improve those skills with some reading and writing. There will be a smattering of articles related to business and marketing as well.</p>