Tuesday, November 26, 2019

Front-End Learning for Programmer

If you are an existing programmer (fluent in one common programming language) and want to learn Front-End (HTML+CSS+JS), I would recommend using freeCodeCamp and picking only the modules you need. If you want to learn just enough to work on modern front-end projects or start a new project with Create React App, below is what modules I think you should learn on freeCodeCamp.

“✔️” means you should learn it. “❌” means you could skip it. “❗” means you could skip if you are in a hurry but you should learn if you have time.

  • Responsive Web Design
    • ✔️ Basic HTML and HTML5
    • ✔️ Basic CSS
    • ✔️ Applied Visual Design
    • ❌ Applied Accessibility
    • ❌ Responsive Web Design Principles
    • ✔️ CSS Flexbox
    • ❌ CSS Grid
    • ✔️ Responsive Web Design Projects
  • JavaScript Algorithms and Data Structures
    • ✔️ Basic JavaScript
    • ✔️ ES6
    • ❌ Regular Expressions
    • ✔️ Debugging
    • ✔️ Basic Data Structures
    • ❗ Basic Algorithm Scripting
      • (Use it as a practice to write more JavaScript code.)
    • ✔️ Object Oriented Programming
    • ✔️ Functional Programming
    • ❗ Intermediate Algorithm Scripting
      • (Use it as a practice to write more JavaScript code.)
    • ❗ JavaScript Algorithms and Data Structures Projects
      • (Use it as a practice to write more JavaScript code.)
  • Front End Libraries
    • ✔️ Bootstrap
    • ❌ jQuery
    • ❌ Sass
    • ✔️ React
    • ✔️ Redux
    • ✔️ React and Redux
    • ✔️ Front End Libraries Projects

Tuesday, November 12, 2019

Progressive Web App as Share Target on Android

I built a PWA (Progressive Web App) to trace shortened URL back to its original URL. (You can find it here.) I don’t want to copy a URL and paste it into my app. I want to use the Android’s sharesheet to send any link in Chrome straight to my app. How do I do that?

Google provides good documentation on this. We need to add a share_target section in manifest.json and then declare that our PWA can act as a share target. Most of the properties in this section can be thought of as attributes on a <form> element with the same name. For example, { "action": "/share", "method": "POST" } is like <form action="/share" method="POST">.

params subsection let us change parameter names if we already have a convension of naming search parameters in GET requests or form fields in POST requests. Otherwise, we can keep them in their original names. One caveat is Android doesn’t use url parameter so when sharing a URL it comes through the text parameter. In my app I need to coalesce these two parameters to get the input from the user.

Is there more? Yes! Twitter makes a great PWA and we can check their manifest.json. Here’s the beautified version of the share_target section:

"share_target": {
  "action": "compose/tweet",
  "enctype": "multipart/form-data",
  "method": "POST",
  "params": {
    "title": "title",
    "text": "text",
    "url": "url",
    "files": [
      {
        "name": "externalMedia",
        "accept": [
          "image/jpeg",
          "image/png",
          "image/gif",
          "video/quicktime",
          "video/mp4"
        ]
      }
    ]
  }
}

It has a files subsection under the params section. This is part of the Web Share Target Level 2. We can accept files from sharesheet and we can assign a file to different parameter name based on MIME type or file extension. My app doesn’t need this capability but it’s good to know what’s possible.

If you like my post, you can subscribe through email or RSS/Atom. That makes sure you won’t miss my future posts.

Wednesday, November 06, 2019

Batch Sending Email with Attachments through AppleScript

I want to learn a little bit of AppleScript. I need to help a friend send out emails to welcome new students to the school. The requirements are:

  1. addressing each recipient by their name in email content;
  2. attaching the same file in all emails.

After some research and tinkering I have a script to send emails:

theRecipients is the list of recipient names and email addresses. This is for requirement #1. theAttachment isn’t hardcoded to any file path. It will prompt and let me choose a file when I run the AppleScript.

The trickiest part is the delay 1. Without this line, emails will be sent without the attachment. It’s a hack to make sure each email has the attachment. I don’t know why it works and I can’t find an explanation online.

After building this AppleScript, I learn that Google App Script is another great way to automate sending emails through Gmail (or GSuite). I will learn App Script and write a post about that next time. If you like this kind of posts, you can subscribe through email or RSS/Atom.

Tuesday, September 24, 2019

MailChimp Popup Dialog on Click

Problem

MailChimp provides sign-up form as pop-up dialog, but has limited options for when to trigger it. Available triggers are like “immediately after the page is open”, “when the user scrolls to the bottom of the page”, etc. I want to trigger the dialog when a reader clicks the sign-up link on my blog. Instead of navigating to the sign-up page, I want to open the dialog and speed up the experience. I hope this can improve subscription rate.

Solution

MailChimp provides an HTML snippet for the pop-up dialog. It contains two <script> tags. I left the first one untouched and modified the second one. Read the code below for reference:

In the first <script> tag, I did nothing. In the second <script> tag, I wrapped the original JavaScript in a function called displayDialog, which will be called in the sign-up link’s click event. I added a third <script> tag to search for sign-up links in the page and add the click event handler.

Within displayDialog function, I not only call the original code in the second <script> tag but also delete two cookies before that. That’s because MailChimp set one of these cookies when a user dismisses the dialog or subscribes through the dialog. The presence of one of the cookies will prevent the dialog from opening again. This behavior makes sense when using MailChimp’s automatic triggers – a user shouldn’t see a dialog again after either dismissing or subscribing. It doesn’t make sense when the trigger is user clicking a link because it’s a clear intention to open the dialog. (If you want to reuse my code, remember to replace window.dojoRequire(...) with the code from your own MailChimp campaign.)

The third <script> tag is customized for my own blog. It looks for any link that points to the sign-up page and add the click event handler. The event handler calls displayDialog to trigger the dialog and then cancels the browser’s navigation to the sign-up page.

If you want to test this feature, make sure you open this post from my blog and click this link to subscribe. It should open the sign-up dialog instead of the sign-up page. If you like this post, remember to put in your email and subscribe!

Wednesday, August 28, 2019

Is Targeted Ads Price Discrimination?

If you use a service for free but you need to see ads targeting towards you, how much do you actually pay? I didn’t think about this before I used Google Contributor a few years ago. Now I think I pay the whatever the price advertisers pay to show me the ads, but then the advertisers subsidize me fully to get me to see their ads.

The concept of Google Contributor is very simple. You can understand it if you ever purchased targeted ads online. You set up a budget between $2 and $15 per month. You use that budget to buy ads targeting a single person – yourself. You compete against any advertisers that happen to target you. Every time when you are supposed to see an ad, the bidding process happens between you and other advertisers. If you win, you see a message saying “thank you for being a contributor” in the place where the ad should be displayed. If you lose, you see the ad from the winning advertiser, just like if you were not using Google Contributor.

I would imagine I win in every case so I never see any ads. The cost I pay for that is the price I actually pay for using the “free” service. When I don’t win or when I don’t use Google Contributor altogether, it’s advertisers subsidizing me but I have to see their ads, but it’s still the same price.

It’s interesting that different user pays different price. It’s like price discrimination. If you are worth more in the eyes of advertisers, you pay more. If your impression is worth less, you pay less. It’s easy to guess that an average user in the US would pay more than an average user in India.

If we apply similar price discrimination to a subscription based service (e.g. Microsoft Office 365, which is cheaper in China), we need to use IP check or other methods to prevent customers in a higher price region from purchasing from a lower price region. There’s no such need when the service is paid by targeted ads. A user in the US can’t pretend to be in India and then “pay” less by seeing lower cost ads. It’s also not in the US user’s interest to do so, because ads targeting an Indian user is less relevant and doesn’t improve experience.

In conclusion, I think targeted ads is an effective form of price discrimination. What do you think? (Feel free to comment after the post.)

Friday, August 31, 2018

Harp/Jade Debug Snippet

I’m using Harp with Jade recently. At the beginning, it was hard for me to figure out the JSON data structure used by Harp at build time. It was also hard to debug JavaScript function written in Jade and executed at Harp compile time. In the end, I figured out that I could dump that JSON as a string to console.log in browser. Everything is so much easier now.

Now I have that debug.jade file in my project. Whenever I want to examine some JSON data in Harp, I just call != partial('debug', { data: anything }) and pass the right data.

Wednesday, May 16, 2018

Divide Notifications into Interrupt, Reminder and Backlog

iOS push notification

I ran an experimentation for more than a year. I put all of my iOS devices into permanent Do Not Disturb mode. It was a great experience, but I felt I should let very small amount of push notifications through.

My initial intention of setting permanent Do Not Disturb was to avoid distraction in my 1:1s. I could see how other people looked at their phones during 1:1. Sometimes it’s a push notification. Sometimes they were just not paying attention to me. I wanted to avoid doing that, so I put my iPhone into DND mode. My Apple Watch mirrored, so it didn’t make a sound or vibrate either.

My experience with permanent DND was good. I no longer had the unconscious reaction to look at my phone when it vibrated. I didn’t need to put away my phone, because it acted like it never received those push notifications until I proactively look at it. There was one small problem: Somtimes I missed those really important push notifications, and then I missed meeting or a time sensitive message.

Because I was very happy with the silence of almost all notifications, I didn’t want to change that. I only wanted a small patch to let some of them through. That triggered me to think about what my ideal push notification model would be. My conclusion was push notifications should be divided into 3 categories:

  • Interrupt: An interrupt should interrupt whatever transaction I’m in and get me to deal with it immediately. This should be extremely rare, and I shouldn’t miss when it happens.
  • Reminder: An ideal reminder should remind me of things in the perfect context, which usually means right time (in between transactions) and right place.
  • Backlog: This is like an email sitting in my Gmail unopened for years. If I want to take a look, I can. Otherwise, don’t come to me. Backlog should never be pushed. It should be pulled.

These are the ideal categories, but iOS doesn’t allow exact setup like this. I have to tweak a little bit and make it implementable within iOS. There are these constraints:

First of all, iOS push notification settings are on per app basis. Because most apps don’t provide finer granularity on push notification control, that means I have to assign category to apps. If I assign interrupt category to an app, every push notifications from that app is an interrupt.

Second, only built-in apps have complex notification settings for iOS and watchOS. For most apps, there’s only one setting for sound. It’s either on or off. Vibration is associated with sound and they are toggled together. There’s an additional toggle for Apple Watch. It’s all or nothing. That means if sound and vibration is on for iPhone, it’s also on for Apple Watch.

One more thing. Because existing technology can’t remind me in perfect context, I have to allow apps to remind me at its convenience and use snooze to make it wait for the perfect context.

Based on these constraints, here is my setup:

  • Interrupt: Apps in interrupt category can use sound/vibration. They can show notifications on Apple Watch. I have certain messaging apps in this category. They are not my main messaging apps.
  • Reminder: Apps in reminder category can also use sound/vibration. They need to provide a snooze button in notification. They show up on Apple Watch. I have some calendar and todo apps in this category.
  • Backlog: No sound and thus no vibration. Not allowed on Apple Watch. This is exactly the same as permanent DND mode.

Besides, I disabled badge for apps that are abusing it. If an app uses badge to get my attention frequently, I disabled badge for it.

There’s a 4th category that I would call null. Apps in this category use push notification to promote themselves in a way that’s not valuable to me. I disabled push notification for them.

This setup isn’t perfect. Apple doesn’t design iOS to work in this way. Apple gives some level of control to users, but no automation for power users. At the moment, I have to turn off sound for most apps one by one because they are in backlog category. I have to turn them off for Apple Watch, too. If I can make this default settings for all new apps, it could save me time.

This is my new experimentation for 2018. It’s working well so far. Maybe I’ll give another round of update in 2019 and identify new ways to tweak this. I hope iOS and Android have more power ways to manage notifications at that point.