I’m a firm believer in using whatever tool you need to get the job done.
Is there shame in using a GUI?
I’m don’t believe in shaming devs for using a GUI and not using a CLI in the Terminal.
Dev shaming is toxic. It hurts people, and that’s not what we want, we want to build each other up! We want to get excited at each others accomplishments!
The tools we use to accomplish the task don’t really matter, what matters is that we build amazing software. There is no elite-ism of using one tool over another.
“You’re not a real dev if you don’t use a CLI” is a myth. Never believe those words. You’re a real dev if you can write software that works!
Why do I use both?
Personally I really use a mix of GUI and CLI. Some tasks are quick and easy in one or the other for me. For you it might be a different mix of benefits.
I prefer GUI for
Quick glance context: Current branch, commits behind/ahead, conflicts, other branches status, changed file count.
Cherry pick lines to commit, discard lines
Interactive rebasing & squashing with ease
Scrolling through exactly what lines of code I’m committing
Join me for a story about my journey migrating my personal API server to a new host. Never has there been such thriller as this adventure. There are learnings, distraction, stories, and of course a bitter sweet goodbye.
What do I host with my API server?
It’s a Node.JS express server.
Code is a joy of mine. In my spare time I tend spin up side projects and build experiments. Many of these ideas depend on storing & responding with data, thus I wrote a lightweight NodeJS express server to act as my generic multi-tenant api to server all apps I may rapidly prototype.
Some notable projects include:
DancingQuest – Chicagoland & Wisconsin Social Dance Calendar
1) I use DigitalOcean as my host. The server cost $5/mo. I created the box 4yrs ago. For new boxes DigitalOcean now offers more RAM & Hard Drive space at the $5 tier.
What happened to jstassen-02? RIP
2 ) Ubuntu upgrade form 16.04 to 18.04. I could just upgrade the system, but value in starting fresh right?
3) Ok ok, dpkg is also very broken on jstassen-01, something with the python 3.5 package being in a very bad inconsistent state. I would really like install docker and start running mysql or mongo db. I started to fix dpkg to get this working, but that went down a rabbit hole.
Given these 3 nudges, it just made sense to swap to a new box, install node and call it a day.
I got distracted at LiteSpeed!
I used DigitialOcean’s pre-configured Node boxes to get me started instead of going from a bare Ubuntu box this time. They have some nice ssh security & software firewalls prebuilt. Wait, but what are these other options?
Ooo what’s this? OpenLiteSpeed NodeJS? Never heard of it, let’s try it out!
After much confusion and configuration (C&C) I had things running pretty well. It required some modifications to the node app. The benefit of running the Reverse Proxy, the box can now listen on port 445 (https) and based off the domain name route to separate apps in the future. Do I need this? Not really, but don’t mind the option.
OpenLiteSpeed Listener configuration & Virtual host mapping page. This will be handy.
Then the code changes started
OpenLiteSpeed integrates & uses Let’s Encrypt out of the box. Previously I had the Node app handling serving up the certs. It’s rather nice to have the Node app be responsible for less. This brings the dev and production app closer together in parody.
The Database files are document based dbs stored to disk in flat files. It was nice to better organize where these were located on my file system. The migration to a docker based mysql or mongo db is a separate project. (whew avoided one distraction)
A new home
Next was updating the url to a more generic one. I previously used https://jstassen-01.jstassen.com. I could simply point that url at the new box. But that’s kinda ugly jstasssen-01 points to a server named jstassen-03 right? Hm. What about create a url like https://api.jstassen.com then it won’t matter what box it points to in the future.
Fun fact, API calls from an app won’t follow 301 redirects. So, redirecting jstassen-01.jstassen.com -> api.jstassen.com won’t work, especially with POST requests. Well Bummer.
No worries I can update all my apps to use to a new url. No big deal! … oh right that’s 11 different projects. Hm.
Tracking my progress. Emojis always help.
Half were very easy, however I wrote my first google chrome extension and Alexa skill back 4 years ago. I last updated & published them about 1 year ago. A lot of security changes have been updated for how these apps are now built. They have refined their permissions, coding patterns, and apis.Previously grandfathered in as legacy for both, but to redeploy, I needed to upgrade them. Sure, that can’t take long.
Next I noticed OAuth apps were failing. Cookies were failing to be set entirely. Kinda critical piece to remembering which user is authenticated! Interestingly Express.js by default won’t trust credentials forward to it through a reverse proxy (like LiteSpeed). Just needed to allow 1 layer of proxied requests. app.set('trust proxy', 1). Well that one liner took an evening to figure out, haha.
You mean I have to rebuild?
To use use the newest packages, I needed refactor both the google chrome extension and Alexa skills. 1 week later, whew it was complete! On the upside, all my dependencies are fresh and up to date. I now have a modern promise based ajax library and promise based db read / writes. Fancy.
I swear all I wanted to do was copy the code over to a new server and start it up. I didn’t bargain for these code improvements and refactoring.
Performance Testing
Is it faster? I ran 1,000 requests 10 concurrent against a heavy GET endpoint. The new box is on par and just marginally faster ( maybe 1%?) but it’s insignificant difference. Reasure none the less.
RIP jstassen-02, you were taken from us much too soon.
jstassen-02 (RIP) was a failed experiment running Plesk server. It was heavy, a RAM hog and just not optimized. Not to mention Plesk limits your vhosts. Api calls sometimes took twice as long compared to jstassen-01.
Backing up
It’s time to say farewell and delete jstassen-01. I’m not scared at all, why would I be? And yet I hesitate.
I found this youtube video with a reasonable way to create an archive of the Ubuntu box I can hold on to just in case. Can I restore from it? Hard to say. But at least the data will be there in the off chance I missed something.
# Backup
sudo tar -cvpzf jstassen-01.tar.gz --exclude=/backup/jstassen-01.tar.gz --one-file-system
# Restore
sudo tar -xvpzf /path/to/jstassen-01.tar.gz -C /directory/to/restore/to --numeric-owner
A small 3.24GB archive. I could make the archive smaller by clearing npm/yarn cache folders and clear temp files. But it’s close enough, not too bad.
Maybe next I’ll experiment with creating a new Droplet for a day (a droplet for a day probably cost something like $0.17) and try a restore. Would be interesting to understand this style of backup.
This probably was a bit overkill since I’ve also started to create 1 off private repos on GitHub and use them as a backups as well. So I a committed version my whole home directory too.
Apartment hunting can be fun, exciting, tricky, confusing, or filled with uncertainty.
Here are 40+ things I’ve thought of to think about when looking at a new apartment.
When comparing apartments, it might be good to build a spreadsheet and rank each apartment against each other. Or think about which items are a must have or like to have. We each rank things differently. For instance sunlight is very important to me, but for you maybe ceiling height is.
Feel free to use these as a starting point for you priorities in where you live!
Good Code Review (CR) on Pull Request (PR) are at the heart creating high quality code. Code reviews on closed pull requests can feel awkward.
I believe we should welcome feedback on all PRs — even closed ones.
A coworker of mine came back from a short vacation and read over my PRs I had opened and merged while they were out. They spotted a bug in one of my PRs and they left a comment pointing it out. They however felt deeply guilty commenting on a closed PR and apologized to me. This is odd to me.
Merged PRs often get treated as code where the “Ship that has sailed”. Treating merged code as “untouchable” forgoes the ownership and responsibility we developers have for the code we create.
I suggest a cultural shift: To strive to produce high quality code, we ought to welcome and be open to Code Review feedback, before, during, and after the life of a Pull Request.
How we allocate time to address the feedback will range from team to team but could be new backlogged stories, re-opening a new PR, or just answering questions.
How do you feel about code reviews on closed pull requests? Is there a better way to handle code feedback after it’s merged?
Using .get() then .set() seems simple and clean, but it’s slow, it fully replaced the the current Map. While the results are the same, ImmutableJS cannot optimize against it and cannot make some faster assumptions.
It is much better to using Immutable.js .update(). Immutable can keep more references and make assumptions that allow it to optimize the update. For more, check the .update() docs.
You can also use .updateIn() for deeply nested data. Read my post on Immutable get() vs .getIn() to see how it works.
A while back I switch from shooting Raw instead of JPG. It was a bit of a leap of faith. I didn’t know how I was going to be able to use my photos when they weren’t JPGs.
Why?
Check out this photo. If I was shooting JPG what you see on the left is all I would have. No way of saving anything. That photo is a gonner, throw it out.
But since I was shooting RAW, all the data is there. It just needs to be brought out. Heck, look at the sky right at the bottom on the line of the before/after. There’s a cloud!
Left image is over exposed with blown out sky, right image has recovered sky and can even see a cloud.
It’s photos like this that have sold me on shooting RAW.
JPG Pros / Cons
Pros:
Ready to be posted or shared
No need to do further processing in another application
Cons
Already processed in camera
Considered Final
(8bit)
Raw Pros / Cons
Pros:
More data
More color data (12 or 14bit)
Higher detail in shadows / highlights
You determine how the data interpreted
Can recover from over / under exposed images
Color temperature easily corrected
Non-destructive editing
Better sharpening / noise reduction
Cons:
Larger file size
Need software on the computer like Lightroom
Cannot use images on social sites
Takes longer to write a photo the your camera chip
Redirecting websites to be secure with https can be a little tricky. I had to exclude redirecting subdomains in htaccess RewriteRule. This mostly because a number of my subdomain’s code lives within a subfolder of my primary domain.
How to Exclude redirecting subdomains in htaccess RewriteRule
To exclude redirecting subdomains in htaccess RewriteRule use the following RewriteCond. This tell Apache to only use the redirect if the request is to the top level domain, not a subdomain.
RewriteCond %{HTTP_HOST} ^[^.]+\.[^.]+$
For instance, my .htaccess for jstassen.com looks like:
This regex only fully matches the base domain. You can see this on Debuggex.
Note: websites with www are considered a subdomain. For instance www.jstassen.com is a subdomain of jstassen.com just like blog.jstasseen.com. This rule will therefore exclude the www subdomain. I have my www subdomain auto redirect to remove the www which I recommend.
Thinking back on how I travel I realize that I’ve develop a set of principles for ways to travel cheap and keep costs low.
These are only general rules of thumb and all are subject to being broken.
1 Week in California $45/day (Excluding flight)
Recent trip costs
Two weeks in Europe France -> Switzerland -> Germany $2500
(~$105 / day without flight)
One week in Alaska $800
(~ $40 / day without flight)
One week in Europe Poland -> Slovakia $1,800
(~$150 / day without flight)
One week in NYC $1,700
(~$97 / day without flight)
Three weeks in Japan $3,000
(~$60 / day without flight)
Ways to Travel Cheap
Pick an affordable destination
Look up food cost
Look up lodging cost
Look up transit cost
Airfare
Be flexible with departure dates, use an app that shows nearby date prices.
Google Flights
Hopper App
Hipmunk App
Chepoair
Book Directly with airline
Max out your carry on (Check as few bags as possible)
Don’t buy things on the airplane or at airport
Don’t upgrade your seat, your only on the plane for a few hours
Some airlines charge to pick your seat, don’t pick a seat.
If a company is paying for flights, extend the days.
Attractions
Book online, sometimes there is a deal / coupons
Pay as a group
Share audio tours – makes it more social
Consider a multi-attraction pass
Stop by a hostel (even if you’re not staying), sometimes there are deals on attractions & tours
Don’t buy the all access pass if you don’t have time to see everything
If you are a student, pay student pricing
Check if you get discounts with AAA, Your Credit Card company, AARP, etc.
Food
Minimize eating out
Street food / Food carts are generally affordable and good
Bakeries
Grocery stores
Cook
Snacks
Refill a water bottle instead of buying beverages.
Eat 2 blocks away from tourist destination.
Pack and bring lunch to tourist destination,
Pick cheep food destination.
Share entrees
Keep and eat any leftovers instead of tossing
Check local customs on tipping. You might not need to tip, even though it may feel odd.
Lodging
Couchsurfing
Stay with friends, or friends of friends. (ask facebook)
Hostel (book directly if possible or by phone, avoid sites that add a fee)
AirBnB
Camping
Call other hotels and talk them down by comparing prices
Use your AAA membership discount if you have it
Transit
Rail deals (tourist pass)
Split cost between travelers (car, group train ticket)
Compare bus vs Train
Spend time reading and understanding a city’s light rail & bus passes to find the best fit for your visit.
Don’t drive the toll ways
Park a little ways away
Consider alternatives
Walk / Bike
Currency
Don’t get the currency before you leave (ok maybe a little)
Don’t get currency at a cash exchange (terrible exchange rate)
Withdraw cash at ATMs with a debit card
Use a Credit Card with no foreign transaction fee.
When given the option always charge the transaction in the local currency, it will convert with fewer fees.
Prefer credit card to cash if possible
Phone
Check what is free with your current provider. For instance texting both photos & videos is free internationally with AT&T, but calling and cell data costs.
Disable all cellular data on your phone to avoid fees. Only enable on a per-app basis as needed.
Download offline maps & language translations to reduce data use.
Don’t check your voicemail.
Bring an unlocked cell phone, and buy a local SIM, takes research.
Call home using WiFi with VoIP. Like Google Hangouts, Skype, Whats App, FB Messenger, etc.
Check behind you and don’t loosing things – replacing items costs
Check if you need to buy travel insurance
Did I miss something? Do I have something wrong? What ways to travel cheap do you know? Leave a comment, I’m always updating this list with more ideas / corrections!
Starting out on Instagram is tough. I’m still building my following. I’ve figured out a couple of patterns that are best to follow when posting to get more engagement on posts. Here are 7 ways to get more likes on Instagram that I’ve found.
Post in the early morning, or the evening.
People tend are busy during the day, they check their feeds either when they are getting ready for the day or after they are starting to wind down. Of the two, evening tends lead to a slightly better output.
A post shared by Sir.Nathan Stassen (@thebox193) on
Post at the best time for you audience.
Know your audience. If you’re posting a shot from a past trip to another country, try to match your post with when they are awake. Thinking about your audiences you might be able to get two audiences at the same time.
For instance, this shot is taken in Switzerland, I live in Chicago. I posted at 7am (morning) Chicago time 3pm (evening) Switzerland time. I hit both my local audience and my Europe audience.
A post shared by Sir.Nathan Stassen (@thebox193) on
Hashtag your post
I’ve seen many great photographers fail to put any hashtags on their posts. Hashtagging is a central feature of Instagram. It’s a key way for others find your post.
I follow the four Ws + D rule:
Where? (stmaryglacier, colorado) What? (mountains) How? (lensbaby, tiltshift) Doing? (hiking).
A post shared by Sir.Nathan Stassen (@thebox193) on
Hashtag in different languages
Hashtagging in other languages broadens the size of your audience. You don’t need to use obscure hashtags. I recommend using Wikipedia instead of Google Translate.
In this shot I looked up the article ‘Dragonfly’. On the left of Wikipedia you’ll see a list of the article in different languages.
A post shared by Sir.Nathan Stassen (@thebox193) on
Add a geo location
Every photo was shot somewhere. You can only set one location, but there might be duplicates of the location on Instagram. Before posting try to searching the location to see which one gets tagged with similar photos.
For instance here you can see I set the location for this post to Steamboat Resort.
A post shared by Sir.Nathan Stassen (@thebox193) on
Like back
When someone likes your photo, take a moment to scroll through their feed and like a photo or two, maybe leave a comment. But wait a few minutes before doing this. What you want is to pull them back to view your feed. They sometimes recognize your username / avatar and will view your feed to like more shots. You’ve invested in them, they will now invest time back in you.
Everyone that liked this shot, I liked at lest one of their photos back.
When comparing Immutable.Set() and Immutable.OrderedSet() you’ll need to convert the OderedSet down to just a plain Set.
Comparing Immutable.Set() and Immutable.OrderedSet()
To compare equality with a Set and OrderedSet use this:
mySet.equals( myOrderedSet.toSet() )
Immutable .equals() compares the left and right to decide if they are both Ordered. If one is ordered and the other is not, they are not equal. isOrdered(a) !== isOrdered(b).
My Feelings
I find this a bit odd, especially when the left is a plain Set. I feel regardless if the right is Ordered or not, it’s the contents that we’re interested in comparing. However this is the Immutable.js definition. You will need to downgraded the OrderedSet for comparison via .toSet() which does have a slight cost to it. Immutable performance is worth keeping an eye on.