├── .gitignore
├── assets
└── hacker-guide-to-setting-up-your-mac
│ └── terminal.png
├── the-birth-of-bluu.md
├── readme.md
├── an-indian-beginning.md
├── bluu-testflight-crashlytics-hockeyapp.md
├── bluu-app-store-submission.md
├── bluu-the-rules.md
├── say-hello-to-gittask.md
├── principles-of-an-ideal-database-client.md
└── hacker-guide-to-setting-up-your-mac.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/assets/hacker-guide-to-setting-up-your-mac/terminal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lapwinglabs/blog/HEAD/assets/hacker-guide-to-setting-up-your-mac/terminal.png
--------------------------------------------------------------------------------
/the-birth-of-bluu.md:
--------------------------------------------------------------------------------
1 | ```
2 | title: The Birth of Bluu
3 | featured: https://i.cloudup.com/kvPq_1dMQm.jpg
4 | tags: bluu, app, design, game, iOS, Android
5 | date: August 1, 2014
6 | slug: the-birth-of-bluu
7 | excerpt: We wanted to make a app that could be usable by the end of a weekend.
8 | author: Andy Pai
9 | ```
10 |
11 | We wanted to make an app that could be usable by the end of the weekend. The hope was to get an app published to the Apple app store quickly to start learning the intricacies of beta deployment and testing, app store submission, and post-release product marketing.
12 |
13 | After discussing ideas ranging from utility to fantasy sports apps, we decided to work on a simple game. We figured since games get downloaded 5x-10x more than any other category, it gave us the greatest chance of getting some adoption. After doing some research on other popular games like 2048 and Timberman, we wanted the game to have the following characteristics:
14 |
15 | 1. Easy to play
16 | 2. Hard to master
17 | 3. Simple graphics
18 |
19 | We thought the flicking and combing of tiles in 2048 made for a pretty awesome experience so we wondered if matching colors instead was numbers could provide similar satisfaction. Having taken a bit of psychology in high-school and college, we remembered that it's harder to read words if they're colored differently than that what they mean.
20 |
21 | The first mock-ups:
22 |
23 | 
24 |
25 | The second mock-up:
26 |
27 |
28 |
29 | 
30 |
31 |
32 | 
33 |
34 |
35 | 
36 |
37 |
38 |
39 |
40 | Final Design:
41 |
42 | 
43 | 
44 | 
45 |
46 |
47 | In [Bluu: The Rules](http://lapwinglabs.com/blog/bluu-the-rules) we describe our next steps in designing the rule logic.
48 |
49 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Blog
2 |
3 | [Principles of an Ideal Database Client](principles-of-an-ideal-database-client.md)
4 |
5 | ```
6 | title: Principles of an Ideal Database Client
7 | tags: [database, client, open source, development]
8 | date: January 25, 2015
9 | slug: principles-of-an-ideal-database-client
10 | excerpt: Discussing the principles that go into an ideal database client
11 | author: Matthew Mueller
12 | ```
13 |
14 | [Say Hello to Gittask](say-hello-to-gittask.md)
15 |
16 | ```
17 | title: Say Hello to Gittask
18 | tags: [gittask, site, open source, development]
19 | date: January 16, 2015
20 | slug: say-hello-to-gittask
21 | excerpt: Introducing a new marketplace for coding tasks
22 | author: Lapwing Labs
23 | draft: true
24 | ```
25 |
26 | [Hacker's Guide to Setting up your Mac](hacker-guide-to-setting-up-your-mac.md)
27 |
28 | ```
29 | title: Hacker's Guide to Setting up your Mac
30 | tags: [mac, hacker, bash]
31 | date: September 30, 2014
32 | slug: hacker-guide-to-setting-up-your-mac
33 | excerpt: Setting up your Mac the Hacker way
34 | author: Matthew Mueller
35 | ```
36 |
37 | [Bluu: App Store Submission](bluu-app-store-submission.md)
38 |
39 | ```
40 | title: Bluu: App Store Submission
41 | tags: Bluu, app, app store submission, privacy policy, D-U-N-S Number, iubenda, screenshots
42 | date: September 15, 2014
43 | slug: bluu-app-store-submission
44 | excerpt: Delays during Apple App Store submission.
45 | author: Andy Pai
46 | ```
47 |
48 | [Bluu: TestFlight vs. Crashlytics vs. HockeyApp](bluu-testflight-crashlytics-hockeyapp.md)
49 |
50 | ```
51 | title: Bluu: TestFlight vs. Crashlytics vs. HockeyApp
52 | tags: TestFlight, Crashlytics, Hockey App, beta testing, crash reporting, bluu
53 | date: August 3, 2014
54 | slug: bluu-testflight-crashlytics-hockeyapp
55 | excerpt: We're happy to be using TestFlight for seamless beta distribution services and Crashlytics for its awesome crash reporting.
56 | author: Andy Pai
57 | ```
58 |
59 | [The Birth of Bluu](the-birth-of-bluu.md)
60 |
61 | ```
62 | title: The Birth of Bluu
63 | featured: https://i.cloudup.com/bLfc2mYZpd.png
64 | tags: bluu, app, design, game, iOS, Android
65 | date: August 1, 2014
66 | slug: the-birth-of-bluu
67 | excerpt: We wanted to make a app that could be usable by the end of a weekend.
68 | author: Andy Pai
69 | ```
70 |
71 | [Bluu: Designing the Rule Structure](bluu-designing-the-rule-structure.md)
72 |
73 | ```
74 | title: Bluu: The Rules
75 | tags: bluu, app, design, game
76 | date: August 1, 2014
77 | slug: bluu-the-rules
78 | excerpt: Creating the rule logic behind Bluu.
79 | author: Andy Pai
80 | ```
81 |
82 | [An Indian Beginning](an-indian-beginning.md)
83 |
84 | ```
85 | title: An Indian Beginning
86 | tags: India, coworking space, Bangalore, Cobalt Bangalore, Taj Lands End
87 | date: July 21, 2014
88 | slug: an-indian-beginning
89 | excerpt: Tales from our India trip.
90 | author: Andy Pai
91 | ```
92 |
--------------------------------------------------------------------------------
/an-indian-beginning.md:
--------------------------------------------------------------------------------
1 | ```
2 | title: An Indian Beginning
3 | tags: India, coworking space, Bangalore, Cobalt Bangalore, Taj Lands End
4 | date: July 21, 2014
5 | slug: an-indian-beginning
6 | excerpt: Tales from our India trip.
7 | author: Andy Pai
8 | ```
9 |
10 | Since Brian was still finishing up work at GE, Matt and I along with Matt Hogan, our co-founder for [Levered Returns](http://www.leveredreturns.com), took a trip to Bangalore, India to start working on the Levered Returns and [Duo](http://duojs.org/) concepts. We figured it would be less distracting and give us a chance to meet some interesting people.
11 |
12 | Below are some highlights from the trip.
13 |
14 | #### The Taj Welcome
15 |
16 | If you have a few hundred dollars in your pocket, I recommend staying at one of the five-star hotels in India and live like a King for couple days. Pictured below is the welcome you get at check-in.
17 | 
18 |
19 | #### Cricket!
20 |
21 | By far India's biggest sport, it was fun playing some street ball. No, it’s not Indian baseball.
22 | 
23 |
24 | #### Rickshaw. 150 Rupees?! 100 Rupees Maximum
25 |
26 | Our primary mode of transport around was the Rickshaw. No, not the ones where [someone cycles you around](http://en.wikipedia.org/wiki/Rickshaws_in_the_United_States). The Indian kind! I don't think they’re made for three dudes our size though. Also, it's pretty hilarious negotiating with drivers, especially when they see foreigners.
27 | 
28 |
29 | #### Cobalt
30 |
31 | Before leaving, we were planning to work at [Jaaga](http://jaaga.in/). When we showed up, we realized the co-working space had moved into someone's apartment instead. After a day of rickshawing around Bangalore, picking each other up, and soul-searching, we finally end the search at [Cobalt](http://www.cobaltblr.com/). If you're looking for a Western style co-working space with nice people, this is it!
32 |
33 | 
34 |
35 | #### $2 Haircut and Shave
36 |
37 | An awesome perk of living in India is the super cheap haircuts and shave. $2 will buy you a haircut, head massage, and shave. The Indian shaving blade can handle even the toughest hairs like Mueller's hipster 'stache.
38 |
39 | 
40 |
41 | #### Random Street Dance Party
42 |
43 | We heard a bunch of noise outside our hotel room, so we stepped out to analyze the commotion. Soon we ended up dancing and waving flags in the middle of the street. Still not sure what we were celebrating...
44 |
45 |
46 |
47 | If you're thinking about taking your start-up to Bangalore, feel free to e-mail us. We would be happy to give you some tips and share some hard learned lessons.
48 |
--------------------------------------------------------------------------------
/bluu-testflight-crashlytics-hockeyapp.md:
--------------------------------------------------------------------------------
1 | ```
2 | title: Bluu: TestFlight vs. Crashlytics vs. HockeyApp
3 | tags: TestFlight, Crashlytics, Hockey App, beta testing, crash reporting, Bluu
4 | date: August 3, 2014
5 | slug: bluu-testflight-crashlytics-hockeyapp
6 | excerpt: We're happy to be using TestFlight for seamless beta distribution services and Crashlytics for its awesome crash reporting.
7 | author: Andy Pai
8 | ```
9 |
10 | At the end of the weekend, we wanted to get Bluu into some hands to start getting feedback. Deployment was surprisingly far more complicated than we had envisioned.
11 |
12 | We had to reach out to our friends and family to get their UDIDs, Apple's unique identifier for iPhones. As expected, none of them had ever heard of a UDID. Some started worrying we were trying to send them some type of phone virus. After some explaining, we had to get them to either:
13 |
14 | 1. Download an app that gave them their UDID or
15 | 2. Plug in their iPhones into their computer to get it for us.
16 |
17 | But the pain didn't stop there. Once we received their UDID's, we had to create a build including the collected UDID's and send it to them for installation via e-mail. Once they received the package, they had to reconnect their phone to iTunes and install the app. Even after these steps, sometimes the app wouldn't install! We needed a better beta testing experience, or we risked losing all our friends.
18 |
19 | The three services we came across that promised to improve our workflow were TestFlight, Crashlytics and HockeyApp. HockeyApp charges $10 / month even for their cheapest plan, so they were out.
20 |
21 | After some research on TestFlight and Crashlytics, our first impressions were:
22 |
23 | ## TestFlight
24 |
25 | - Free
26 | - Collects UDID's by downloading an app on the user's phone. They use the same app to deliver the app for download. No cords necessary. Hallelujah!
27 | - Recently acquired by Apple, so should work seamlessly for iOS stuff. Unfortunately, this also means that they won't support Android anymore, but it did look like we could get crash reporting and detailed usage statistics by integrating with their SDK.
28 |
29 | ## Crashlytics
30 |
31 | - Free? Seriously? Even the Enterprise services? Is this a scam?... Oh, they got acquired by Twitter. Hopefully Twitter's deep pockets can probably afford to keep it around and free, at least for a while :)
32 | - Offers beta distribution for iOS and Android
33 | - Crash reporting seems more visual and intuitive than TestFlight
34 |
35 | After trying out Crashlytics and TestFlight, we decided to use both. TestFlight no longer allows downloads of their SDK, so you don't get session tracking, crash logging, and in-app updates. While Crashlytics offers a complete solution including Beta distribution, TestFlight's beta distribution is far more seamless and less buggy. Having to use Crashlytics for crash reporting isn't all a loss though since it's reporting format is superior to TestFlight's format. Crashlytics presents all data with amazing visuals making it very easy to interpret and act accordingly.
36 |
37 | So, we're happy to be using TestFlight for seamless beta distribution services and Crashlytics for its awesome crash reporting.
38 |
--------------------------------------------------------------------------------
/bluu-app-store-submission.md:
--------------------------------------------------------------------------------
1 | ```
2 | title: Bluu: App Store Submission
3 | tags: Bluu, app, app store submission, privacy policy, D-U-N-S Number, iubenda, screenshots
4 | date: September 15, 2014
5 | slug: bluu-app-store-submission
6 | excerpt: Delays during Apple App Store submission.
7 | author: Andy Pai
8 | ```
9 |
10 | ### Bluu: App Store Submission
11 |
12 | During the Apple App Store submission process, we were delayed by these three unforeseen requirements:
13 |
14 | 1. D-U-N-S Number
15 | 2. Privacy Policy
16 | 3. Primary Screenshot
17 |
18 | #### D-U-N-S Number (DUNS)
19 | When we were submitting Bluu, we reached a screen that asked for our company's DUNS number. As it turns out, it's easier to get Obama's cell phone number than a DUNS number.
20 |
21 | Basically, no start-up has a DUNS number; you have to acquire it through Dun & Bradstreet. Apple uses this number to verify your identity with Dun & Bradstreet. We tried to get our DUNS number in the following ways:
22 |
23 | 1. Using the D&B website
24 | 2. Using Apple's website
25 |
26 | ##### The Bad Way: Using the D&B website
27 |
28 | This approach is a complete disaster and will make you question if you even want to submit your app. We first tried to get our DUNS number using the tool on [D&B iUpdate](https://iupdate.dnb.com/). After battling with their website that provides no error messages but just refuses to move forward when you hit continue, we eventually decided just to call them. The rep on the phone said we would have to pay around $600 to get our DUNS number instantly or we would have to wait 30-45 days. Ugh...seems like D&B is trying to innovate the art of phone pick pocketing.
29 |
30 | ##### The Less Bad Way: Using Apple's website
31 |
32 | Out of frustration, we then tried to use Apple's [DUNS Number Look-up Tool for Company Enrollment](https://developer.apple.com/ios/enroll/dunsLookupForm.action). After the look-up had failed, it generated a link to submit a request for our DUNS number to D&B on our behalf. Seven days later we had our number.
33 |
34 |
35 | #### Privacy Policy
36 |
37 | App Store submission also requires a privacy policy under certain circumstances. Since Bluu doesn't collect much personal information we used [this](https://dl.dropboxusercontent.com/u/2312024/Bluu%20Privacy%20Policy.pdf) simple privacy policy we got from [iubenda](http://iubenda.refr.cc/47N4N5B), It's a pretty sleek web app that lets you customize your privacy policy depending on the services used in your application (Facebook, Admob, HockeyApp etc.). Use this [link](http://iubenda.refr.cc/47N4N5B) to get 10% off.
38 |
39 | #### Primary Screenshot
40 |
41 | When we were uploading screenshots for Bluu, we realized it would be more effective if the screenshot that shows up in search results looked more like an advertisement. So we created this screenshot:
42 |
43 | 
44 |
45 | It took a bit to find the all the iPhone and iPad templates to make the screenshot possible so I'm sharing them for your convenience:
46 |
47 | 1. [iPhone 4](https://dl.dropboxusercontent.com/u/2312024/iPhone4.png)
48 | 2. [iPhone 5](https://dl.dropboxusercontent.com/u/2312024/iPhone5.png)
49 | 3. [iPad](https://dl.dropboxusercontent.com/u/2312024/iPad.png)
50 |
51 | Also, here are the dimensions you need for all the screenshots:
52 |
53 | 1. iPhone 4: 960 x 640
54 | 2. iPhone 5: 1136 x 640
55 | 3. iPhone 6: 1334 x 750
56 | 4. iPhone 6 Plus: 2208 x 1242
57 | 5. iPad: 1536 x 2048
58 |
59 | The iPhone 6 Plus is the strange one since it doesn't match the actual pixel specification on the Apple website. The iPhone 6 Plus basically scales it down to 1920 x 1080, the actual pixel dimensions.
60 |
61 | Hope these tips help make your first submission process easier!
62 |
--------------------------------------------------------------------------------
/bluu-the-rules.md:
--------------------------------------------------------------------------------
1 | ```
2 | title: Bluu: The Rules
3 | tags: [Bluu, app, design, game]
4 | date: August 1, 2014
5 | slug: bluu-the-rules
6 | excerpt: Creating the rule logic behind Bluu.
7 | author: Andy Pai
8 | ```
9 | If you didn't read my last post on [The Birth of Bluu](http://lapwinglabs.com/blog/the-birth-of-bluu), here's what you missed: we wanted to give ourselves a crash course in turning a new idea into a released app so that we'd have a better understanding of what it takes, and we figured a simple game would make for a good pilot project. This post talks about how we refined the idea for [Bluu](https://itunes.apple.com/us/app/bluu/id916926135?ls=1&mt=8) into something that we thought would be fun to play and easy to implement.
10 |
11 | The idea behind Bluu was that we could take advantage of the [Stroop Effect](http://en.wikipedia.org/wiki/Stroop_effect) (depicted below) to create a game that was mentally stimulating but simple to implement.
12 |
13 | 
14 |
15 | But what would that game look like? How would you play it? Well, defining the actual rules for Bluu turned out to be the most time-consuming part of the weekend and required a few iterations.
16 |
17 | ## Keeping it simple
18 | The goal of this project was to learn the intricacies of the overall app development lifecycle, not get bogged down in implementation effort, so we designed Bluu as a really simple 'race-the-clock' game that required players to quickly respond to 'text/color' challenges (whatever that meant...we hadn't really defined it at that point).
19 |
20 | To start, we laid out the gameboard of Bluu with a center ('Inside') tile surrounded by four 'Outside' tiles such that the goal of the game became to match the Inside tile with the correct Outside tile. Kind of an arbitrary decision, but we needed to start somewhere!
21 |
22 | 
23 |
24 | This left us with the task of defining the rules for determining which 'Outside' tile would correctly match an 'Inside' tile.
25 |
26 | ## Matchmaker, Matchmaker...
27 | The mockup above shows three primary characteristics of each tile that we could manipulate for each turn: Background Color, Word Color, and Word. This gave us a whole host of options for rule sets that would make two tiles 'matchable'. We tried a few different combinations, but they all followed the theme of doing things one way unless the color 'blue' was involved. This twist allowed us to add some difficulty to the game without significantly complicating the ruleset because it forces you to think critically at every turn.
28 |
29 | ### Attempt #1
30 | #### Rule 1: Match the background color of the inside tile to the correct word outside.
31 | For example, in the mockup above you would flick the tile down, since its color is red and the bottom tile contains the word 'Red'.
32 |
33 | #### Rule 2: Unless the tile is blue!
34 | If the inside tile is colored blue, then match it to the outside blue tile (so you're matching background colors in this case).
35 |
36 | We realized this rule logic led to a lot of eye movement since you had to read the text on all four outside tiles at all times. So we decided it would be better if *only* the center tile contained any text that required reading.
37 |
38 | ### Attempt #2
39 | #### Rule 1: Match the inside tile's word to the outside background color.
40 | So for example, if the inside tile contains the word "Yellow", you'd find the outer tile that was colored yellow and match with that. This required less eye movement and allowed us to speed up the game.
41 |
42 | #### Rule 2: Unless the tile is blue!
43 | This rule didn't change. If the inside tile is colored blue, then match it to the outside blue tile.
44 |
45 | We played the game internally with this ruleset, and while it was certainly an improvement over having to read 5 tiles per turn, we thought it became too easy after playing a few times. So we shuffled the rules around one more time before introducing to beta testers.
46 |
47 | ### Attempt #3: Beta Testing Rules
48 | #### Rule 1: Match the inside tile's text color to the outside background color...
49 | So if the word in the middle tile looked like Green, you'd send it to the outer tile whose background color was red. This added a little more complexity to the last revision of Rule 1 and more actively introduced the Stroop Effect by forcing you to acknowledge the color a word is printed in, even though it conflicts with the actual name presented.
50 |
51 | #### Rule 2: Unless the text is "blue"...
52 | If the inside tile's text says blue, then you match it to the outside tile's background color. So 'Blue' on the inside tile would match the outside tile colored blue. This rule keeps the game from getting too easy; without it you could just tune out the text entirely.
53 |
54 | #### Rule 3: Or you see blue
55 | If the inside tile's text *color* is blue, then DO NOT match it to the blue outside tile! You can send it to any outer tile that's *not* colored blue. Again, this rule just adds a degree of difficulty and forces you to do some more complicated mental gymnastics before making the right match.
56 |
57 | We released our beta version with these rules, anticipating that Rule #3 may overly-complicate the game. Our testers agreed, commenting that the rules were difficult to keep straight. We even got feedback from some saying that the game was broken because the rules were commonly misunderstood. So for launch, we stuck with only the first two rules from Attempt #3, dropping the 3rd for the sake of simplicity. We also added the tutorial cards that interactively teach you how to play and give you a chance to practice without time constraints so that you can test your understanding. You'll see these the first time you play the game.
58 |
59 | If the game has app store success, it'll be fun remixing the rule combinations for challenge modes and additional levels!
60 |
61 | In [Bluu: TestFlight vs. Crashlytics vs. HockeyApp](http://lapwinglabs.com/blog/bluu-testflight-crashlytics-hockeyapp) we describe our experience with selecting a beta testing and crash reporting service.
62 |
--------------------------------------------------------------------------------
/say-hello-to-gittask.md:
--------------------------------------------------------------------------------
1 | ```
2 | title: Say Hello to Gittask
3 | tags: [gittask, site, open source, development]
4 | date: January 16, 2017
5 | slug: say-hello-to-gittask
6 | excerpt: Introducing a new marketplace for coding tasks
7 | author: Lapwing Labs
8 | draft: true
9 | ```
10 |
11 | Gittask is a marketplace for connecting people that need to get coding tasks done with developers who can complete these tasks.
12 |
13 | 
14 |
15 | You can use Gittask for building your website, adding a feature
16 |
17 | Tasks may include things like:
18 |
19 | - I have a design for a website, I need someone to help write the HTML and CSS.
20 |
21 | - I need someone to help me add Google Maps into my Wordpress website.
22 |
23 | - Help! I have a broken PHP site and I need someone to fix it for me.
24 |
25 | - I need some advice for picking the best charting library
26 |
27 | You can find us here: https://gittask.com
28 |
29 | ## Why we built Gittask
30 |
31 | Developers: We want a world where you can spend a few hours on the computer and earn some money.
32 |
33 | Companies: We want a world where companies can get high quality code written for them in a matter of hours instead of weeks.
34 |
35 | Open Source Authors: to make "Open Source Developer" a job title and a sustainable career. We also want to make working in open source more accessible for a larger group of people who otherwise cannot afford to give their work away for free.
36 |
37 | ----
38 |
39 | As a developer I want to be able to log into my computer and earn money at a time of my choosing from a location of my choosing.
40 |
41 | As a founder, I want to be able to find people that are experts in certain parts of my stack, that can build those parts of my business better than I can.
42 |
43 | As an open source author, getting paid to build what you love is an ultimate form of freedom.
44 |
45 | ## Gittask for Developers
46 |
47 | We built gittask to help developers quickly earn money during the hours of their choosing, from a location of their choosing.
48 |
49 | Tasks are specific to libraries and languages, so it's easy to find the perfect match for your skill set and start earning money quickly.
50 |
51 | ## Gittask for Companies
52 |
53 | We think companies are going to love Gittask because they can reach out to specialists or even creators of these libraries or languages for help or assistance.
54 |
55 | There’s no risk to getting started with Gittask. It’s free to sign up and free to post a task. Gittask takes care of the marketing for you by automatically posting tasks on Github, Twitter and various other marketing channels. This frees you up to work on other things and reduces your recruiting costs.
56 |
57 | By outsourcing tasks to those who really know these projects well, companies can operate more efficiently, saving time and money.
58 |
59 | For example, if you’re building a website and you need to integrate with Facebook, instead of spending a couple days figuring out the Facebook API, you can just post a task on Gittask to have an expert implement it for you.
60 |
61 | ## Gittask for Open Source
62 |
63 | We believe that open source is fundamentally changing how we write software.
64 | …
65 | Gittask was built on the shoulders of the open source community.
66 | …
67 | That’s why we are giving 10% of each completed task back to the open source community.
68 |
69 | This 10% is distributed based on your contributions to the codebase, so if someone completes a $300 task using jQuery, $30 goes to the top contributors of jQuery. Here’s what the breakdown looks like:
70 |
71 | 
72 |
73 | You can check the pricing breakdown of your own repositories here: https://gittask.com/pricing
74 |
75 | ## The Landscape
76 |
77 | There are a couple of other services already out there doing similar things, so I want to talk about where we fit into the space.
78 |
79 | ### Bountysource
80 |
81 | In a sentence, Bountysource "builds in" open source, while Gittask "builds on" open source.
82 |
83 | Bountysource supports the open source community through paying for issues to be fixed and features to be added. If there's a lingering bug in jQuery library that's really bothering me, I'll post a bounty to sweeten the deal for whoever takes the time to fix it.
84 |
85 | Gittask supports the open source community by leveraging a developer's expertise in an open source library or language. If I need a custom jQuery carousel for my website, I'd look to Gittask for finding a jQuery expert to get it done quickly and properly.
86 |
87 | ### Gratipay
88 |
89 | In a sentence, Gratipay “donates” to open source, while Gittask “pays back” open source.
90 |
91 | Formerly known as Gittip, [Gratipay](https://gratipay.com) promotes open source projects and businesses through anonymous donations. This gives people an opportunity to help support individuals working on cool projects or interesting businesses. If you’re getting a lot of benefit out of the tools that [TJ Holowaychuk](https://github.com/tj) built, you might consider tipping him for his hard work.
92 |
93 | With Gittask, you pay for the developer’s domain expertise, code, and support. You get something back
94 |
95 | ### oDesk / Elance / Freelancer.com
96 |
97 | oDesk, Elance, and Freelancer.com are the more traditional companies that you’d look to for your outsourcing needs. For [Lapwing Labs](http://lapwinglabs.com), we used each of these services extensively to build [Levered Returns](http://leveredreturns.com).
98 |
99 | We found that the quality on these services was very hit or miss. Often times we had to throw away or refactor the task to make it work in our application.
100 |
101 | We can do better. After working in open source for 4 years, I believe that the open source community has the most talented and passionate developers in the world. By forging a close relationship with the community we will raise the bar and make outsourcing viable for those who are not willing to compromise on quality.
102 |
103 | ## We need your Help
104 |
105 | You can help us. We’re a young company with a lot to learn.
106 |
107 | We’re . We’re bootstrapping gittask with our own money
108 |
109 |
110 |
111 | If you like this product, we’d love some twitter love.
112 |
113 | If you’re an open source author, you can promote tasks on your repositories by adding badges to your Readme. Here’s the code to do that:
114 |
115 | ```
116 | [https://gittask.com/cheeriojs/cheerio.svg]
117 | ```
118 |
119 |
--------------------------------------------------------------------------------
/principles-of-an-ideal-database-client.md:
--------------------------------------------------------------------------------
1 | ```
2 | title: Principles of an Ideal Database Client
3 | tags: [database, client, open source, development]
4 | date: January 25, 2015
5 | slug: principles-of-an-ideal-database-client
6 | excerpt: Discussing the principles that go into an ideal database client
7 | author: Matthew Mueller
8 | ```
9 |
10 | As we've been building [Gittask](https://gittask.com), we've noticed some very leaky abstractions, specifically around our database client. We've had to write some gnarley boilerplate to handle type conversations and rollbacks. That got me thinking a lot about this question:
11 |
12 | > What would the ideal database client would look like?
13 |
14 | Database clients come in all shapes and sizes. Some are [awful](https://github.com/mongodb/node-mongodb-native) to work with, some are quite [lovely](https://github.com/pebble/yieldb) to work with. Unfortunately, I've found that all database clients fall short in some way or another. Here's what I believe goes into an ideal database client.
15 |
16 | ## Principles of an Ideal Database Client
17 |
18 | In my mind, the ideal database client would have the following characteristics:
19 |
20 | - **Lossless Serialization & Deserialization:**
21 |
22 | The data that goes in, should be exactly the same as the data that comes out. If this is not possible, the data should not go in at all.
23 |
24 | - **Polyglot Persistence:**
25 |
26 | Your database client should be able to speak to different backend databases.
27 |
28 | - **Atomic Transactions across Databases:**
29 |
30 | Your database client should be able to chain together writes across databases and rollback if there's a failure anywhere in the pipeline.
31 |
32 | Let's cover each of these principles in more detail:
33 |
34 | ### Lossless Serialization & Deserialization
35 |
36 | As developers, we shouldn't have to worry about how the database is going to muddle with our data. That's a leaky abstraction and extremely error-prone.
37 |
38 | Our database or database client should be responsible for keeping these data structures intact. When you save a Date object, you should expect to get a Date object back out.
39 |
40 | The serialization and deserialization steps should be separate but consumed by the ideal database client. There may be cases when you do not use this client for data retrieval, but you will still want the data to be cast properly.
41 |
42 | I wrote [superjson](https://github.com/lapwinglabs/superjson) as a first attempt at solving this problem for Node.js.
43 |
44 | ### Polyglot Persistence
45 |
46 | The database landscape has grown immensely over the last couple years. Each new database has certain advantages over the others, but all make certain tradeoffs.
47 |
48 | In fact, the [CAP theorem](http://en.wikipedia.org/wiki/CAP_theorem) tells us that it's impossible to have the perfect database and we need to choose which tradeoffs are acceptable for our application.
49 |
50 | One workaround for these restrains is the idea of [Polygot Persistence](http://martinfowler.com/bliki/PolyglotPersistence.html) that was popularized by [Martin Fowler](https://twitter.com/martinfowler). Polygot Persistence is the idea that you should pick the right database for the right job. This way we have can our cake and eat it too.
51 |
52 | ---
53 |
54 | Our database client should follow suit. Our database client should be able to speak the language of many different databases. In code that might look like this:
55 |
56 | ```js
57 | Client(mongo(details)).put(key, value);
58 | Client(redis(details)).get(key);
59 | ```
60 |
61 | ### Atomic Transactions
62 |
63 | You should be able to define atomic transactions across databases.
64 | Many databases have a way to do atomic transactions for their respective database, but this is not good enough in the world of polyglot persistence.
65 |
66 | For example, when you create a user, usually you perform (at least) two database writes:
67 |
68 | 1. Save the user data
69 | 2. Save the user session (so they're logged in)
70 |
71 | You could use the same database for both, but then you are sacrificing on either performance or query flexibility. A common polyglot persistence pairing for this task is Mongo for saving user data and Redis for saving the user session.
72 |
73 | It's important that these writes are atomic. If one of these writes fails, your application will be in an invalid state, so we need a way for the database client to "rollback" changes if there's an error while running these commands. The simplest way to do this is to take a snapshot and if there's a failure, rollback to the old values. In code this may look something like this:
74 |
75 | ```js
76 | client.atomic()
77 | .db(mongo).put('user', obj)
78 | .db(redis).put('session:' + sid, obj.id)
79 | .run(fn);
80 | ```
81 |
82 | Before each write, the ideal client would know how to reverse itself in the event of an error somewhere in the pipeline.
83 |
84 | ## What about ORM?
85 |
86 | I spent a lot of time [using](https://github.com/LearnBoost/mongoose/) and [building](https://github.com/modella/modella) ORMs and I'm now convinced that they are leaky abstraction and do more harm than good as your application grows.
87 |
88 | Laurie Voss blogged back in 2011 about why [ORM is an anti-pattern](http://seldo.com/weblog/2011/08/11/orm_is_an_antipattern). This blog post is still very relevant.
89 |
90 | I think you can get most of the advantages an ORM offers by having a good standalone data validation library (I recommend [rube](http://github.com/lapwinglabs/rube)) and our ideal database client.
91 |
92 | Then you can write your own models in a performant way with the best tools for the job.
93 |
94 | ## What about the unique features that databases provide?
95 |
96 | You may be wondering: well, some databases have more features than others. How do you write a client that can still take advantage of a database's unique features?
97 |
98 | I believe all databases operations can be boiled down to a few low-level operations:
99 |
100 | ```
101 | - client.get(key)
102 | - client.put(key, value)
103 | - client.del(key)
104 | - client.select(collection) (or "database", "table", "sublevel", etc.)
105 | - client.atomic() (initialize an atomic transaction)
106 | ```
107 |
108 | I think the ideal database would natively support these operations, but be extended for a database's unique features (via signals). In code it may look something like this:
109 |
110 | ```js
111 | var client = Client(mongo(details));
112 | client.put(key, value);
113 | client.mongo.query(query)
114 | ```
115 |
116 | The reason for `client.mongo` is that it's now very easy to locate those features which are unique to mongo. This makes your databases more interchangeable. So if we change our underlying database to LevelDB, our mongo-specific queries will throw:
117 |
118 | ```js
119 | var client = Client(leveldb(details));
120 | client.put(key, value);
121 | client.mongo.query(query);
122 | ```
123 |
124 | ## Let's build this together
125 |
126 | The ideal database has not been built yet. Right now, it's a series of high-level ideas that should go into building this client. I'm calling on the community to help get involved to hammer out the details and harden the implementation.
127 |
128 | If you are interested in getting involved or following along, I've set up a repository on [Github](https://github.com/lapwinglabs/yurt), with the working title Yurt.
129 |
130 | As always, if you like the work we do or want to follow us along as we learn, follow us on Twitter at [@lapwinglabs](https://twitter.com/lapwinglabs).
131 |
--------------------------------------------------------------------------------
/hacker-guide-to-setting-up-your-mac.md:
--------------------------------------------------------------------------------
1 | ```
2 | title: Hacker's Guide to Setting up Your Mac
3 | tags: [mac, hacker, bash]
4 | date: September 30, 2014
5 | slug: hacker-guide-to-setting-up-your-mac
6 | excerpt: Setting up your Mac the Hacker way
7 | author: Matthew Mueller
8 | ```
9 |
10 | Hackers obsess over automation. We want robots to do the grunt work so we can focus on the fun stuff. One area that's ripe for automation that hasn't seen much attention lately is setting up your computer.
11 |
12 | Today I want to show you some techniques to apply automation to the setup of your Mac. The goal of this post is to automate 80% of the bootstrapping, allowing you to setup a new Mac in a matter of hours, not days.
13 |
14 | 
15 |
16 | ## Previous Work
17 |
18 | There has been previous work done in this area to automate your Mac's setup. [Boxen](https://boxen.github.com/) is probably the most notable. Boxen is Github's solution to keeping their teams running similar environments so there aren't as many inconsistencies across boxes. Boxen is a great solution for more mature companies with devops teams
19 | , but what about the small startups or the lone hackers? We need a more suitable solution for them.
20 |
21 | ## Our toolbox
22 |
23 | This blog post will make use of the following open source tools to automate your Mac:
24 |
25 | - Installing Binaries with [homebrew](http://brew.sh/)
26 | - Installing Apps with [homebrew cask](http://caskroom.io/)
27 | - Backing up and Restoring Configuration with [mackup](https://github.com/lra/mackup)
28 | - Solid Mac defaults for hackers using [osx-for-hackers.sh](https://gist.github.com/brandonb927/3195465) (modified)
29 | - Bringing it all together with [dots](https://github.com/matthewmueller/dots)
30 |
31 | ## Installing Binaries with Homebrew
32 |
33 | Homebrew is a community-driven package installer and an essential tool for every hacker's toolkit. Homebrew automates the setup, compiling and linking of binaries. It also makes updating and uninstalling binaries a breeze.
34 |
35 | This is the first thing you should install on a fresh mac. Drop this snippet in a bash script to make sure homebrew gets installed:
36 |
37 | ```bash
38 | # Check for Homebrew,
39 | # Install if we don't have it
40 | if test ! $(which brew); then
41 | echo "Installing homebrew..."
42 | ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
43 | fi
44 |
45 | # Update homebrew recipes
46 | brew update
47 | ```
48 |
49 | The next thing you should do is update the unix tools you already have on your mac. This is more relevant than ever since the recent ["Shellshock"](http://goo.gl/zElPKk) debacle.
50 |
51 | Here's a snippet to update these unix tools:
52 |
53 | ```bash
54 | # Install GNU core utilities (those that come with OS X are outdated)
55 | brew install coreutils
56 |
57 | # Install GNU `find`, `locate`, `updatedb`, and `xargs`, g-prefixed
58 | brew install findutils
59 |
60 | # Install Bash 4
61 | brew install bash
62 |
63 | # Install more recent versions of some OS X tools
64 | brew tap homebrew/dupes
65 | brew install homebrew/dupes/grep
66 | ```
67 |
68 | You'll also need to update the `$PATH` in your `~/.bash_profile` in order to use these tools over their Mac counterparts:
69 |
70 | ```bash
71 | $PATH=$(brew --prefix coreutils)/libexec/gnubin:$PATH
72 | ```
73 |
74 | This establishes a solid foundation for your Mac. You can also install other tools with Homebrew to improve your workflow. Here's what I install:
75 |
76 | ```bash
77 | binaries=(
78 | graphicsmagick
79 | webkit2png
80 | rename
81 | zopfli
82 | ffmpeg
83 | python
84 | sshfs
85 | trash
86 | node
87 | tree
88 | ack
89 | hub
90 | git
91 | )
92 |
93 | echo "installing binaries..."
94 | brew install ${binaries[@]}
95 | ```
96 |
97 | After you're done, you should clean everything up with:
98 |
99 | ```bash
100 | brew cleanup
101 | ```
102 |
103 | ## Installing Apps with Homebrew Cask
104 |
105 | [Homebrew Cask](http://caskroom.io/) is an extension for Homebrew that allows you to automate the installation of Mac Apps and Fonts.
106 |
107 | After you have homebrew installed, you'll want to install Homebrew Cask:
108 |
109 | ```bash
110 | brew install caskroom/cask/brew-cask
111 | ```
112 |
113 | The number of apps you can install with Cask is enormous and growing every day. You can take a look at what applications are installable in their [caskroom/homebrew-cask](https://github.com/caskroom/homebrew-cask/tree/master/Casks) repo or you can search for applications from the CLI:
114 |
115 | ```bash
116 | brew cask search /google-chrome/
117 | ```
118 |
119 | Everyone's choice of apps will be different, but here is the script I use to install my favorite apps:
120 |
121 | ```bash
122 | # Apps
123 | apps=(
124 | alfred
125 | dropbox
126 | google-chrome
127 | qlcolorcode
128 | screenflick
129 | slack
130 | transmit
131 | appcleaner
132 | firefox
133 | hazel
134 | qlmarkdown
135 | seil
136 | spotify
137 | vagrant
138 | arq
139 | flash
140 | iterm2
141 | qlprettypatch
142 | shiori
143 | sublime-text3
144 | virtualbox
145 | atom
146 | flux
147 | mailbox
148 | qlstephen
149 | sketch
150 | tower
151 | vlc
152 | cloudup
153 | nvalt
154 | quicklook-json
155 | skype
156 | transmission
157 | )
158 |
159 | # Install apps to /Applications
160 | # Default is: /Users/$user/Applications
161 | echo "installing apps..."
162 | brew cask install --appdir="/Applications" ${apps[@]}
163 | ```
164 |
165 | If you want to install beta versions of things like Chrome Canary or Sublime Text 3, you'll need to tap the `versions` cask:
166 |
167 | ```bash
168 | brew tap caskroom/versions
169 | ```
170 |
171 | ### Attention Alfred users
172 |
173 | One thing you may notice if you're an [Alfred](http://www.alfredapp.com/) user is that you cannot actually launch these apps from Alfred because the actual location of the app is not in `/Applications` but in `/opt/homebrew-cask/Caskroom/`.
174 |
175 | To add this path to Alfred, you can run the following command:
176 |
177 | ```bash
178 | brew cask alfred link
179 | ```
180 |
181 | Voila!
182 |
183 | ### Bonus: Installing Fonts like a Boss
184 |
185 | Cask can also be used to automatically download and install fonts. In order to enable this, you'll need to tap the `fonts` cask:
186 |
187 | ```bash
188 | brew tap caskroom/fonts
189 | ```
190 |
191 | The font recipes are prefixed by `font-*`, so if you want to download [Roboto](http://www.google.com/fonts/specimen/Roboto), try searching for `font-roboto`:
192 |
193 | ```bash
194 | brew cask search /font-roboto/
195 | ```
196 |
197 | Here's how I install fonts:
198 |
199 | ```bash
200 | # fonts
201 | fonts=(
202 | font-m-plus
203 | font-clear-sans
204 | font-roboto
205 | )
206 |
207 | # install fonts
208 | echo "installing fonts..."
209 | brew cask install ${fonts[@]}
210 | ```
211 |
212 | You can find a full list of the fonts in the [caskroom/homebrew-fonts](https://github.com/caskroom/homebrew-fonts/tree/master/Casks) repo.
213 |
214 | ## Mackup
215 |
216 | [Mackup](https://github.com/lra/mackup) is a community-driven tool for backing up and restoring system and application settings. You can find the list of applications it supports in the [lra/mackup](https://github.com/lra/mackup/tree/master/mackup/applications) repo.
217 |
218 | I haven't had much luck installing Mackup using Homebrew (on Yosemite), but it's easy enough to install with python's `pip`:
219 |
220 | ```bash
221 | pip install mackup
222 | ```
223 |
224 | If `pip` is not available, you may need to install `python` with `brew install python`.
225 |
226 | By default mackup saves your preferences to your Dropbox, so you'll want to setup Dropbox first. Once Dropbox is setup, backing up your settings is simple:
227 |
228 | ```bash
229 | mackup backup
230 | ```
231 |
232 | This command will match your installed applications with it's recipes and symlink the settings files to `~/Dropbox/Mackup`.
233 |
234 | To restore these settings on another Mac or a wiped Mac, simply run:
235 |
236 | ```bash
237 | mackup restore
238 | ```
239 |
240 | ## osx-for-hackers.sh
241 |
242 | [osx-for-hackers.sh](https://gist.github.com/brandonb927/3195465) is a script by [Brandon Brown](https://github.com/brandonb927) that is based on [Mathias Bynens](https://github.com/mathiasbynens)'s popular [dotfiles](https://github.com/mathiasbynens/dotfiles/blob/master/.osx).
243 |
244 | This script optimizes your Mac's settings for hackability. It disables many of the annoying defaults Macs have, speeds up the keyboard repeat rate and window animations, and applies many other tweaks.
245 |
246 | This script should not be run without prior examination. It's quite opinionated and intended to be modified. You can find the version I modified here:
247 |
248 | https://gist.github.com/MatthewMueller/e22d9840f9ea2fee4716
249 |
250 | This version makes the script more idempotent, removing a lot of the prompts that I'd like to handle in other places.
251 |
252 | ## dots(1)
253 |
254 | [dots(1)](https://github.com/matthewmueller/dots) is a script I wrote to glue these concepts together. It's intended to be the first thing you install on your Mac (or Ubuntu server). It has no outside dependencies and works on many different distributions. To get the binary, simply run:
255 |
256 | ```
257 | (mkdir -p /tmp/dots && cd /tmp/dots && curl -L# https://github.com/matthewmueller/dots/archive/master.tar.gz | tar zx --strip 1 && sh ./install.sh)
258 | ```
259 |
260 | To boot up your Mac with sensible defaults, you can run:
261 |
262 | ```bash
263 | dots boot osx
264 | ```
265 |
266 | [dots(1)](https://github.com/matthewmueller/dots) is very much a work in progress, but I'm hoping to align the community's efforts around creating robust tools to quickly bootstrap new hacker-friendly machines.
267 |
268 | ## Conclusion
269 |
270 | By setting up automation, you can get up and running on a new Mac faster, you will stay up to date with the latest security fixes and you can minimize inconsistencies among your teammate's computers.
271 |
272 | What are your favorite tools for automation? Leave a comment!
273 |
274 | If you're interested in this kind of stuff or in our [other work](http://lapwinglabs.com/#work), you should [get in touch](mailto:hi@lapwinglabs.com).
275 |
276 | Happy automating!
277 |
--------------------------------------------------------------------------------