Illustration of IKEA stepping into a chest of drawers that is not secured to the wall, so it is falling on him.
Strategy

Stop Using ‘Drop-down’ | Adrian Roselli



TL;DR: Stop using the word drop-down. Instead choose a term that accurately describes the control you want.




Illustration of IKEA stepping into a chest of drawers that is not secured to the wall, so it is falling on him.


I have worked both with native platform developers and web developers. While control names might differ, if a control was functionally the same then it was not an issue. A TextBox, for example, translates pretty easily to <input type="text"> in HTML. Or at least in 1995 it did.



I’ve also worked with ad agencies as they spun up their web teams. Translating their HyperCard or Director skills meant their lingo also worked its way into web projects. But we could still posit that a hypertext region in a design comp was probably a link in HTML.



The word drop-down (dropdown, drahp-daughn, daft-dolt) was common with both sets of clients. However, if you used the term with one group, you might get a specific control that does not translate to the web. With another group you might get a design that makes a specific control impossible to build.



With broken processes that didn’t get everyone in the room at the same time and without a common understanding of drop-down, we ossified into our current situation.





As you embark on a design or build or specification, it is important to understand what you are producing and why. When you say drop-down, which one of these things do you mean? What about your client? Your designer? Your developer? The user (who calls the help line)? The screen reader? The voice control software?




1. <select>



Tip If your intent is to use a native HTML <select>, then call it a select.



It most accurately describes the technical implementation which also describes the customization challenges. Though the design challenges may not be as challenging as some think.



If describing the control to a screen reader user, it may be helpful to know that VoiceOver on macOS & iOS and TalkBack on Android will refer to a <select> as pop-up button. JAWS and NVDA refer to it as combobox.




2. ARIA Listbox



ARIA defines roles for composite user interface widgets, which are generally containers for the necessary parts of a complete widget. The listbox role corresponds to the native <select> element. The listbox‘s required children have the option role, corresponding to the native <option>.



Tip If you are referring to this construct, call it an ARIA listbox.



The term sets expectations for the implementation and implies a design not constrained by browser defaults the way <select> is. There is more than one way to implement a control that uses the listbox role, with the critical difference being the trigger. See the articles linked at the end.




3. <datalist>



Despite screen readers on Windows referring to a <select> as combobox, the word combobox has a very specific meaning especially to old-school Windows forms developers. In web technology terms, it is analogous to a <select> with a text field.



Until recently, HTML had no equivalent to a native combobox, but the <datalist>/<option> roughly addresses that. Screen readers seem to enjoy announcing it differently depending on, well, reasons — listbox pop-up on iOS, text field on macOS, edit box on Android, type in text in JAWS with IE11, combo in JAWS with Chrome, text pop-up in JAWS with Firefox, and has auto-complete with NVDA.



Tip To refer to this pattern, call it a datalist.



This will also signal to developers and designers that you are leaning on browser defaults, and therefore manage expectations for visual representation.




4. ARIA Combobox



If you are looking for a combobox, it would be a good idea to identify whether you want it developed with ARIA or with native HTML (see <datalist>). How much custom design is required will probably influence your choice.



In unsupporting browsers, the ARIA combobox role can fill that gap when paired with the required textbox role and (generally) the listbox role.



Tip To refer to this pattern, call it an ARIA combobox.



The term sets expectations for the implementation and implies a design not constrained by browser defaults the way <datalist> is. You may still need to do further testing to identify if you want the ARIA 1.0 combobox, ARIA 1.1 combobox (linked above), or draft ARIA 1.2 combobox.




5. Autocomplete



If the control is meant to provide users with suggestions that may not be available in the DOM already, then you will need to clarify further.



If the request is for a control with the autocomplete attribute (perhaps to satisfy WCAG SC 1.3.5: Identify Input Purpose), then that is not a distinct control. That is a feature that the browser can support on existing <input>, <select>, or <textarea> fields.



Otherwise, presuming the previous options are not a fit and the requirements call for an XMLHttpRequest to populate options as you type, then you have a different kind of control. Alternatively, if the control supports matching values the user does not type (such as typing a word in one language and seeing a result in a different language, as in this autocomplete example), then you also have a different kind of control.



Tip For this scenario, knowing you may still need to gather requirements, call it an autocomplete.






If you are trying to recreate a native menu, as you would get when you right-click with your mouse, then the ARIA menu role is your choice. If you want a native menu similar to what youfind in a Windows or Mac application then the menubar role is your pick.



Tip You can get away with referring to either option as an ARIA menu.



When discussing this option, it must be clear that an ARIA menu is for replicating native OS features, not for web site navigation or other general web content purposes. If you need help making your case, I have written in detail at Don’t Use ARIA Menu Roles for Site Nav.




7. <details>/<summary>



While <details> and <summary> support in browsers is relatively recent (and absent in IE and legacy Edge), this a handy native element for hiding and showing content. For unsupporting browsers you will still need JavaScript for a polyfill.



Effectively <details>/<summary> are a native disclosure widget. That’s about it. <details>/<summary> are not a lot of other things (I thought them not being a modal was obvious, but people gotta experiment).



Tip You can refer to these generally as details / summary, or details & summary.



A competent web person will know you are talking about an interactive widget, not a form control.




8. Disclosure Widget



Think of this as the ARIA version of <details> and <summary>, but in this case you are not using ARIA roles to enhance generic controls. You need a <button> with aria-expanded (and aria-controls despite falling support) and an associated content container whose visibility is toggled.



The disclosure widget at the ARIA Authoring Practices document is one of the few mature patterns in that note, and you can use it as the basis for your code. The pattern is robust and can even be used for navigation.



Tip Use the term disclosure widget to refer to this pattern.




9. Accordion



Similar to the disclosure widget pattern, there is no accordion role defined in ARIA. Unlike the disclosure widget, there is no corresponding native HTML element. The ARIA tab pattern, even the vertical one, is not a fit because tab panels do not collapse to reclaim space. That being said, ensure your need does not map to the ARIA tab pattern.



The accordion widget at the ARIA Authoring Practices document is one of the other mature patterns in that note, which you can use as the basis for your code. You need a <button> with aria-expanded (and aria-controls despite falling support) within a header and an associated content container whose visibility is toggled while also toggling the visibility of the other content containers.



Tip When discussing this pattern, call it an accordion.




10. Fly-out Navigation



Web site navigation has been referred to as drop-downs for years. For evidence of how common it is, and its age, the Suckerfish drop-downs were released in 2003 and leaned on an already common term.



If you are looking for navigation where tabbing or mousing through the top-level options reveals nested options, then we need a more meaningful term. The WAI provides tutorials for assorted patterns, and the Fly-out Menus fits. It is not a new term, existing since before Suckerfish.



Tip If you have navigation that generally fits this pattern, refer to it is fly-out or fly-out navigation.





11. Custom Display Selector



This is sort of a catch-all. I have seen developers come up with all methods of making controls that essentially work by hiding some stuff, then showing that stuff by animating or popping some container into existence. These are generally inaccessible and this might be a great opportunity to make sure you choose something that conforms to one of the patterns above.



If you find yourself venturing into this territory, probably stop. Go back and figure out what the requirements truly are, as opposed to relying on assumptions or a weird desire to invent a new pattern that nobody will understand.



Tip When discussing this approach, call it consulting.








I suspect someone might mention <menu> and <menuitem>, but those elements are deprecated for lack of implementation. I refer you to ARIA menus above if you think you have a use case.



I have heard the term pop-up in place of drop-down. Pop-up is an even more confusing term since it can also mean a tool-tip, a native dialog, a modal dialog, or even a new window (remember pop-unders?). This is not helped when screen readers refer to some <select>-like controls as pop-ups.



If someone asks for a pop-up, you first have to disambiguate (hey, a Wikipedia word!) between a dialog-like thing, a form control, or display widget thing. Then you need to be diligent in what terms you use.



The term menu also gets tossed around when referring to a <select>, combobox, or navigation, all of which contributes to the confusion. There are arguably fewer potential meanings for menu then for drop-down, but you can apply the same logic to try to pare down what anyone means who uses it.



For a deeper dive into the <select>, listbox, or combobox patterns, particularly if you plan to implement any of them, I strongly recommend the following articles by Sarah Higley:


TL;DR



Stop using the word drop-down. Instead choose a term that accurately describes the control you want.







Source link

Build a Node.js Tool to Record and Compare Google Lighthouse...
Strategy

Build a Node.js Tool to Record and Compare Google Lighthouse…


In this tutorial, I’ll show you step by step how to create a simple tool in Node.js to run Google Lighthouse audits via the command line, save the reports they generate in JSON format and then compare them so web performance can be monitored as the website grows and develops.

I’m hopeful this can serve as a good introduction for any developer interested in learning about how to work with Google Lighthouse programmatically.

But first, for the uninitiated…

What is Google Lighthouse?

Google Lighthouse is one of the best-automated tools available on a web developer’s utility belt. It allows you to quickly audit a website in a number of key areas which together can form a measure of its overall quality. These are:

  • Performance
  • Accessibility
  • Best Practices
  • SEO
  • Progressive Web App

Once the audit is complete, a report is then generated on what your website does well… and not so well, with the latter intending to serve as an indicator for what your next steps should be to improve the page.

Here’s what a full report looks like. 

Along with other general diagnostics and web performance metrics, a really useful feature of the report is that each of the key areas is aggregated into color-coded scores between 0-100.

Not only does this allow developers to quickly gauge the quality of a website without further analysis, but it also allows non-technical folk such as stakeholders or clients to understand as well.

For example, this means, it’s much easier to share the win with Heather from marketing after spending time improving website accessibility as she’s more able to appreciate the effort after seeing the Lighthouse accessibility score go up 50 points into the green.

But equally, Simon the project manager may not understand what Speed Index or First Contentful Paint means, but when he sees the Lighthouse report showing website performance score knee deep in the red, he knows you still have work to do.

If you’re in Chrome or the latest version of Edge, you can run a Lighthouse audit for yourself right now using DevTools. Here’s how:

You can also run a Lighthouse audit online via PageSpeed Insights or through popular performance tools, such as WebPageTest.

However, today, we’re only interested in Lighthouse as a Node module, as this allows us to use the tool programmatically to audit, record and compare web performance metrics.

Let’s find out how.

Setup

First off, if you don’t already have it, you’re going to need Node.js. There are a million different ways to install it. I use the Homebrew package manager, but you can also download an installer straight from the Node.js website if you prefer. This tutorial was written with Node.js v10.17.0 in mind, but will very likely work just fine on the most versions released in the last few years.

You’re also going to need Chrome installed, as that’s how we’ll be running the Lighthouse audits.

Next, create a new directory for the project and then cd into it in the console. Then run npm init to begin to create a package.json file. At this point, I’d recommend just bashing the Enter key over and over to skip as much of this as possible until the file is created.

Now, let’s create a new file in the project directory. I called mine lh.js, but feel free to call it whatever you want. This will contain all of JavaScript for the tool. Open it in your text editor of choice, and for now, write a console.log statement.

console.log('Hello world');

Then in the console, make sure your CWD (current working directory) is your project directory and run node lh.js, substituting my file name for whatever you’ve used.

You should see:

$ node lh.js
Hello world

If not, then check your Node installation is working and you’re definitely in the correct project directory.

Now that’s out of the way, we can move on to developing the tool itself.

Opening Chrome with Node.js

Let’s install our project’s first dependency: Lighthouse itself.

npm install lighthouse --save-dev

This creates a node_modules directory that contains all of the package’s files. If you’re using Git, the only thing you’ll want to do with this is add it to your .gitignore file.

In lh.js, you’ll next want to delete the test console.log() and import the Lighthouse module so you can use it in your code. Like so:

const lighthouse = require('lighthouse');

Below it, you’ll also need to import a module called chrome-launcher, which is one of Lighthouse’s dependencies and allows Node to launch Chrome by itself so the audit can be run.

const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');

Now that we have access to these two modules, let’s create a simple script which just opens Chrome, runs a Lighthouse audit, and then prints the report to the console.

Create a new function that accepts a URL as a parameter. Because we’ll be running this using Node.js, we’re able to safely use ES6 syntax as we don’t have to worry about those pesky Internet Explorer users.

const launchChrome = (url) => {

}

Within the function, the first thing we need to do is open Chrome using the chrome-launcher module we imported and send it to whatever argument is passed through the url parameter. 

We can do this using its launch() method and its startingUrl option.

const launchChrome = url => {
  chromeLauncher.launch({
    startingUrl: url
  });
};

Calling the function below and passing a URL of your choice results in Chrome being opened at the URL when the Node script is run.

launchChrome('https://www.lukeharrison.dev');

The launch function actually returns a promise, which allows us to access an object containing a few useful methods and properties.

For example, using the code below, we can open Chrome, print the object to the console, and then close Chrome three seconds later using its kill() method.

const launchChrome = url => {
  chromeLauncher
    .launch({
      startingUrl: url
    })
    .then(chrome => {
      console.log(chrome);
      setTimeout(() => chrome.kill(), 3000);
    });
};

launchChrome("https://www.lukeharrison.dev");

Now that we’ve got Chrome figured out, let’s move on to Lighthouse.

Running Lighthouse programmatically

First off, let’s rename our launchChrome() function to something more reflective of its final functionality: launchChromeAndRunLighthouse(). With the hard part out of the way, we can now use the Lighthouse module we imported earlier in the tutorial.

In the Chrome launcher’s then function, which only executes once the browser is open, we’ll pass Lighthouse the function’s url argument and trigger an audit of this website.

const launchChromeAndRunLighthouse = url => {
  chromeLauncher
    .launch({
      startingUrl: url
    })
    .then(chrome => {
      const opts = {
        port: chrome.port
      };
      lighthouse(url, opts);
    });
};

launchChromeAndRunLighthouse("https://www.lukeharrison.dev");

To link the lighthouse instance to our Chrome browser window, we have to pass its port along with the URL.

If you were to run this script now, you will hit an error in the console:

(node:47714) UnhandledPromiseRejectionWarning: Error: You probably have multiple tabs open to the same origin.

To fix this, we just need to remove the startingUrl option from Chrome Launcher and let Lighthouse handle URL navigation from here on out.

const launchChromeAndRunLighthouse = url => {
  chromeLauncher.launch().then(chrome => {
    const opts = {
      port: chrome.port
    };
    lighthouse(url, opts);
  });
};

If you were to execute this code, you’ll notice that something definitely seems to be happening. We just aren’t getting any feedback in the console to confirm the Lighthouse audit has definitely run, nor is the Chrome instance closing by itself like before.

Thankfully, the lighthouse() function returns a promise which lets us access the audit results.

Let’s kill Chrome and then print those results to the terminal in JSON format via the report property of the results object.

const launchChromeAndRunLighthouse = url => {
  chromeLauncher.launch().then(chrome => {
    const opts = {
      port: chrome.port
    };
    lighthouse(url, opts).then(results => {
      chrome.kill();
      console.log(results.report);
    });
  });
};

While the console isn’t the best way to display these results, if you were to copy them to your clipboard and visit the Lighthouse Report Viewer, pasting here will show the report in all of its glory.

At this point, it’s important to tidy up the code a little to make the launchChromeAndRunLighthouse() function return the report once it’s finished executing. This allows us to process the report later without resulting in a messy pyramid of JavaScript.

const lighthouse = require("lighthouse");
const chromeLauncher = require("chrome-launcher");

const launchChromeAndRunLighthouse = url => {
  return chromeLauncher.launch().then(chrome => {
    const opts = {
      port: chrome.port
    };
    return lighthouse(url, opts).then(results => {
      return chrome.kill().then(() => results.report);
    });
  });
};

launchChromeAndRunLighthouse("https://www.lukeharrison.dev").then(results => {
  console.log(results);
});

One thing you may have noticed is that our tool is only able to audit a single website at the moment. Let’s change this so you can pass the URL as an argument via the command line.

To take the pain out of working with command-line arguments, we’ll handle them with a package called yargs.

npm install --save-dev yargs

Then import it at the top of your script along with Chrome Launcher and Lighthouse. We only need its argv function here.

const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');
const argv = require('yargs').argv;

This means if you were to pass a command line argument in the terminal like so:

node lh.js --url https://www.google.co.uk

…you can access the argument in the script like so:

const url = argv.url // https://www.google.co.uk

Let’s edit our script to pass the command line URL argument to the function’s url parameter. It’s important to add a little safety net via the if statement and error message in case no argument is passed.

if (argv.url) {
  launchChromeAndRunLighthouse(argv.url).then(results => {
    console.log(results);
  });
} else {
  throw "You haven't passed a URL to Lighthouse";
}

Tada! We have a tool that launches Chrome and runs a Lighthouse audit programmatically before printing the report to the terminal in JSON format.

Saving Lighthouse reports

Having the report printed to the console isn’t very useful as you can’t easily read its contents, nor are they aren’t saved for future use. In this section of the tutorial, we’ll change this behavior so each report is saved into its own JSON file.

To stop reports from different websites getting mixed up, we’ll organize them like so:

  • lukeharrison.dev
    • 2020-01-31T18:18:12.648Z.json
    • 2020-01-31T19:10:24.110Z.json
  • cnn.com
    • 2020-01-14T22:15:10.396Z.json
  • lh.js

We’ll name the reports with a timestamp indicating when the date/time the report was generated. This will mean no two report file names will ever be the same, and it’ll help us easily distinguish between reports.

There is one issue with Windows that requires our attention: the colon (:) is an illegal character for file names. To mitigate this issue, we’ll replace any colons with underscores (_), so a typical report filename will look like:

  • 2020-01-31T18_18_12.648Z.json

Creating the directory

First, we need to manipulate the command line URL argument so we can use it for the directory name.

This involves more than just removing the www, as it needs to account for audits run on web pages which don’t sit at the root (eg: www.foo.com/bar), as the slashes are invalid characters for directory names. 

For these URLs, we’ll replace the invalid characters with underscores again. That way, if you run an audit on https://www.foo.com/bar, the resulting directory name containing the report would be foo.com_bar.

To make dealing with URLs easier, we’ll use a native Node.js module called url. This can be imported like any other package and without having to add it to thepackage.json and pull it via npm.

const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');
const argv = require('yargs').argv;
const url = require('url');

Next, let’s use it to instantiate a new URL object.

if (argv.url) {
  const urlObj = new URL(argv.url);

  launchChromeAndRunLighthouse(argv.url).then(results => {
    console.log(results);
  });
}

If you were to print urlObj to the console, you would see lots of useful URL data we can use.

$ node lh.js --url https://www.foo.com/bar
URL {
  href: 'https://www.foo.com/bar',
  origin: 'https://www.foo.com',
  protocol: 'https:',
  username: '',
  password: '',
  host: 'www.foo.com',
  hostname: 'www.foo.com',
  port: '',
  pathname: '/bar',
  search: '',
  searchParams: URLSearchParams {},
  hash: ''
}

Create a new variable called dirName, and use the string replace() method on the host property of our URL to get rid of the www in addition to the https protocol:

const urlObj = new URL(argv.url);
let dirName = urlObj.host.replace('www.','');

We’ve used let here, which unlike const can be reassigned, as we’ll need to update the reference if the URL has a pathname, to replace slashes with underscores. This can be done with a regular expression pattern, and looks like this:

const urlObj = new URL(argv.url);
let dirName = urlObj.host.replace("www.", "");
if (urlObj.pathname !== "https://css-tricks.com/") {
  dirName = dirName + urlObj.pathname.replace(///g, "_");
}

Now we can create the directory itself. This can be done through the use of another native Node.js module called fs (short for “file system”).

const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');
const argv = require('yargs').argv;
const url = require('url');
const fs = require('fs');

We can use its mkdir() method to create a directory, but first have to use its existsSync() method to check if the directory already exists, as Node.js would otherwise throw an error:

const urlObj = new URL(argv.url);
let dirName = urlObj.host.replace("www.", "");
if (urlObj.pathname !== "https://css-tricks.com/") {
  dirName = dirName + urlObj.pathname.replace(///g, "_");
}
if (!fs.existsSync(dirName)) {
  fs.mkdirSync(dirName);
}

Testing the script at the point should result in a new directory being created. Passing https://www.bbc.co.uk/news as the URL argument would result in a directory named bbc.co.uk_news.

Saving the report

In the then function for launchChromeAndRunLighthouse(), we want to replace the existing console.log with logic to write the report to disk. This can be done using the fs module’s writeFile() method.

launchChromeAndRunLighthouse(argv.url).then(results => {
  fs.writeFile("report.json", results, err => {
    if (err) throw err;
  });
});

The first parameter represents the file name, the second is the content of the file and the third is a callback containing an error object should something go wrong during the write process. This would create a new file called report.json containing the returning Lighthouse report JSON object.

We still need to send it to the correct directory, with a timestamp as its file name. The former is simple — we pass the dirName variable we created earlier, like so:

launchChromeAndRunLighthouse(argv.url).then(results => {
  fs.writeFile(`${dirName}/report.json`, results, err => {
    if (err) throw err;
  });
});

The latter though requires us to somehow retrieve a timestamp of when the report was generated. Thankfully, the report itself captures this as a data point, and is stored as the fetchTime property. 

We just need to remember to swap any colons (:) for underscores (_) so it plays nice with the Windows file system.

launchChromeAndRunLighthouse(argv.url).then(results => {
  fs.writeFile(
    `${dirName}/${results["fetchTime"].replace(/:/g, "_")}.json`,
    results,
    err => {
      if (err) throw err;
    }
  );
});

If you were to run this now, rather than a timestamped.json filename, instead you would likely see an error similar to:

UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'replace' of undefined

This is happening because Lighthouse is currently returning the report in JSON format, rather than an object consumable by JavaScript.

Thankfully, instead of parsing the JSON ourselves, we can just ask Lighthouse to return the report as a regular JavaScript object instead.

This requires editing the below line from:

return chrome.kill().then(() => results.report);

…to:

return chrome.kill().then(() => results.lhr);

Now, if you rerun the script, the file will be named correctly. However, when opened, it’s only content will unfortunately be…

[object Object]

This is because we’ve now got the opposite problem as before. We’re trying to render a JavaScript object without stringifying it into a JSON object first.

The solution is simple. To avoid having to waste resources on parsing or stringifying this huge object, we can return both types from Lighthouse:

return lighthouse(url, opts).then(results => {
  return chrome.kill().then(() => {
    return {
      js: results.lhr,
      json: results.report
    };
  });
});

Then we can modify the writeFile instance to this:

fs.writeFile(
  `${dirName}/${results.js["fetchTime"].replace(/:/g, "_")}.json`,
  results.json,
  err => {
    if (err) throw err;
  }
);

Sorted! On completion of the Lighthouse audit, our tool should now save the report to a file with a unique timestamped filename in a directory named after the website URL.

This means reports are now much more efficiently organized and won’t override each other no matter how many reports are saved.

Comparing Lighthouse reports

During everyday development, when I’m focused on improving performance, the ability to very quickly compare reports directly in the console and see if I’m headed in the right direction could be extremely useful. With this in mind, the requirements of this compare functionality ought to be:

  1. If a previous report already exists for the same website when a Lighthouse audit is complete, automatically perform a comparison against it and show any changes to key performance metrics.
  2. I should also be able to compare key performance metrics from any two reports, from any two websites, without having to generate a new Lighthouse report which I may not need.

What parts of a report should be compared? These are the numerical key performance metrics collected as part of any Lighthouse report. They provide insight into the objective and perceived performance of a website.

In addition, Lighthouse also collects other metrics that aren’t listed in this part of the report but are still in an appropriate format to be included in the comparison. These are:

  • Time to first byte – Time To First Byte identifies the time at which your server sends a response.
  • Total blocking time – Sum of all time periods between FCP and Time to Interactive, when task length exceeded 50ms, expressed in milliseconds.
  • Estimated input latency – Estimated Input Latency is an estimate of how long your app takes to respond to user input, in milliseconds, during the busiest 5s window of page load. If your latency is higher than 50ms, users may perceive your app as laggy.

How should the metric comparison be output to the console? We’ll create a simple percentage-based comparison using the old and new metrics to see how they’ve changed from report to report.

To allow for quick scanning, we’ll also color-code individual metrics depending on if they’re faster, slower or unchanged.

We’ll aim for this output:

First Contentful Paint is 0.49% slower
First Meaningful Paint is 0.47% slower
Speed Index is 12.92% slower
Estimated Input Latency is the same
Total Blocking Time is 85.71% faster
Max Potential First Input Delay is 10.53% faster
Time to first byte is 19.89% slower
First CPU Idle is 0.47% slower
Time to Interactive is 0.02% slower

Compare the new report against the previous report

Let’s get started by creating a new function called compareReports() just below our launchChromeAndRunLighthouse() function, which will contain all the comparison logic. We’ll give it two parameters —from and to  — to accept the two reports used for the comparison.

For now, as a placeholder, we’ll just print out some data from each report to the console to validate that it’s receiving them correctly.

const compareReports = (from, to) => {
  console.log(from["finalUrl"] + " " + from["fetchTime"]);
  console.log(to["finalUrl"] + " " + to["fetchTime"]);
};

As this comparison would begin after the creation of a new report, the logic to execute this function should sit in the then function for launchChromeAndRunLighthouse().

If, for example, you have 30 reports sitting in a directory, we need to determine which one is the most recent and set it as the previous report which the new one will be compared against. Thankfully, we already decided to use a timestamp as the filename for a report, so this gives us something to work with.

First off, we need to collect any existing reports. To make this process easy, we’ll install a new dependency called glob, which allows for pattern matching when searching for files. This is critical because we can’t predict how many reports will exist or what they’ll be called.

Install it like any other dependency:

npm install glob --save-dev

Then import it at the top of the file the same way as usual:

const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');
const argv = require('yargs').argv;
const url = require('url');
const fs = require('fs');
const glob = require('glob');

We’ll use glob to collect all of the reports in the directory, which we already know the name of via the dirName variable. It’s important to set its sync option to true as we don’t want JavaScript execution to continue until we know how many other reports exist.

launchChromeAndRunLighthouse(argv.url).then(results => {
  const prevReports = glob(`${dirName}/*.json`, {
    sync: true
  });

  // et al

});

This process returns an array of paths. So if the report directory looked like this:

  • lukeharrison.dev
    • 2020-01-31T10_18_12.648Z.json
    • 2020-01-31T10_18_24.110Z.json

…then the resulting array would look like this:

[
 'lukeharrison.dev/2020-01-31T10_18_12.648Z.json',
 'lukeharrison.dev/2020-01-31T10_18_24.110Z.json'
]

Because we can only perform a comparison if a previous report exists, let’s use this array as a conditional for the comparison logic:

const prevReports = glob(`${dirName}/*.json`, {
  sync: true
});

if (prevReports.length) {
}

We have a list of report file paths and we need to compare their timestamped filenames to determine which one is the most recent.

This means we first need to collect a list of all the file names, trim any irrelevant data such as directory names, and taking care to replace the underscores (_) back with colons (:) to turn them back into valid dates again. The easiest way to do this is using path, another Node.js native module.

const path = require('path');

Passing the path as an argument to its parse method, like so:

path.parse('lukeharrison.dev/2020-01-31T10_18_24.110Z.json');

Returns this useful object:

{
  root: '',
  dir: 'lukeharrison.dev',
  base: '2020-01-31T10_18_24.110Z.json',
  ext: '.json',
  name: '2020-01-31T10_18_24.110Z'
}

Therefore, to get a list of all the timestamp file names, we can do this:

if (prevReports.length) {
  dates = [];
  for (report in prevReports) {
    dates.push(
      new Date(path.parse(prevReports[report]).name.replace(/_/g, ":"))
    );
  }
}

Which again if our directory looked like:

  • lukeharrison.dev
    • 2020-01-31T10_18_12.648Z.json
    • 2020-01-31T10_18_24.110Z.json

Would result in:

[
 '2020-01-31T10:18:12.648Z',
 '2020-01-31T10:18:24.110Z'
]

A useful thing about dates is that they’re inherently comparable by default:

const alpha = new Date('2020-01-31');
const bravo = new Date('2020-02-15');

console.log(alpha > bravo); // false
console.log(bravo > alpha); // true

So by using a reduce function, we can reduce our array of dates down until only the most recent remains:

dates = [];
for (report in prevReports) {
  dates.push(new Date(path.parse(prevReports[report]).name.replace(/_/g, ":")));
}
const max = dates.reduce(function(a, b) {
  return Math.max(a, b);
});

If you were to print the contents of max to the console, it would throw up a UNIX timestamp, so now, we just have to add another line to convert our most recent date back into the correct ISO format:

const max = dates.reduce(function(a, b) {
 return Math.max(a, b);
});
const recentReport = new Date(max).toISOString();

Assuming these are the list of reports:

  • 2020-01-31T23_24_41.786Z.json
  • 2020-01-31T23_25_36.827Z.json
  • 2020-01-31T23_37_56.856Z.json
  • 2020-01-31T23_39_20.459Z.json
  • 2020-01-31T23_56_50.959Z.json

The value of recentReport would be 2020-01-31T23:56:50.959Z.

Now that we know the most recent report, we next need to extract its contents. Create a new variable called recentReportContents beneath the recentReport variable and assign it an empty function.

As we know this function will always need to execute, rather than manually calling it, it makes sense to turn it into an IFFE (Immediately invoked function expression), which will run by itself when the JavaScript parser reaches it. This is signified by the extra parenthesis:

const recentReportContents = (() => {

})();

In this function, we can return the contents of the most recent report using the readFileSync() method of the native fs module. Because this will be in JSON format, it’s important to parse it into a regular JavaScript object.

const recentReportContents = (() => {
  const output = fs.readFileSync(
    dirName + "https://css-tricks.com/" + recentReport.replace(/:/g, "_") + ".json",
    "utf8",
    (err, results) => {
      return results;
    }
  );
  return JSON.parse(output);
})();

And then, it’s a matter of calling the compareReports() function and passing both the current report and the most recent report as arguments.

compareReports(recentReportContents, results.js);

At the moment this just print out a few details to the console so we can test the report data is coming through OK:

https://www.lukeharrison.dev/ 2020-02-01T00:25:06.918Z
https://www.lukeharrison.dev/ 2020-02-01T00:25:42.169Z

If you’re getting any errors at this point, try deleting any report.json files or reports without valid content from earlier in the tutorial.

Compare any two reports

The remaining key requirement was the ability to compare any two reports from any two websites. The easiest way to implement this would be to allow the user to pass the full report file paths as command line arguments which we’ll then send to the compareReports() function.

In the command line, this would look like:

node lh.js --from lukeharrison.dev/2020-02-01T00:25:06.918Z --to cnn.com/2019-12-16T15:12:07.169Z

Achieving this requires editing the conditional if statement which checks for the presence of a URL command line argument. We’ll add an additional check to see if the user has just passed a from and to path, otherwise check for the URL as before. This way we’ll prevent a new Lighthouse audit.

if (argv.from && argv.to) {

} else if (argv.url) {
 // et al
}

Let’s extract the contents of these JSON files, parse them into JavaScript objects, and then pass them along to the compareReports() function. 

We’ve already parsed JSON before when retrieving the most recent report. We can just extrapolate this functionality into its own helper function and use it in both locations.

Using the recentReportContents() function as a base, create a new function called getContents() which accepts a file path as an argument. Make sure this is just a regular function, rather than an IFFE, as we don’t want it executing as soon as the JavaScript parser finds it.

const getContents = pathStr => {
  const output = fs.readFileSync(pathStr, "utf8", (err, results) => {
    return results;
  });
  return JSON.parse(output);
};

const compareReports = (from, to) => {
  console.log(from["finalUrl"] + " " + from["fetchTime"]);
  console.log(to["finalUrl"] + " " + to["fetchTime"]);
};

Then update the recentReportContents() function to use this extrapolated helper function instead:

const recentReportContents = getContents(dirName + "https://css-tricks.com/" + recentReport.replace(/:/g, '_') + '.json');

Back in our new conditional, we need to pass the contents of the comparison reports to the compareReports() function.

if (argv.from && argv.to) {
  compareReports(
    getContents(argv.from + ".json"),
    getContents(argv.to + ".json")
  );
}

Like before, this should print out some basic information about the reports in the console to let us know it’s all working fine.

node lh.js --from lukeharrison.dev/2020-01-31T23_24_41.786Z --to lukeharrison.dev/2020-02-01T11_16_25.221Z

Would lead to:

https://www.lukeharrison.dev/ 2020-01-31T23_24_41.786Z
https://www.lukeharrison.dev/ 2020-02-01T11_16_25.221Z

Comparison logic

This part of development involves building comparison logic to compare the two reports received by the compareReports() function. 

Within the object which Lighthouse returns, there’s a property called audits that contains another object listing performance metrics, opportunities, and information. There’s a lot of information here, much of which we aren’t interested in for the purposes of this tool.

Here’s the entry for First Contentful Paint, one of the nine performance metrics we wish to compare:

"first-contentful-paint": {
  "id": "first-contentful-paint",
  "title": "First Contentful Paint",
  "description": "First Contentful Paint marks the time at which the first text or image is painted. [Learn more](https://web.dev/first-contentful-paint).",
  "score": 1,
  "scoreDisplayMode": "numeric",
  "numericValue": 1081.661,
  "displayValue": "1.1 s"
}

Create an array listing the keys of these nine performance metrics. We can use this to filter the audit object:

const compareReports = (from, to) => {
  const metricFilter = [
    "first-contentful-paint",
    "first-meaningful-paint",
    "speed-index",
    "estimated-input-latency",
    "total-blocking-time",
    "max-potential-fid",
    "time-to-first-byte",
    "first-cpu-idle",
    "interactive"
  ];
};

Then we’ll loop through one of the report’s audits object and then cross-reference its name against our filter list. (It doesn’t matter which audit object, as they both have the same content structure.)

If it’s in there, then brilliant, we want to use it.

const metricFilter = [
  "first-contentful-paint",
  "first-meaningful-paint",
  "speed-index",
  "estimated-input-latency",
  "total-blocking-time",
  "max-potential-fid",
  "time-to-first-byte",
  "first-cpu-idle",
  "interactive"
];

for (let auditObj in from["audits"]) {
  if (metricFilter.includes(auditObj)) {
    console.log(auditObj);
  }
}

This console.log() would print the below keys to the console:

first-contentful-paint
first-meaningful-paint
speed-index
estimated-input-latency
total-blocking-time
max-potential-fid
time-to-first-byte
first-cpu-idle
interactive

Which means we would use from['audits'][auditObj].numericValue and to['audits'][auditObj].numericValue respectively in this loop to access the metrics themselves.

If we were to print these to the console with the key, it would result in output like this:

first-contentful-paint 1081.661 890.774
first-meaningful-paint 1081.661 954.774
speed-index 15576.70313351777 1098.622294504341
estimated-input-latency 12.8 12.8
total-blocking-time 59 31.5
max-potential-fid 153 102
time-to-first-byte 16.859999999999985 16.096000000000004
first-cpu-idle 1704.8490000000002 1918.774
interactive 2266.2835 2374.3615

We have all the data we need now. We just need to calculate the percentage difference between these two values and then log it to the console using the color-coded format outlined earlier.

Do you know how to calculate the percentage change between two values? Me neither. Thankfully, everybody’s favorite monolith search engine came to the rescue.

The formula is:

((From - To) / From) x 100

So, let’s say we have a Speed Index of 5.7s for the first report (from), and then a value of 2.1s for the second (to). The calculation would be:

5.7 - 2.1 = 3.6
3.6 / 5.7 = 0.63157895
0.63157895 * 100 = 63.157895

Rounding to two decimal places would yield a decrease in the speed index of 63.16%.

Let’s put this into a helper function inside the compareReports() function, below the metricFilter array.

const calcPercentageDiff = (from, to) => {
  const per = ((to - from) / from) * 100;
  return Math.round(per * 100) / 100;
};

Back in our auditObj conditional, we can begin to put together the final report comparison output.

First off, use the helper function to generate the percentage difference for each metric.

for (let auditObj in from["audits"]) {
  if (metricFilter.includes(auditObj)) {
    const percentageDiff = calcPercentageDiff(
      from["audits"][auditObj].numericValue,
      to["audits"][auditObj].numericValue
    );
  }
}

Next, we need to output values in this format to the console:

First Contentful Paint is 0.49% slower
First Meaningful Paint is 0.47% slower
Speed Index is 12.92% slower
Estimated Input Latency is the same
Total Blocking Time is 85.71% faster
Max Potential First Input Delay is 10.53% faster
Time to first byte is 19.89% slower
First CPU Idle is 0.47% slower
Time to Interactive is 0.02% slower

This requires adding color to the console output. In Node.js, this can be done by passing a color code as an argument to the console.log() function like so:

console.log('x1b[36m', 'hello') // Would print 'hello' in cyan

You can get a full reference of color codes in this Stackoverflow question.  We need green and red, so that’s x1b[32m and x1b[31m respectively. For metrics where the value remains unchanged, we’ll just use white. This would be x1b[37m.

Depending on if the percentage increase is a positive or negative number, the following things need to happen:

  • Log color needs to change (Green for negative, red for positive, white for unchanged)
  • Log text contents change.
    • ‘[Name] is X% slower for positive numbers
    • ‘[Name] is X% faster’ for negative numbers
    • ‘[Name] is unchanged’ for numbers with no percentage difference.
  • If the number is negative, we want to remove the minus/negative symbol, as otherwise, you’d have a sentence like ‘Speed Index is -92.95% faster’ which doesn’t make sense.

There are many ways this could be done. Here, we’ll use the Math.sign() function, which returns 1 if its argument is positive, 0 if well… 0, and -1 if the number is negative. That’ll do.

for (let auditObj in from["audits"]) {
  if (metricFilter.includes(auditObj)) {
    const percentageDiff = calcPercentageDiff(
      from["audits"][auditObj].numericValue,
      to["audits"][auditObj].numericValue
    );

    let logColor = "x1b[37m";
    const log = (() => {
      if (Math.sign(percentageDiff) === 1) {
        logColor = "x1b[31m";
        return `${percentageDiff + "%"} slower`;
      } else if (Math.sign(percentageDiff) === 0) {
        return "unchanged";
      } else {
        logColor = "x1b[32m";
        return `${percentageDiff + "%"} faster`;
      }
    })();
    console.log(logColor, `${from["audits"][auditObj].title} is ${log}`);
  }
}

So, there we have it.

You can create new Lighthouse reports, and if a previous one exists, a comparison is made.

And you can also compare any two reports from any two sites.

Complete source code

Here’s the completed source code for the tool, which you can also view in a Gist via the link below.

const lighthouse = require("lighthouse");
const chromeLauncher = require("chrome-launcher");
const argv = require("yargs").argv;
const url = require("url");
const fs = require("fs");
const glob = require("glob");
const path = require("path");

const launchChromeAndRunLighthouse = url => {
  return chromeLauncher.launch().then(chrome => {
    const opts = {
      port: chrome.port
    };
    return lighthouse(url, opts).then(results => {
      return chrome.kill().then(() => {
        return {
          js: results.lhr,
          json: results.report
        };
      });
    });
  });
};

const getContents = pathStr => {
  const output = fs.readFileSync(pathStr, "utf8", (err, results) => {
    return results;
  });
  return JSON.parse(output);
};

const compareReports = (from, to) => {
  const metricFilter = [
    "first-contentful-paint",
    "first-meaningful-paint",
    "speed-index",
    "estimated-input-latency",
    "total-blocking-time",
    "max-potential-fid",
    "time-to-first-byte",
    "first-cpu-idle",
    "interactive"
  ];

  const calcPercentageDiff = (from, to) => {
    const per = ((to - from) / from) * 100;
    return Math.round(per * 100) / 100;
  };

  for (let auditObj in from["audits"]) {
    if (metricFilter.includes(auditObj)) {
      const percentageDiff = calcPercentageDiff(
        from["audits"][auditObj].numericValue,
        to["audits"][auditObj].numericValue
      );

      let logColor = "x1b[37m";
      const log = (() => {
        if (Math.sign(percentageDiff) === 1) {
          logColor = "x1b[31m";
          return `${percentageDiff.toString().replace("-", "") + "%"} slower`;
        } else if (Math.sign(percentageDiff) === 0) {
          return "unchanged";
        } else {
          logColor = "x1b[32m";
          return `${percentageDiff.toString().replace("-", "") + "%"} faster`;
        }
      })();
      console.log(logColor, `${from["audits"][auditObj].title} is ${log}`);
    }
  }
};

if (argv.from && argv.to) {
  compareReports(
    getContents(argv.from + ".json"),
    getContents(argv.to + ".json")
  );
} else if (argv.url) {
  const urlObj = new URL(argv.url);
  let dirName = urlObj.host.replace("www.", "");
  if (urlObj.pathname !== "https://css-tricks.com/") {
    dirName = dirName + urlObj.pathname.replace(///g, "_");
  }

  if (!fs.existsSync(dirName)) {
    fs.mkdirSync(dirName);
  }

  launchChromeAndRunLighthouse(argv.url).then(results => {
    const prevReports = glob(`${dirName}/*.json`, {
      sync: true
    });

    if (prevReports.length) {
      dates = [];
      for (report in prevReports) {
        dates.push(
          new Date(path.parse(prevReports[report]).name.replace(/_/g, ":"))
        );
      }
      const max = dates.reduce(function(a, b) {
        return Math.max(a, b);
      });
      const recentReport = new Date(max).toISOString();

      const recentReportContents = getContents(
        dirName + "https://css-tricks.com/" + recentReport.replace(/:/g, "_") + ".json"
      );

      compareReports(recentReportContents, results.js);
    }

    fs.writeFile(
      `${dirName}/${results.js["fetchTime"].replace(/:/g, "_")}.json`,
      results.json,
      err => {
        if (err) throw err;
      }
    );
  });
} else {
  throw "You haven't passed a URL to Lighthouse";
}

View Gist

Next steps

With the completion of this basic Google Lighthouse tool, there’s plenty of ways to develop it further. For example:

  • Some kind of simple online dashboard that allows non-technical users to run Lighthouse audits and view metrics develop over time. Getting stakeholders behind web performance can be challenging, so something tangible they can interest with themselves could pique their interest.
  • Build support for performance budgets, so if a report is generated and performance metrics are slower than they should be, then the tool outputs useful advice on how to improve them (or calls you names).

Good luck!



Source link

How to Make Repeating Border Images
Strategy

How to Make Repeating Border Images


I just saw this cool little site from Max Bittker: broider. You design an image on a 9-slice grid (except the middle part) and it will produce an image for you to use with border-image along with the CSS to copy and paste.

Check out my little design:

The areas of the image ultimately output to a base64 PNG file with the designs in each area. For example, if you just drew in the top-center quadrant, the generated PNG looks like this:

Which gives you a single border like this, which might be just what you want:

On the new ShopTalk Show website, we have a similar effect in a few places, like this:

We did that in a slightly different way. Rather than border-image, we used a background-image and background-repeat: round; That way we could use an image in pretty much the same way, only we had to take the extra step of placing an “inner” element in order to knock out the middle (so it fakes a border).

Like this:

Looking at it now, we probably should have just used border-image, as it can do the same thing and is a bit cleaner. Our Almanac page has more examples.



Source link

10 JavaScript Things New React Devs Need to Know
Strategy

10 JavaScript Things New React Devs Need to Know


I recently worked with a group of volunteer developers to start moving our RICOH THETA Developer community web sites into an integrated React web application. The experience was wonderful. We were able to quickly tap into REST API data sources with React and build an interface to our fun dev community that gets roughly 1 million views a year. Most of us were new to React when the project started. Although I had fun, it would have been more fun had I spent an extra 20 minutes brushing up on modern JavaScript before I started reading React code examples.

I’ll explain the 10 JavaScript things we wished we studied just a little bit more before we started coding the site in React by grabbing online code examples.

Our new React site is still in the community feedback phase, but you can see the current concept here. The site consists of three primary React components, each pulling data from a different REST API. The backend data sources are a combination of APIs from our Discourse forum, Django Rest Framework holding our list of apps in PostgreSQL, and our custom document server. 

The bottom line is that the component architecture of React is so awesome that we were able to get something up in a few days and use the site itself to solicit feedback on the design instead of a long-drawn-out process of mockups and discussion. 

You might also be interested in: Functional Programming Using JavaScript

Absorb the 10 tips below and get started on your first React project today. 

1. Fat Arrow

Fat arrows are used as function shortcuts. Instead of writing function() , you can omit the function keyword and write  () => . You can omit the return statement and the curly brackets if you return only line, () => "long string" .  

You can assign the function to a constant: const MyExport = () => { code goes here }.

2. Template Literals

There are three ways to specify strings in JavaScript.

  1. Double quote  "string" 
  2. Single quote  'string' 
  3. Back-tick  `string` 

The back-tick string comes with special powers.

You can insert variables into the string.

Another fun back-tick feature is that the string can span multiple lines.

Run and edit code snippets.

3. Import and Export

You can import code from one file into another.

 import { MyExport } from "./MyExport.js";  

In this example, I am importing MyExport.js into App.js

This code example is available here.

To import the contents of a file, you must export it. The example below shows use of a fat arrow function, template literal, and the new export feature.

Back in my  App.js  file, I can now use the function that I exported from  MyExport.js .

The  console.log  output is shown below. 

4. Destructuring

You can destructure objects or arrays with this syntax.

 const {userId, title} = json 

To illustrate this example, let’s first pull a JSON entry from the fake JSON test server, jsonplaceholder.

I can now work with this single JSON entry.

The JSON entry is held in the variable called,  json .

I can now pull the  userId  and  title  out by enclosing these keys in curly brackets.  {userId, title}.

The console will show the following:

Run the example  here.

5. Map

You will use the array map method constantly. Master it. This works like a forEach loop.

Code examples are available here

The result is: 

  [ 1, 4, 9, 16 ] 

This example uses the fat arrow function. This allows us to eliminate the curly brackets and return statement. The code loops through each element of the array and holds each value in the variable  element 

You can add a string to the variable. 

 console.log(myArray.map(element => "My number is " + element)); 

You can get the index of the array by adding a second parameter.

 console.log(myArray.map((element, index) => `At index ${index} the number is ${element} `));

 

6. Filter

Using the same array, you can filter the output for conditions.

 console.log (myArray.filter(element => element > 3)); 

Filter returns an array. In this example, the array is only a single element, [4].

7. Find

Find is similar to filter but does not return an array. It will only return the first element that meets the condition and then exits.

 console.log(myArray.find(element => element === 3)); 

This code returns a single number, 3 .

8. Reduce

This is the most difficult to understand of the array methods.

It works like a loop that has an outside global variable that keeps the contents of a mathematical operation applied to each element of the array.

The classic example is to add all the elements of an array together and return a single number.

This returns 10.  The variable total starts at 0. 

  1. total = 0, current = 1 (first element of array)
  2. add 0 + 1.  Now total is 1.
  3. loop through array
  4. total = 1, current = 2 (second element of array)
  5. add 1 + 2. Now total is 3
  6. loop 
  7. total = 3, current = 3 (third element of array)
  8. add 3 + 3.  Now total is 6
  9. loop
  10. total = 6, current = 4 (fourth element of array)
  11. add 6 + 4. Now total is 10 – This is the answer!

You can start the total or accumulator at any value. The code below starts the accumulator at 100.

 console.log(myArray.reduce((total, current) => total + current, 100)); 

The result is 110.

The code for all the array exercises is available here.

9. Ternary Operator

The ternary operator looks weird.

 console.log(activeUser ? "Welcome" : "Please sign in");   

It functions like an if-then-else statement.

The variable to the left of the question mark  ?  is a boolean true/false variable. The string “Welcome” is shown if activeUser is true.  If activeUser is false, then the string after the colon   is shown – “Please sign in” is shown.  This code will log “Welcome”

This code will log “Please sign in”.

Despite the weird looks, the concept of the ternary operator is easy to understand if you think of it as a shortcut for an if-then-else statement.

10. Async and Await

I find the syntax of async and await easier to understand compared to promises.

In my earlier point on deconstruction, I used a promise.

Although the functionality of promise and the async function with await are the same, the promise can be written with async and await to clearly show what your code is waiting for.  In this example, the code must first wait for the response data to arrive from the Internet.  It then needs to wait for the response to be converted into JSON.  The code example below is available here

Summary

React is a wonderful framework to use for development. It can help make JavaScript fun again.  The development system integrates Babel behind the scenes, allowing us to use new JavaScript features that makes JavaScript easier to use once we learn the new syntax. Beginners to React might feel intimidated reading the many code examples or tutorials available for React if they aren’t familiar with the new features of JavaScript.  Learning JavaScript language fundamentals before diving into React will allow you to focus on the cool and exciting component architecture of React that enables you to build beautifully designed applications quickly.  

Further Reading

How JavaScript Actually Works: Part 1

Guide to New JavaScript Features Introduced at Google I/O 2019



Source link

10 Reasons Why Every Developer Should Learn Python in 2020
Strategy

10 Reasons Why Every Developer Should Learn Python in 2020


There are only a few programming languages of the world that offer multiple functionalities. 

In today’s world, where developers have to build various types of applications, learning a language that is multi-functional is definitely helpful. 

Python is definitely one such language that can be considered a general-purpose programming language that would let the developer build various types of applications.

You may also enjoy: My Journey With Python (Part I)

Reasons To Learn Python In 2020

1. Web Solutions

Python is considered to be amongst the preferred languages of the web developers. Consequently, learning this language would work in your favor as a developer. 

There are many web behemoths that are designed and powered by Python, like Google, Youtube, Netflix, Instagram, Dropbox, Yahoo, Reddit, Spotify, and many more. Python is used more to build server-side applications. 

With Python, we also have a great benefit from having useful libraries. These libraries would help in storing modules or routines which are used on a regular basis by programs. 

Some examples of useful Python libraries are JSON, HTML and XML, beautifulSoup, Feedparser, Email processing, request, and so on. Python also has some amazing frameworks which have files and folders where we find the blocks with ready-to-use codes. 

Some great Python web frameworks are Django, Pyramid, Flask, Tornado, web2py, CherryPy, Falcon, and many more. 

2. Data Science

With the advent of the web, innovative ways of using it have been developed. From which this is one of the most useful ways. 

In today’s world where data is considered to be of paramount importance, organizations use data science so that they can add value to different aspects of operations. 

Python is used by the developers for data exploration, data analysis, and data visualization. It is preferred by data scientists because of the kind of ease of use it provides, and the coding is simpler in comparison to other difficult to learn programming languages. 

There are certain libraries that help in data exploration as well as analysis such as SciPy, Pandas, NumPy and some more. 

For data visualization, we have some great helpful libraries named Matplotlib, Datashader Seaborn, Basemap, Cartopy, Ridge Map, Geoplot, holoviews, DeCiDa and so on.

3. Feasibility

Python is a high-level language. Two types of programming languages with stark differences exist for web development. One is the high-level programming language whereas the other one is low-level programming language. 

In the former one, the language used is closer to the human language whereas, in the latter one, it is near to machine language. 

It is obvious that the language that is close to human language is easier to understand. On top of that, the codes in Python are short.

As they render readability, they are easy to form. When other programming languages are extremely difficult to code, this is definitely a contributing factor to the increasing popularity of this language.

4. Simple Learning

This language is growing. One of the important reasons behind this development is eased it provides when one learns it. Python is not a very complicated language. As a result, learning becomes easier in comparison to other languages. For learning any programming language there are two components that are of utmost importance: codes and syntax. 

Being a high-level language, the codes are simpler in comparison to other low-level languages and syntax is also easier to other languages. 

It is so simplified that it is now the most popular introductory teaching language at top universities in the US. 

It is used in eight of the top 10 computer science departments for teaching Python in introductory computer science courses. 

5. Artificial Intelligence and Machine Intelligence

Remember the sci-fi movies we used to watch and get awestruck by those machines which used to work which was not possible to do for us humans!! 

Now, these fictional stories are going to convert into reality soon. In fact, some have already been converted. 

This has become possible due to the advent of Artificial Intelligence (AI) and Machine Intelligence (MI).

For making AI and MI work, we need to learn the machines first. Machine Learning would help us in observing and providing meticulous results of humongous data. To acquire, analyze and manipulate gathered data we need a programming language. Almost all developers use Python for this purpose.

There are some important benefits provided by Python which make it be the preferred choice of developers. Amongst them are stability and ease of use. 

Python is helpful in the development of codes and processes. It aids in the execution of the created routines and finally assists in maintenance. 

Python provides some of the most useful tools like amazing libraries such as

  • SciPy for scientific-technical computing
  • NumPy for mathematical functioning and scientific computing
  • Keras, and Scikit-learn for machine learning (for Artificial Intelligence)
  • TensorFlow for Machine Learning and Symbolic Math Library

Because of the credibility and readability this language provides, it has become the primary choice of the developers.

6. Adaptability

Python is considered to be one of the most flexible programming languages. It is called so for not only one but two reasons.

Integration With Other Programming Languages

Python is able to combine the different large components or blocks of other languages and make one whole. 

With the help of Python, applications can be programmed in a better manner because it makes it possible for various types of programmers to work together on one single project. 

Let’s take an example. If we plan to build a data science application, C/C++ developers can work on and execute numerical algorithms whereas data scientists who are working on the same project will be able to code Python programs that would first test and use the algorithms developed. This is how the integration works.

Platform Independence

Python is a cross-platform programming language. This means that Python applications can seamlessly work on various Operating Systems such as Windows, Linux/Unix, Mac and so on. 

A Python program that is developed in Windows can work in Mac or Linux/Unix systems and the other way round. This is one of the greatest advantages of Python. 

This feature saves extra costs involved in purchasing and learning a new Operating system. Hence, this is a highly laudable trait of this language.

7. Multiple Functionalities

Python can be called a general purpose programming language as its functions are multi-directional. There are various fields and aspects in which it becomes helpful. 

Apart from the ones already mentioned data science, web solutions and artificial and machine intelligence, there are some more too, which are listed below:

Desktop Graphical User Interface Applications

We are able to create Desktop Graphical User Interface Applications using Python. There are some amazing GUI frameworks available if one wants to create GUI applications. 

They are PyQT, Tkinter, PyGUI, WxPython, Kivy and many more. Kivy is preferred for building multi-touch applications.

Commercial and Enterprise Applications

Using Python, you can make related applications which would help in the overall business. Some examples of the same would be ERP and e-commerce systems. 

Even applications that can be used intra-organization can also be developed using our favorite language. We can take Picalo, Odoo, and Tryton as examples.

3D Graphics and Games

With the help of Python development, you can create applications that use 3D graphics. This would surely lead to building applications of gaming. 

There are some useful frameworks like PyKyra and PyGame. They are two frameworks that help in developing games. We also get some 3D rendering libraries.

CAD Applications

Computer-Aided Design is gaining a lot of popularity as it helps us visualize in a better manner. 

However, creating the application of the same is a big pain for the developers as objects and their usefulness have to be represented well. 

Their life is made easy by our own Python. Fandango is one such example of this type.

Audio and Video Applications

Using Python, you can create applications that are able to interact with multi-media like audio and video. 

We have some great examples of the application which have been developed using Python-like Cplay and  TimPlayer.

So, Python is truly a versatile player. This has to be the most motivational reason behind learning it.

8. Frameworks and Libraries

Let’s first understand what they are and what the difference between them is. 

Framework 

Applications are made of numerous codes. If the applications are huge, they would require lots of coding. There are certain components that are commonly used to build a website.  

Web frameworks have files and folders with coding which is ready-to-use. This would help in making programming hassle-free. 

Library

A library is a group of precompiled modules which a program usually uses. They are stored in the format of an object. The modules which are used on a regular basis are stored in libraries.

9. Community Support

As mentioned earlier, Python has been used for more than 25 years and there are more than 8 million users of Python across the globe.

As a result, we find a lot of support provided by the community members. They help in different ways which are mentioned below:

Suggestions

Even the most seasoned developers sometimes require suggestions. Community members even consist of some of the best developers. They come to your aid when you get stuck at a point in your development. 

Knowledge of the Bugs

There are discussions taking place with regard to the kinds of bugs found in libraries or frameworks. They are then escalated as well. We get knowledge about what is lacking.

Learning for the Newcomers

The novice gets to learn a lot as there are many experienced developers who are community members. This is how the community helps the developers.

10. Cost-Effectiveness

Python is an open-source programming language. Hence, it is available freely. We can use the allocated budget elsewhere where we feel it be appropriate. Or else we can save the project overhead because of this. 

In fact, most of the frameworks and libraries are also open-source. So, this helps not only the developers but even the organizations to a great extent. 

In big organizations, huge budgets are allocated for acquiring licenses for programming languages. That budget can be straight away used in other purposes.

Lastly, Python is proving to be a great career choice as a lot of development jobs are prevailing in the market and it offers a handsome salary. So, it would be a wise choice to learn it in the new decade.

Conclusion

Here, we have provided you with a list of reasons for which you should learn Python in 2020. 

We hope you had a great time reading this article and it proves to be of great help.

If you still have any questions or suggestions related to the blog, feel free to mention them in our comment section. 

Further Reading

Six Python Tips for Beginners

Top 10 Resources for Python Developers



Source link

Post image
Strategy

Meditation Website Design : graphic_design


Hi r/graphic_design community,

I’m a programmer who’s working on a side project that lets people come together and meditate during a 2-hour window every week. Which is good timing considering the number of people (including myself) starting to work remotely on a TBD time basis.

I have a simple single page application setup going but know the design and experience could be better.

This is the screen I have up before a session starts. When the session has started, a Buddhist chant plays with a mute option and info about the chant that’s playing. I’m setting up a count button people click where new people coming to the site can see how many other people have/are meditating.

Post image

If anyone’s interested in helping out with the design for a fun project to work on and design/idea credits on the about page don’t hesitate to reach out.

Thanks for reading and stay safe



Source link