How DNS Mistakes Can Score You a Google Manual Penalty

When your livelihood is tied to website traffic, one of the worst things you can wake up to is an email from Google Search Console.

I’m no stranger to bad news from the Big G and the non-communication and horror movie circular forward-you-to-the-right-group conversations that go along with any dialog you might think would rectify the problem. I spent six months trying to get my site off the AdExchange blacklist because of a minor AdWords violation on an account I didn’t even know was still serving $10 per month worth of ads. Which sounds insane, I know, because my ancient AdWords account should have nothing at all to do with my display partner’s Ad Exchange account, but believe me… What a mess. In that case, I was fortunate that a friend-of-a-friend-of-a-friend had a direct Google rep with a back-door into some super-secret re-evaluation queue not visible to mere mortals.

But my real talent seems to be using DNS records to try to shoot myself in the hard drive. A couple of years back I managed to take my math worksheets site offline with a DNS record change that I thought was working fine because of a forgotten localhost entry that resolved to the right address. When I saw a huge traffic drop in Google Analytics the next day, I immediately knew I’d messed up, but that brief span of time offline wiped out almost six months worth of SEO ranking progress. I’m a huge fan of Uptime Robot now.

Not How You Want to Start your SEO Day

Subdomain DNS Records are Dangerous

So you can bet, I’ve become pretty dang careful with DNS records pointed to my primary site. But, I’m also a developer.

There’s that old adage, “Real Developers Test It In Production,” something you should not ascribe to, so naturally I sandbox development and staging servers on subdomains. And of course, a subdomain means a DNS A/AAAA record that needs your full attention. And that, friends, is the beginning of the reason why I got another Google Search Console email a couple of days ago and why I’m doing something different with my dev servers going forward.

The obvious scary thing in the email’s subject line was the words “Hacked Content” and then, if that wasn’t enough to make every hair stand on end, the body text shouted “manual penalty” with a handy link right to the page on Google Search Console, which provided a big fat confirmation of every bit of bad news. Great.

After I calmed down a bit, I settled in to see what was going on. Google helpfully provided links to some of the pages that it claimed were hacked, and none of the URLs looked right at all. None were coming from the main www subdomain, which immediately lowered my heart rate, but even the URLs to the development subdomain they all referenced looked really weird.

And then, it downed on me, that development subdomain wasn’t even around any more. I had decommissioned the server it was running under months ago, so that content couldn’t even be coming from a machine I was using. That server was gone, but its IP address was still resolving. And when I’d surrendered that IP address back to Linode, it meant that basically anybody else could start using a new server with that IP for their own purposes. So when someone else spun up a new site, it became reachable via a subdomain I still had defined. DNS induced brain damage, part two it seemed.

So in this case, there wasn’t any “hacked content” anywhere, it was just that my DNS made it look as though I was serving duplicate content from some random site out from under a subdomain I controlled. And while the manual penalty suggested it was only relevant to URL patterns that matched that subdomain, it was also pretty specific that the manual penalty affected the overall reputation and authority of everything under the domain, so fixing it right away was a priority.

The obvious and easy solution was just to delete the DNS record pointing to that subdomain, wait for propagation and then file a reconsideration request through Search Console. Even though the reconsideration request indicated that Google took “several weeks” to review anything, I did thankfully get a follow up email in roughly 36 hours that said the penalty had been removed.

I’m not sure if I took a short term traffic hit or not on the main domain as all of these events transpired over a weekend, and the traffic pattern for this site drops off significantly there and around the holidays in general. Otherwise the site traffic looks normal in spite of the brief stint with the manual penalty in place. So far, it looks like I dodged whatever bullet might have been headed my way. I think an important contributor to this rapid turnaround and preserving rankings was that I fixed the issue rapidly and explained in clear detail in the reconsideration request what happened and how I resolved it, and specifically that it wasn’t actually an actual malicious hack.

But the key take away is not just to be super careful managing your DNS entries, but also to run any publicly visible development and test boxes under a domain that has nothing to do with your main property.

If this had been an actual hack of a machine we were using for something critical, and maybe one that appeared more malicious than serving duplicate content, that manual penalty could have had a real negative financial consequence for the main site. It’s hard enough to secure a production server, but a development machine that is transient in nature is probably going to be less secure, and potentially a softer attack vector.

SEO is hard work, and shooting yourself in the DNS is pretty easy. If a hack, or even just a DNS misconfiguration, of a dev machine can lead to a manual penalty that affects not just the subdomain, but your entire web property, it’s much wiser to have it far away from your main domain. In the future, I’ll be running any publicly visible dev machines under an entirely different domain name for this reason.

Eclectic Observations from Arriving Late to the LinkedIn Party

After having been bitten quite hard by Google’s August algorithm update, I’ve been on a mission to establish a bit more EAT related to my online presence in hopes of a recovery. If you’re wondering what the heck I’m talking about, EAT is a recent bit of buzz phraseology that has those of us with an interest in SEO pounding our forks at the dinner (i.e., revenue) table and hollering about the latest batch of secret ingredients in Google’s ranking algorithm sauce.

EAT in SEO parlance stands for “Expertise, Authority and Trust” and from all impressions, this seems to be a subjective measurement of a site’s credibility assigned by a human quality ranker at the Big G. And fundamentally this comes down to identifying people associated with sites, and establishing that those sites are built and run by bonafide credentialed humans and not Russian robots or other nefarious automatons. Google has a document that gives some vague hand-wavy instructions for its human raters to follow to find out more about a site’s pedigree, typically by looking off-site for items on the EAT menu.

I’ve been studying this menu for a while now, but one item off the appetizer list that I completely missed was setting up a personal profile on LinkedIn and getting a company page listed for DadsWorksheets.

So let me be candid here. I’m a terrific introvert. Where lately people run around denouncing the looming perils of social media addiction, I’m one of those dungeon dwellers whose arm need be twisted nigh off before I’ll log into my FaceBook page. And, yes, if you’re one of the hundred-odd people who’ve sent me a LinkedIn invitation in the last few years, I hope you don’t feel scorned that I didn’t join you and I’ll ask your forgiveness now… It’s just that I never actually setup an account until today.

But after arriving catastrophically late to the party and reaching out to a dozen connections who might take some pity on my apparently self-induced social media ostracism, I did have a few observations coming in the door:

  • Wow, most of you old friends look quite professional in your profile pictures. I find myself wondering if I should shed my sunglasses, or if there’s some value in maintaining profile picture continuity across StackOverflow, GitHub, Discord and all the other tech-oriented services I actually do lurk through regularly.
  • Indeed, your profile pictures match some envious résumés and work history.  And interestingly, some glaring omissions. I’m looking at you, dear Veebo alumi, and wondering about airing those battle scars publicly as well.
  • Even more nostalgia inducing than the prospect of updating my own dusty CV is seeing where so many of you have travelled since we parted company. Being in this soloprenuer consulting thing for so long, it’s easy to forget how many interesting places with great people you’ve worked with. It’s good to see you all again.

So maybe this social media thing isn’t all the cat videos and political noise it’s seemed to be, and I just needed to find the right place. We’ll see. For now, the hour or two on LinkedIn today was actually kind of fun.

Adding Snap.svg to Vue.js and Nuxt.js Projects

SVG is amazing, and if you’re building any custom vector graphics from your client code, one of the easiest libraries to use is Snap.svg. I’ve used it in a number of projects, including vanilla JavaScript and various transpiling setups including Transcrypt.

I’m trying to go a little more mainstream after wasted years of time on fringe technologies that fell out of favor.

I’m spending a lot of time these days learning Vue.js and really hoping this is going to be a worthwhile long term investment in my skillset. So it was only a matter of time before I found myself needing to get Snap.svg working in my Vue.js projects, which meant some extra fiddling with WebPack.

Getting Snap.svg Working with Vue.js

Out of the gate, there’s some hurdles because Snap mounts itself on the browser’s window object, so if you’re trying to load Snap through WebPack (as opposed to just including it in a project using a conventional script tag), you need to do some gymnastics to get WebPack’s JavaScript loader to feed the window object into Snap’s initialization logic. You can find an overview of the problem in this GitHub issue which illustrates the obstacles in the context of using React, but the issues as they relate to Vue.js are the same.

I’m assuming you have a Vue.js webpack project that you started with vue-cli or from a template that has everything basically running okay, so you’ve already got Node and webpack and all your other infrastructure in place.

For starters, you’ll want to install Snap.svg and add it to your project dependencies, so from a terminal window open and sitting in the directory where your project’s package.json/package-lock.json sit…

npm install --save snapsvg

That will download and install a copy of the Snap.svg source into your node_modules directory and you’ll have it available for WebPack to grab.

Normally you’d be able to use a package installed like this by using an import statement somewhere, and you’d think you could do this in your Vue project’s main.js file, if you start down this path you’ll get the window undefined issue described in that GitHub link above.

The tricky bit though is getting WebPack to load the Snap properly, and to do that we’ll need a WebPack plugin that lets us load as a JavaScript dependency and pass some bindings to it. So, in that same directory install the WebPack imports-loader plugin…

npm install --savedev imports-loader

To tell the imports-loader when it needs to do its magic, we have to add it to the WebPack configuration. I changed my webpack.base.conf.js file to include the following inside the array of rules inside the module object…

 module: {
   rules: [
       test: require.resolve('snapsvg'),
       use: 'imports-loader?this=>window,fix=>module.exports=0',

Now we can load Snap.svg in our JavaScript, but imports-loader uses the node require syntax to load the file. So in our main.js, we can attach Snap.svg by telling WebPack to invoke the exports loader like this…

const snap = require(`imports-loader?this=>window,fix=>module.exports=0!snapsvg/dist/snap.svg.js`);

…and then attach it to our root Vue instance, still in main.js, something like this…

const vueInstance = new Vue( {
 el: '#app',
 template: '<App/>',
 components: { App }
} );

export { vueInstance };

There is some redundancy in that require() call and the way we setup the module resolution in the WebPack configuration. I’m fuzzy about why I seemed to need this in both spots, but it works so I’m running with it. If you have insights they’d be appreciated; let me know in the comments.

Getting Snap.svg Working with nuxt.js

Nuxt requires a slightly different twist, because as you’re aware a typical Nuxt project doesn’t have either a main.js file or a native copy of the WebPack configuration. We need to make the same changes, but just in a slightly different spots.

You need to install both snapsvg and imports-loader just like we did above…

npm install --save snapsvg
npm install --savedev imports-loader

The way we modify the WebPack configuration in a Nuxt project is to create a function that accepts and extends the WebPack configuration from with your nuxt.config.js file…

 ** Build configuration

 build: {
   extend(config, ctx) {
      config.module.rules.push( {
        test: require.resolve('snapsvg'),
        use: 'imports-loader?this=>window,fix=>module.exports=0',
       } );

Since we don’t have a main.js, we need to use a Vue.js plugin to inject shared objects and code into Vue. In your projects plugins folder, create a file named snap.js that contains code to attach a snap object created again using imports-loader…

export default ({ app }, inject) => {
  app.snap = require(`imports-loader?this=>window,fix=>module.exports=0!snapsvg/dist/snap.svg.js`);

…and back in your nuxt.config.js file, include this plugin…

plugins: [
   {src: '~/plugins/snap'},

These approaches seem to work well for me in both a standard Vue.js and Nuxt.js projects, but both of these setups have been cobbled together from reading a lot of other bits and pieces… If you’ve got a better or approach or see a way to clean up what I’ve done, please let me know.

Meanwhile, good luck with your Snap and Vue projects!





Migrating from to the AnyBoard App

For a little over a year, I’ve been running a fantastic NOC-style dashboard on the AppleTV in my office courtesy of a nifty app called Dasher. It took a little Python gymnastics, but I was able to pull data from Google Analytics, Ahrefs and Staq to assemble a consolidated view of what’s happening at, all of which helps keep my eye on getting things done there.

Much of the work in this is a Python script that runs locally to collect the data. I’ve been pushing that data up to Dasher’s servers, which then gets fed back to the Dasher app on the AppleTV. But I’ve been concerned for quite some time because this app never got the love or attention it deserved, I’m sure in large part because it required chattering through a web API to push the data. So as well as this worked, it was never really going to be broadly adopted by anyone but us propeller heads.

That means I knew the hammer was going to fall on this little gem at some point, and sure enough I got the email yesterday that Dasher was shutting down in May.

I rely on this dashboard enough that Dasher’s demise caused me to peel off for part of yesterday to find a replacement. I didn’t want to spend the next few weeks with some thought gnawing the back of my head, so I at least needed a plan.

And there are several good alternative dashboard apps out there, many of which with integrations to Analytics plus 100 other services I didn’t need. These are all great solutions, but they also all came with $10 per month fees, and missing integrations to oddball places like Staq and some of the other custom bits that I’d still have to jump through hoops to get fed anyway.

I’m already collecting all the data and generating a few simple charts in Pillow, so sending it somewhere that would ultimately show up on the AppleTV shouldn’t be hard. If there was even a simple version of Safari or another browser I could load on the AppleTV to bring up and auto-refresh a web page, I’d have a solution by kicking out some HTML or a even a full blown Vue.js app, but short of renewing my Apple developer account, reinstalling Xcode and side-loading tvOSBroswer, there isn’t much on the map.

That’s why I’m so glad I found AnyBoard. This is a great little app that does everything and more that Dasher did, but without putting a third party server in the middle.

When you setup Anyboard, you point it at a JSON file that you’ve made visible somewhere. That JSON file describes how one or more dashboards are laid out and also where to get the data. The data comes from other JSON files you identify using URLs in the configuration. By refreshing those JSON files with new data, the Anyboard app will have access to live data feeds from whatever sources you can cobble together. There’s also a pre-built setup for Nagios, but I didn’t play with it here.

Because all of the dashboard data is moving between the Apple TV and the local network, you can configure Anyboard to hit URLs on a local server, so your dashboard configuration and your actual data can stay inside the building. Also, you’re not dependent on a third party developer necessarily pulling the plug on the API that feeds the app. So I’m anticipating a very long relationship with Anyboard here.

Not that I think there’s anything to worry about. I traded a few emails with Ladislav at sféra, the Anyboard developer, and he was eager to help work through some odd things I was doing in my configuration and answer a few questions I had. These are the kinds of guys worth our support.

I was able to port my Dasher configuration over to Anyboard in about half a day, and the resulting dashboards look better than they ever have. Anyboard is free, there’s no premium version (which I would have gladly bought) or subscription fees (which I would have ruled out). It’s a solid app that does an important job and does it well. I can see a few minor areas that I hope Ladislav polishes up in future builds, but if you’re comfortable cranking out a few simple JSON files, I can definitely recommend Anyboard as an AppleTV dashboard solution without hesitation.

You can find out more about Anyboard at

Does Mark Cuban Want You to Die In Poverty?

A friend of mine asked me for the thoughts on this article and video…

What Mark Cuban Says will be the #1 Job Skill in 10 Years

The TL/DR is “creative thinking” therefore pursue a liberal arts degree, in lieu of other applied fields such as, pointedly, software engineering.

Which is probably suicide.

I’ve never quite understood the hero-worship over Mark Cuban. I get that he’s successful and made a lot of money in the tech bubble, but I think his key bit of acumen was getting diversified before the crash. After that, what? Basketball teams? Shark Tank? Okay. He probably doesn’t think much of me either, so whatever.

But, no, a liberal arts degree isn’t going to be any more valuable in 10 years than it is today. There’s nothing wrong with these skills for their own merits, but society and the economy is already telling us their value in an employment related context. And that value is not positively correlated in any respect to what college tuition costs.

Yes, in the coming years, we’ll have more data being produced, and more information being thrown at us. Just like if we compared today to ten years ago. But if anything, those societal changes have made knowing how to understand data, manipulate data, generate data even more of a valuable skill… The demand for software professionals (which is simply people who work with data) is vastly outstripping supply and will continue to do so for decades. The notion that because we have more data means we’ll need fewer data-literate professionals is, even on its surface, pure idiocy.

Meanwhile the job opportunities for liberal arts education majors seems often to come from service industry positions that have nothing to do with their degrees. These are exactly the places where automation is going to displace employment. And by, “displace” I mean totally erase. We are on the verge of possibly the biggest shift in employment demand since the invention of the steam engine, and hundreds of millions of people are going be underemployed due to technological innovation. If a graduate’s primary job skill is analyzing French literature, and they spent $100,000 and four years to get there, I’m going to go out on a limb and say they’re hosed.

There’s some sort of mythology around liberal arts degrees being more creative than applied fields. I don’t know where this thinking originated, but I’ll wager it didn’t come from anybody actually working on problems in any applied field. Problems in business and applied sciences not only require creative, critical thinking… They often have enormous consequences when creative solutions can’t be found on time and on budget.

Don’t believe me? Because, you know, Mark Cuban? Basketball? Maybe read these articles instead of listening to Mark…

Only 2% of employers are actively recruiting liberal arts degree holders. Compare that to the 27% that are recruiting engineering and computer information systems majors and 18% that are recruiting business majors.

It’s unclear whether liberal arts graduates are pursuing social service jobs because they’re more drawn to them, because they’re suited to a wider breadth of possible fields (which also contributes to a slow start salary-wise) or because that’s simply what’s left after all the other jobs are taken.

If you’re going to college, get a degree in building something. Business, “hard” science or engineering. These are problem solving degrees that require not just creative thinking, but creative problem solving. Those are the skills employers need.

Or, get a degree in, essentially, debt management. Because that’s probably the primary differentiable skill you’re going to acquire with an advanced liberal arts degree.

How Eclipse Killed GWT

I’ve had a love and hate relationship with Google Web Toolkit for a couple of years now. I built a modest size project using GWT back in 2010, which was definitely during a time of some GWT 2.x related growing pains, suffered through the uncertainty of Google abandoning GWT in favor of Dart, then watched the whole project get handed off as open source to for a long descent into obscurity.

I’m contemplating a larger project again, one with a significant web front-end. And GWT 3.0 is on the horizon, right? I went back to dear GWT to build a few small widgets, trying to see if maybe things were better now. Six widgets down this path, I’m throwing in the towel. And here’s why.


I mean, don’t get me wrong. GWT seems to have the smell of death all over it on it’s own. As far as I can tell there still isn’t any kind of proper date data type, even an emulation of the Java standard library classes. Google, the biological parent, has essentially kicked the kid to the curb. Looking at GWT questions on StackOverflow is like staring into room full of starving lonely people. If I had to get a question answered there or even in the hoary old googlegroups thread, I’d probably need antidepressants.

But GWT still worked, did basically what was advertised, and it was familiar.

Except. Eclipse.

I’ve got a long relationship with Eclipse as well, going way back to when it was an IBM product called “VisualAge for Java” that (I think) was originally written in SmallTalk of all things. I ran a good sized team building desktop front-end applications in Java in the early 2000’s. This one application has forever convinced me that nobody should be writing desktop applications of any complexity in any language running a VM. Simple typing in Eclipse is an exercise in torment. What do you imagine you do, every second of every minute, all day as a developer in an IDE? Typing. If your IDE sucks at that, nothing else matters. I find myself wondering what the people actually working on Eclipse itself think about it, but I suspect this is one of those situations where when you’re so close to the problem you don’t realize how bad it is (Hint: VERY bad). I’m sure somebody loves it. But I’m sure they’ve never actually worked with anything else. Including a manual typewriter, because even that would be less frustrating than writing code in Eclipse’s text editor.

And if Eclipse on its own wasn’t enough to make me want to torture small forest creatures, GWT on Eclipse was driving me really insane. The build process was slow, buggy and complicated. For projects that didn’t need a backend, I could still never get a configuration to launch without Jetty. Occasionally I’d screw up something in my project settings that would prevent me from being able to launch debug configurations, and I’d recourse to creating an entirely new GWT project and bring all the source into that. It was lunacy of the sort that made you beg for makefiles.

I explored other options… I could never get GWT working right in IntelliJ even if the text editor there was a little more sensible, and when it came time for widget #7, the despair was palpable and I realized I was finally, utterly, completely, done.

Widget #7 wound up coming to life with nothing more than a shell prompt, BBEditTranscrypt and the Developer Tools in Google Chrome. And I couldn’t be happier.

Goodbye old friend.

Increasing Performance with svgwrite

I’ve been working for quite some time on a Python project that generates a large-ish number of SVG files using Manfred Moitzi’s svgwrite package, which is pretty awesome.

However, I noticed that the runtime of this particular project was increasingly obnoxious, and only getting worse as the number of SVGs grew. So, out came cprofile, and sure enough, the bulk of the execution time was going through a tree of functions like check_svg_attribute_value, _check_svg_value and others seemingly related to validating the SVG during serialization.

The fix was pretty simple…

dwg = svgwrite.Drawing(size=(‘100px’,’100px’), debug=False)

Turns out that debug parameter is True by default, and setting it explicitly to False cut my execution time by almost 90%. Most of the remainder I’m sure is just I/O… (Mumbling as he ignores the rest of the profiler output.)