Wednesday, August 20, 2014

An Interview Question

Here's a great interview question, well, assuming that you're interviewing a software engineer.

What is the easiest way to determine if a given string is the rotation of another string?

First, I guess there could be some question of what rotation of a string even is. If you were to take letters off the end of the string and stick them on the beginning one at a time, you would be making a rotation of the string. For example, the following are all rotations of the string "obfuscate"
ateobfusc
fuscateob
scateobfu
eobfuscat
There are lots of ways you could try to determine if one string is a rotation of another. You could easily rule out some strings by checking to make sure the lengths are the same first. Then you could maybe start at the first character and attempt a character-by-character comparison and move your pointer back to the front if you reach the end...or some other complicated algorithm.

But there's a really easy way to tell if a string is a rotation of another string. Engineers who value the simplest way to solve a problem will do it this way.

Stick one of the strings together with a copy of itself and then see if the other string appears inside that new string. Like this, using the examples above:
ateobfuscateobfusc
fuscateobfuscateob
scateobfuscateobfu
eobfuscateobfuscat
You still need a sanity check for length, because you can find "ob" inside of "fuscateobfuscateob" but that doesn't make it a rotation.

Here it is as a JavaScript function.

function isRotation(a, b) {
    return (a.length === b.length) && ((a + a).indexOf(b) !== -1)
}

That's all there is to it. You can do it in one line. I think it's a good question.

Amphibian.com comic for August 20, 2014

Monday, August 18, 2014

CSS Speech Bubbles

I'd like to take a moment to talk about my CSS speech bubbles. My comic uses CSS rules for making <p> tags render as speech bubbles for the frogs. If you view the page source, you'll see that there are no tables or images involved - just pure CSS.

There are many examples out there on the Internet about how to achieve this effect. I based mine on this one: Bubbler - CSS Speech Bubble Generator. Of all the examples I saw, I just like this one the best.

There was one minor issue I came across though. The frogs are in different places in each cell, but because the bubble stems are positioned using the CSS psuedo-elements ::before and ::after, the values that determine the stem location cannot be set via JavaScript.

I decided to solve this issue by removing the stem position from the .bubble::before and .bubble::after classes in the CSS, and creating another set of classes just for the stem positions.

I called these new classes bubble25, bubble50, and bubble75. You can probably guess that the number represents the percentage used for the left attribute in the stem position.

So now, if I want to create a speech bubble with the stem on the right side (75% of the bubble width) I create a tag like this:

<p class="bubble bubble75">here is some content for the bubble</p>

While I can't position the stems at every possible position this way, having the 3 different options has proven sufficient so far. This is a good example of a design trade-off. I could create a hundred different classes and never use 90% of them, or I could create just 3 and get a good-enough position 99% of the time.

Here's a snippet of my CSS that shows more clearly what I'm talking about.

.bubble {
 position: absolute;
 width: 44%;
 padding: 2%;
 text-align: center;
 background: #FFFFFF;
 border: #000000 solid 3px;
 font-family: 'Sniglet', sans-serif;
 line-height: initial;
 color: #000000;
 box-sizing: content-box;
 -moz-box-sizing: content-box;
 -webkit-box-sizing: content-box;
 -webkit-border-radius: 20px;
 -moz-border-radius: 20px;
 border-radius: 20px;
}

.bubble:after {
 content: '';
 position: absolute;
 border-style: solid;
 border-color: #FFFFFF transparent;
 display: none;
 width: 0;
 z-index: 1;
 box-sizing: initial;
 -moz-box-sizing: initial;
 -webkit-box-sizing: initial;
 border-width: 21px 7px 0;
 bottom: -21px;
 margin-left: -12px;
}

.bubble:before {
 content: '';
 position: absolute;
 border-style: solid;
 border-color: #000000 transparent;
 display: none;
 width: 0;
 z-index: 0;
 box-sizing: initial;
 -moz-box-sizing: initial;
 -webkit-box-sizing: initial;
 border-width: 25px 9px 0;
 bottom: -27px;
 margin-left: -14px;
}


.bubble25:after {
 left: 25%;
 display: block;
}

.bubble25:before {
 left: 25%;
 display: block;
}

.bubble50:after {
 display: block;
 left: 50%;
}

.bubble50:before {
 display: block;
 left: 50%;
}

.bubble75:after {
 display: block;
 left: 75%;
}

.bubble75:before {
 display: block;
 left: 75%;
}

Make sure you check out John Clifford's Bubbler to make your own bubble CSS. Speech bubbles can be a welcome addition to any web site.

Amphibian.com comic for August 18, 2014

Friday, August 15, 2014

Bad Requirements Create Bad Systems

One of the most important lessons I've learned as a software engineer is the importance of good requirements. Requirements definition is absolutely the most important part of a software development project. You can have the best engineers in the world but if your requirements are terrible your system will be terrible.

You might find other lists on the Internet of things that make requirements "good." I'm going to give you a list of what makes requirements bad.

Don't ever write requirements like these...

  • Bad Requirements are Ambiguous. If you tell me, "The system should be able to be dropped from a height of 8 feet onto a wooden floor without breaking it," I will build you a system that will not break the floor when it falls onto it. The system, however, will shatter into a thousand pieces.
  • Bad Requirements are Subjective. If you tell me, "The system should use pretty colors," I am not going to build your system. If you tell me, "The system should be fast," I am not going to build your system.
  • Bad Requirements are not Testable. If you tell me, "The system should never crash on a Saturday afternoon," I'm going to ask you to watch it every Saturday to make sure it doesn't.

All of the examples I just gave could be rewritten to be good requirements. It just takes a little more thought.
  • The system shall not break when dropped from a height of 8 or more feet onto a surface with a Brinell hardness of 1.6 HBS 10/100 or greater.
  • The system should use only pink and purple as display colors for text.
  • The system should process inputs at a rate of 3 per second.
  • The system should have a mean time between failures of 87 days.
Remember, you can't build the right system from the wrong requirements.


Amphibian.com comic for August 15, 2014

Wednesday, August 13, 2014

Just How Mobile?

I'm sure you're familiar with the Native App vs. HTML5 debate. There's a lot to be said in that one. As a developer, I would much rather make a single HTML5 web app instead of native apps for both iOS and Android.

However, I know that such a course of action would very likely be a bad idea. Don't get me wrong, I love HTML5. But I've seen very few cases where an HTML5 solution is on par with a native app solution. There are some exceptions, and it very much depends on what your particular app is doing.

But HTML5 is getting better. I fully except that someday mobile apps will do things in mobile browsers that are quite impressive. That day is not today.

One place in particular that shows the mobile web's shortcomings is in games. There are many examples of good HTML5 games that are playable on the desktop browsers, but I have trouble finding good ones that play well on mobile browsers. Even very simple games just get awkward on mobile devices.

So if you decide to go native, you'll have to make apps for both iOS and Android. But what if you decide that your particular app is simple enough that you can do it in HTML5? You might want to consider making two web apps, one for desktop and one for mobile. Oh, "that's silly" you say. Everyone knows that you just use responsive design and make one web app.

Or do you?

I read this article, in which the author makes the case that your mobile use cases might be so different from your desktop use cases that it makes more sense to make a second web application just for mobile users. I'm certainly a big fan of understanding your requirements (and use cases) well before developing your software.

Here's the article. Give it a read.

Is responsive design killing mobile?

Think about it.

Amphibian.com comic for August 13, 2014

Monday, August 11, 2014

Gopher, Anyone?

Does anyone remember Gopher?

Anyone?

I guess probably not. There used to be this document access protocol called Gopher that people used instead of the Hypertext Transfer Protocol (a.k.a. HTTP) that we know and love today. Well, maybe "instead of" isn't the right phrase. We used it alongside HTTP. It was like this other kind of thing you could do with the Internet. It's mostly forgotten now. We almost exclusively use HTTP to access documents over the Internet these days.

It's worth talking about because we often think of the Web (the entity created by HTTP) and the Internet as the same thing. The proliferation of ReST Web Services today as a means of opening up almost any kind of service imaginable over HTTP is increasing the confusion. Maybe because I used to do networking over a 2400 bps modem on a Tandy 1000 computer I don't see the Internet that way.

Tandy1000HX tweaked.jpg
"Tandy 1000HX tweaked"
The Internet is a wide area network of computers and computer-like devices using TCP/IP. HTTP is a protocol on top of that, just like Gopher, FTP, SSH, and a thousand others. Maybe someday HTTP won't be so dominant and some other protocol will find more widespread appeal.

And here's another thought. No one probably remembers using Lynx either. I used that to browse the web in college. Good times. Good times...

I sure could gopher a giant chocolate chip cookie right now.

Amphibian.com comic for August 11, 2014


Image Credits:
"Tandy1000HX tweaked" by Jesster79 (Non-creditable tweaks by Ubcule) - This file was derived from: Tandy1000HX.jpg . Licensed under CC BY-SA 3.0 via Wikimedia Commons.

Friday, August 8, 2014

JavaScript Colors: RGB to HEX

In my web comic editor, I needed to be able to both read and set the background color values on HTML elements. Since I've been working with colors as hex codes since, umm, forever, I thought it would be good to work with the colors that way. But to my dismay, I found that you can set the color of an element using a hex string (e.g. #ff0000), an RGB string (e.g. rgb(255,0,0)), or an HSL string (e.g. hsl(360,100%,50%)) but when you read the value it is always in RGB format. Here's an example:

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Color Test</title>
</head>

<body>

<div id="hextest" style="background-color: #FF0000; width: 100px; height: 100px;"></div>

<div id="rgbtest" style="background-color: rgb(0,255,0); width: 100px; height: 100px;"></div>

<div id="hsltest" style="background-color: hsl(240,100%,50%); width: 100px; height: 100px;"></div>

</body>

<script>

var a = document.getElementById('hextest').style.backgroundColor;
var b = document.getElementById('rgbtest').style.backgroundColor;
var c = document.getElementById('hsltest').style.backgroundColor;

console.log(a);
console.log(b);
console.log(c);

</script>

</html>


Maybe you've had this problem yourself. Fortunately, I found a handy JavaScript function that will convert RGB strings back into hex. It is a very compact and interesting function. Let's take a look at it.

function rgb2hex(rgb) {
 
 function hex(x) {
  return ("0" + parseInt(x).toString(16)).slice(-2);
 }
 var r = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
 var h = '#' + hex(r[1]) + hex(r[2]) + hex(r[3]);
 return h.toUpperCase();

}

There's a lot of good JavaScript to learn about here. First, you may notice that the function has another function declared inside of it. The inner function, hex, is essentially private to the rgb2hex function the same as a variable definition would be. It's like an anonymous inner function that isn't so anonymous. So what's the hex function doing?

It assumes, first of all, that you give it a String representation of an integer. Like "35" or something. The parseInt() function turns that into a JavaScript Number so that you can call toString(16) on it. What does that do, you ask? The parameter "16" is the radix. Without going into too much detail about what a radix is, just know that using radix 2 will give you the number's value in binary, radix 8 will give you the number's value in octal, and radix 16 gives you the number's value in hexadecimal. So calling toString(16) on a Number object with value 28 will give you the String "1c". But what's up with the fact that "0" is prepended to that value and then the whole thing is sliced with a slice parameter of -2? That's just a simple way of making sure that the return value of the function is always 2 characters and is left-padded with zeros. If the input to the function is less than 16, then the toString(16) call will return a String that is only 1 character long. But if the input is greater than 15, the result will be at least 2 characters. So if we always put a "0" in front and then just return the last two characters of the String, it will ensure that the hex value is 0-padded. Using slice() with a negative value as the parameter is a trick that returns the characters from the end of the String instead of the beginning. For example, "whatnot".slice(-3) returns "not".

Wow, that's quite a lot going on in that one line of JavaScript. The rest of the rgb2hex function isn't quite so tricky. Line 6 just uses a regular expression to find the 3 numbers in the RGB string. For example, with an input String of "rgb(100,200,150)" the value for r will be an array containing the values "100", "200", and "150". Line 7 just uses those three values as parameters to the hex function and sticks the "#" on the front. The last line returns the complete value in all upper case, since I like #FFFFFF better than #ffffff.

Anyway, I hope this function is as helpful to you as it was to me.

Amphibian.com comic for August 8, 2014



Wednesday, August 6, 2014

Your Uncoolness is the Coolest

When I was in fourth grade, my vision had deteriorated to the point that I could not adequately function in the classroom. I suppose it was inevitable, since heredity had given me a disadvantage in the vision department. But when I was 10 years old, having to wear glasses was terrible. They weren't anything close to the stylish frames I own today. They were thick, dark, plastic frames that looked terrible by today's standards. Or did they...

Now that we've delved into the pain of my childhood, let's talk about my oldest daughter. At 14, she still had perfect vision but chose to start wearing fake glasses just for the look. And by look, of course I mean style. I wear glasses for the look too, but in my case that means so that I can actually look at things (I can't wear contacts or have eye surgery, but that's a story for another day). Back to my daughter...the glasses she wants to wear are the dark plastic type frames that I once despised. What happened?

I won't embarrass her by posting her picture here, but she actually looks really good in the glasses. She even had her school picture taken wearing them last year. When I was her age, all I dreamed about was being able to get my picture taken without my glasses.

Here's my theory on what has happened. Somehow, over time, kids bought the notion that being yourself and being different were good things. It's cool to be different. So now, everyone wants to be different. And they become more different by assuming the qualities that have historically caused other children to be labeled as different. It's some kind of coolness paradox. If you do the things that make you uncool you achieve coolness.

Personally, I think they're missing the point. You should be the best you that you can be. If you wear glasses, great. Pick some that work with your face and be confident and happy. If you love to write software and be alone in your room, great. Write some really fun apps for phones. If you love to play soccer, great. Go run and kick things and whatnot. Maybe you don't know what makes you different and special yet. That's fine too, just try different activities and you'll discover something. Don't rule anything out, unless of course it's illegal and/or dangerous. I found that same year I got my glasses that I loved programming. I did it every day from then on and didn't really care if I was cool or not.

Remember, you are different enough just by the fact that you are yourself. Unless, of course, you are an identical twin.

Amphibian.com comic for August 6, 2014