Tomi Hiltunen

Enthusiastic app developer in Google Go & HTML5

maanantai 16. joulukuuta 2013

How to land internship at a tech startup

In October 2013 I began looking for new opportunities abroad. Now, just two months later, I am choosing over multiple offers from world's finest startups. I recently read an article by Kippt founder Jori Lallo which inspired me to write my own article about my experiences. I'm going to focus more in-depth on finding and landing the actual internship position.

1. Set up your online profiles

Whether you're a hacker, a designer or a business guru, there are number of outstanding websites to present your works, gained publicity and achievements. These websites are often used by business executives and recruiters. That's why you should be there too.

LinkedIn has proved to be a valuable tool for job seekers. Used by recruiters across the globe. Has a fine job board as well. Be sure to ask your co-workers for recommendations.

Excellent for coders. This site is valuable for showcasing the quality of your code and the level of your activity on open source projects.

Perfect for designers. Both of these sites feature good tools for showcasing your visual designs.

2. Set up your personal website

People at small startups are often super busy. They might go through their email during lunch or on the bus. Therefore it is important to have just one compact website that has all the necessary details. And make it work well on mobile! This website is your personal ad which should provoke enough interest for people to take another more careful look on it.

You don't need much on your website. Here's a small framework for you:
  • Who are you and what are you like?
  • What are you good at? Mention awards and press coverage!
  • What have you worked on so far? Mention projects, responsibilities and companies.
  • Links to your online profiles: LinkedIn, Twitter, GitHub etc.
My personal website is at innovaniac.com. It features most of my public projects and the technologies I currently use most. This is the website that I link to the initial emails I send to companies I want to apply to. Before setting up my own website only half of the application lead to interviews. With the website all of my applications lead to interviews.

3. Finding the internship positions

Some of the companies have their internship positions listed on their careers page while some won't even publish their internship positions openly. There are number of job boards available for tech startups. Your local university might as well have an internship program which can connect you to your dream position. Internship programs can also make introductions on your behalf to companies you haven't even heard of before. You can also think about the kind of companies you want to work with and straight-up shoot them an email asking for an internship. Apply to multiple places at the same time. Worst that can happen here is that you will have a handful of positions to choose from.

Check out these websites:

Fantastic job board with YCombinator backed startups seeking to expand their team of professionals. This board updates regularly so be sure to check in every once in a while.

Thousands of startups seeking professionals. Use this site also as a professional online profile.

Internship positions from many cities across the United States.

4. Prepare for the interviews

So far most Silicon Valley startups have interviewed me in multiple steps ranging from Skype interviews to coding practices to do on my own time. Skype and Google Hangouts were often used for the calls so it is a good idea to set up your accounts there and to get familiar with the apps.

Be prepared to code small exercises during the interview calls. Interviewers will likely test your knowledge on certain technologies, your logic thinking and your knowledge on computer science related topics. Therefore it's good to read through articles about computational problems and algorithms and calculating basic probabilities. There's also tons of resources online for prepping before the interviews. If you are still studying you can take on in-depth courses on the topics at your university. Understanding these things is beneficial not only for the interviews but also for your work.

Take a good look on the company you are applying to. Familiarize yourself on the product and business model of the company. Think about what you can bring to the company and have a list of questions ready for them about what you would like to know about them.

Your first interviews might not go all that smoothly. However, in time you will gain confidence and have your thoughts more organized. Just keep practicing!

5. Finally

Good luck! Don't be worried about getting a few "no" in return. There will always be companies that won't find a strong match with your past experience and the companies might have very specific needs. The earlier you start, the closer you are to your dream position in the industry's most promising startups.

For recap:

  • Set your profiles on LinkedIn, GitHub, Twitter, Angel.co, Dribbble.
  • Set up or update your personal website and PDF version of your CV.
  • Add links to your profiles, CV and website to your profiles, CV and website.
  • Be in touch with your local university and look-up for internship opportunities on the job boards.
  • Prepare, prepare & prepare. (but don't stress too much!)
  • Remain positive!

torstai 25. heinäkuuta 2013

Stance.io pilot is out.

What started out of frustration towards the regular discussion boards has been turned into a shiny new app. Stance.io is the simplest debating platform online. It's a fantastic tool for getting people engaged in discussion. Read on for the whole story of Stance.io.


Background

Browsing through lengthy bulletin board threads has frustrated me for some time now. The discussions are often lengthy, fussy and branch all over. In the end there's no easy way of telling what people really think. All you have is hundreds of pages full of replies of replies of replies.

Anatomy of the debates of Stance.io

Debates on Stance.io consist of the topic and the two opposite camps. In the picture above you can see the topic being "Should Vimention.com allow anonymous posting?". The opposing camps on this one are "yes" and "no". The camps can be pretty much anything: you can choose from the few pre-set ones or create your own, like "iPhone" vs. "Lumia".

Both camps have arguments which represent people's thoughts on the topic. They should answer the question "why" when a user is rooting for the certain camp. Each argument should hold only one answer for the question "why". Users can choose to second any of the existing arguments or create new ones, on both sides if they will.

Participants for each debate can be found from Twitter, mailing lists, IRC channels and websites. Just by sharing the link to your debate you'll reach firstly your own followers. As they participate, they are encouraged to share the link to their Twitter followers continuing the chain further and further.

Many benefits of using Stance.io

  • Engage people to discuss hot topics.
  • Spread awareness.
  • Harness the power of people's social networks to reach more people.
  • See a bird's-eye view on people's thoughts on the topic.
  • Use the results for decision making.

Try the pilot

As already mentioned in the first paragraph, the pilot is out! You can start your first debates now at Stance.io. The app will continue improving and your feedback will be worth more than gold to me.

Stay in touch with me through LinkedIn: fi.linkedin.com/in/tomihiltunen/

maanantai 18. maaliskuuta 2013

Heads up with GAE blobstore!

The problem

I recently ran into problems with Google App Engine blobstore. My HTML5 page had a multipart form for creating content on my app. The form included various inputs for name, coordinates and also a file input for a photo. The form was posted to the blobstore generated upload URL... and it crashed.

After experimenting a bit with my code I narrowed down the cause to be with blobstore's method ParseUploads(). The problem exists only when at least one of the text inputs contained a value with non-ascii characters such as the scandinavian "ö".

I ran a search on Google App Engine's issue tracker on "blobstore go" and found out that it is an actual reported bug in the environment.

The same problem does not exist when there is no non-ascii characters in the inputs. The problem does not exist either with regular form uploads (without file inputs) read with r.FormValue("...").

The solution (for now)

I went around the problem by separating the photo uploads from the other data. My form now does not include a file input. I replaced that with a button connected to the Plupload JavaScript plugin. The upload is handled by a separate handler and the form posts only the text inputs to another handler.

Now my content can have the photos added and names/descriptions can contain non-ascii characters. This satisfies my need for now!

Using URL slugs

What are slugs in URLs?

Slugs are a part of URLs that make the URLs more human-readable and search engine friendly. A URL with a slug gives the viewer a better idea of what is behind the link before even clicking on it.

Lets say that you have an article named "Tower of London". The unique URL for this article without the slug could be:

http://example.com/articles/21

Now with a slug generated from the title of the article:

http://example.com/articles/21/tower_of_london

Seems a lot more informative? Do you find the topic more obvious in the last example?

Essentials in generating a slug

In this article I will discuss just the idea of generating a slug from the title of your content. It is also suggested that other important keywords should be included in the slug for further SEO friendliness. I'm happy using just the title without extra keywords, but feel free to include them in your own app.

The key is that slugs should consist only of characters that do not need to be URL encoded.

There's different variations for generating slugs. I find it more visually pleasing to replace all white-space characters with underscores. Some replace other punctuations with a dash or underscore but I rather leave them out of the slug all together.

How I do it

Here's an algorithm used by me for slugging the titles:
  • Check for all non URL-friendly characters with reg-exp [^A-Za-z0-9\s-_]
    • Non-friendly character was found!
    • See if it can be transliterated
      • Yes?
        • Replace with the latin counter part
      • No?
        • Replace with an empty string
  • Trim all the leading and trailing white-space characters
  • Replace all 1...* characters long white-spaces with an underscore. \s+
  • Convert the string to lower-case
  • Done!

In Go

import (
    "strings"
    "regexp"
)

/*
 *  Dictionary of accented characters and their transliterations.
 *  Don't consider this dictionary complete!
 */
var dictionary = map[string]string {
    "Š": "S",
    "š": "s",
    "Đ": "Dj",
    "đ": "dj",
    "Ž": "Z",
    "ž": "z",
    "Č": "C",
    "č": "c",
    "Ć": "C",
    "ć": "c",
    "À": "A",
    "Á": "A",
    "Â": "A",
    "Ã": "A",
    "Ä": "A",
    "Å": "A",
    "Æ": "A",
    "Ç": "C",
    "È": "E",
    "É": "E",
    "Ê": "E",
    "Ë": "E",
    "Ì": "I",
    "Í": "I",
    "Î": "I",
    "Ï": "I",
    "Ñ": "N",
    "Ò": "O",
    "Ó": "O",
    "Ô": "O",
    "Õ": "O",
    "Ö": "O",
    "Ø": "O",
    "Ù": "U",
    "Ú": "U",
    "Û": "U",
    "Ü": "U",
    "Ý": "Y",
    "Þ": "B",
    "ß": "Ss",
    "à": "a",
    "á": "a",
    "â": "a",
    "ã": "a",
    "ä": "a",
    "å": "a",
    "æ": "a",
    "ç": "c",
    "è": "e",
    "é": "e",
    "ê": "e",
    "ë": "e",
    "ì": "i",
    "í": "i",
    "î": "i",
    "ï": "i",
    "ð": "o",
    "ñ": "n",
    "ò": "o",
    "ó": "o",
    "ô": "o",
    "õ": "o",
    "ö": "o",
    "ø": "o",
    "ù": "u",
    "ú": "u",
    "û": "u",
    "ý": "y",
    "þ": "b",
    "ÿ": "y",
    "Ŕ": "R",
    "ŕ": "r",
}

/*
 * Creates a lower-case trimmed string with underscores for white-spaces.
 *
 *      - Converts to lower case.
 *      - Trims the leading/trailing white spaces.
 *      - Converts applicable accented caharcters to non-accented and removes invalid ones.
 *      - Converts leftover white-spaces to underscores regardles of type.
 */
func Slug(original string) (edited string) {
    // Remove invalid characters
    re, _ := regexp.Compile(`[^A-Za-z0-9\s-_]`)
    edited = re.ReplaceAllStringFunc(original, convertAccent)
    // Trim leading and trailing white-space
    edited = strings.TrimSpace(edited)
    // Convert all white-spaces to underscores
    re, _ = regexp.Compile(`\s+`)
    edited = re.ReplaceAllString(edited, "_")
    // All done!
    return strings.ToLower(edited)
}

/*
 * Converts accented characters if found from the dictionary.
 * Otherwise will replace the character with an empty string.
 */
func convertAccent(found string) (string) {
    if newValue, ok := dictionary[found]; ok {
        return newValue
    }
    return ""
}

Optimizing images on GAE blobstore using Go

So your app allows users to post image files to the App Engine blobstore?

About App Engine blobstore

Blobstore is a service provided by Google App Engine for storing files or "blobs". The blobstore provides an easy method for allowing users upload files to your app. On this article I will focus solely on image files and how to optimize them after they are uploaded to the blobstore.

Reasons for optimizing the images

Optimizing the images may mean scaling down the image dimensions and changing the compression rate. This affects the image's file size. Smaller file size means lower storage costs and shorter download times. Shorter download times make happy users.

How to do it

Please note: I expect that you already know the basics of using blobstore for uploading files!

Step 1) Download my image optimizer package from GitHub

Step 2) Import the package to your project

import "github.com/tomihiltunen/gae-go-image-optimizer"

Step 3) Where you would normally call "blobstore.ParseUploads()"

// Create settings for the optimization.
optimizerOptions := optimg.NewCompressionOptions(r) // r *http.Request

// Set maximum image dimension
// 0 = no change (default)
optimizerOptions.Size = 1600

// Set image quality
// 100 = no compression (defaults to 75)
optimizerOptions.Quality = 75

// Call the ParseBlobs method.
// Return values are similar to blobstore.ParseUploads().
blobs, other, err := optimg.ParseBlobs(optimizerOptions)

// Do the rest
...

Considerations

Reading and writing to the blobstore is a rather lengthy operation. Optimizing images immediately during upload process will make your app appear slow to users. In this case the image would be first uploaded to the blobstore, the request redirected to your app's handler, image read from the blobstore, optimized and finally, the new image is written to the blobstore and the original one deleted. As you know, responsiveness of your app affects directly the experience of using your app.

One option for eliminating the slow response times is to have a task queue for the optimization process. When the blob is uploaded your handler will just add the object's and blob's keys to the task queue. When the queue has finished the optimization it will simply replace the blobkey to the objects properties. The old blob can be used as the image until the task queue has finished the optimization.

Optimizing on the client-side

If you do not need server-side optimization, you can use plugin like Plupload which has the options for optimizing image dimensions and compression rate before uploading the image to the server. Benefits of this approach is that the upload time is shorter and you don't have to use your server resources for the optimization process as you can make the client do the heavy lifting.