<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rob Sherling</title>
    <description>The latest articles on DEV Community by Rob Sherling (@rob117).</description>
    <link>https://dev.to/rob117</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F12999%2F7882f6c9-8085-489b-a9fb-da5bbb7c7858.jpeg</url>
      <title>DEV Community: Rob Sherling</title>
      <link>https://dev.to/rob117</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rob117"/>
    <language>en</language>
    <item>
      <title>React Native PSA - select and highlight text with custom context menus</title>
      <dc:creator>Rob Sherling</dc:creator>
      <pubDate>Mon, 18 Dec 2023 02:04:53 +0000</pubDate>
      <link>https://dev.to/rob117/react-native-psa-select-and-highlight-text-with-custom-context-menus-lml</link>
      <guid>https://dev.to/rob117/react-native-psa-select-and-highlight-text-with-custom-context-menus-lml</guid>
      <description>&lt;p&gt;Image credit - realtime photo of me trying to update this library, thanks to &lt;a href="https://unsplash.com/ja/@cookiethepom" rel="noopener noreferrer"&gt;@cookiethepom&lt;/a&gt; on unsplash.&lt;/p&gt;

&lt;p&gt;Before I begin, huge shout out to the two repositories that this was forked from: &lt;a href="https://github.com/Astrocoders/react-native-selectable-text" rel="noopener noreferrer"&gt;@astrocoders&lt;/a&gt; with the original, and &lt;a href="https://github.com/alentoma/react-native-selectable-text" rel="noopener noreferrer"&gt;@alenToma&lt;/a&gt;. Without their work, this never would have happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is this?
&lt;/h2&gt;

&lt;p&gt;In short, you can now select text again in React Native, fixing a &lt;a href="https://github.com/facebook/react-native/issues/13938" rel="noopener noreferrer"&gt;six year old issue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can select any text on iOS or Android and give custom context menu actions that you define.&lt;/p&gt;

&lt;p&gt;In short, you can do this now (clicking play gif will unstretch the image):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F16995184%2F54835973-055e7480-4ca2-11e9-8d55-c4f7a67c2847.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F16995184%2F54835973-055e7480-4ca2-11e9-8d55-c4f7a67c2847.gif" alt="demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Repo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/@rob117/react-native-selectable-text" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/rob117/react-native-selectable-text" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Relevant info
&lt;/h2&gt;

&lt;p&gt;Basically, the libraries that this was forked from hadn't been maintained for iOS for years and required hacks and workarounds to even get working. I just removed old dependencies, updated the iOS code to compile correctly, and cleaned up the readme.&lt;/p&gt;

&lt;p&gt;I tried to use ChatGPT to help, but honestly it was just analyzing iOS error messages and removing odd JS dependencies one-by-one.&lt;/p&gt;

&lt;p&gt;If you see any problems with it, PRs welcome!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>opensource</category>
      <category>highlighttext</category>
    </item>
    <item>
      <title>iOS Certificates and Profiles in 5 minutes</title>
      <dc:creator>Rob Sherling</dc:creator>
      <pubDate>Tue, 14 Dec 2021 00:08:44 +0000</pubDate>
      <link>https://dev.to/rob117/ios-certificates-and-profiles-in-5-minutes-8d2</link>
      <guid>https://dev.to/rob117/ios-certificates-and-profiles-in-5-minutes-8d2</guid>
      <description>&lt;p&gt;Hi. This is kind of a quick-and-dirty article about how certs and profiles work, because they're boring to read about and hard to understand (for me).&lt;/p&gt;

&lt;p&gt;This is my understanding of how they work. This might not be completely accurate, but it's been enough to work with. I'll cover the concept as fast as possile, and then a practical example.&lt;/p&gt;

&lt;p&gt;Before we get into it, terms:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;cert, certificate = signing certificate&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;profile = provisioning profile&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Certs and Profiles: concept
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Certificates
&lt;/h3&gt;

&lt;p&gt;Certificates are basically permission vouchers to build your app for a specific purpose.&lt;/p&gt;

&lt;p&gt;We have two major categories of certs: Development and Distribution.&lt;/p&gt;

&lt;p&gt;Development is for local debugging (think hooking a device up to your computer via usb).&lt;/p&gt;

&lt;p&gt;Distribution is for making non-debug, stand-alone files that are usually used in two ways.&lt;br&gt;
Ad-Hoc: you plan to distribute your app to a few devices outside the app store for testing.&lt;br&gt;
AppStore: Apple will distribute them on the App Store. &lt;/p&gt;

&lt;p&gt;For Ad-hoc, you'll almost always use it in the super-early starting phase of your Dev to make sure your app builds correctly and then never again because Testflight is just better.&lt;/p&gt;

&lt;h3&gt;
  
  
  Profiles
&lt;/h3&gt;

&lt;p&gt;A profile is tied to a specific certificate (again, for development or distribution) and is a permission slip to build an app for a &lt;em&gt;specific set of devices&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Note that a build profile that is tied to an AppStore cert will not ask you to specify devices, because Apple will distribute it to the world at large.&lt;/p&gt;

&lt;h2&gt;
  
  
  Actual practical example
&lt;/h2&gt;

&lt;p&gt;So, in this example I'll go through development that starts on an iPhone and then goes to iPad.&lt;/p&gt;

&lt;p&gt;Step 0) Buy an iPhone.&lt;br&gt;
Step 1) Go into your Apple developer account and click on certificates. Right now we just want to do some dev and testing via USB, so we choose development.&lt;br&gt;
Step 2) Add the iPhone we just bought to our Apple Developer Account list of devices. This is an account-wide list of all the devices you want to use for dev.&lt;br&gt;
Step 3) Go to the profiles section. Click create profile. When it asks you what cert you want this to apply to, click the development cert we just made. It will ask what devices you want the profile to allow installation for - click your iPhone. Done.&lt;/p&gt;

&lt;p&gt;Now we can use this cert and profile to do some dev. After a while, we realize that we want to test on iPad as well.&lt;/p&gt;

&lt;p&gt;Step 4) Buy an iPad.&lt;br&gt;
Step 5) Go back into your Apple Developer Account and add the iPad to your devices list.&lt;br&gt;
Step 6) Create a NEW profile. We have to make a new one because we cannot edit old profiles to add devices to them. The new profile will ask what cert (our only cert, the dev one) and what devices (check iPhone AND iPad). Done.&lt;/p&gt;

&lt;p&gt;Now we can do dev on both.&lt;/p&gt;

&lt;p&gt;After a while, we want to upload to the app store. Good.&lt;/p&gt;

&lt;p&gt;Go to the Apple Dev Portal, create a cert, but this time choose distribution - App Store.&lt;/p&gt;

&lt;p&gt;Then create a new profile and at the cert step, choose the cert we just created.&lt;/p&gt;

&lt;p&gt;Done.&lt;/p&gt;

&lt;p&gt;I hope this was helpful.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>signing</category>
      <category>profiles</category>
      <category>distribution</category>
    </item>
    <item>
      <title>My AWS service was over-provisioned by ~1000 times: A 5-minute guide on how to check app resource use on fargate</title>
      <dc:creator>Rob Sherling</dc:creator>
      <pubDate>Sat, 09 Oct 2021 20:30:38 +0000</pubDate>
      <link>https://dev.to/rob117/my-aws-service-was-over-provisioned-by-1000-times-a-5-minute-guide-on-how-to-check-app-resource-use-on-fargate-159j</link>
      <guid>https://dev.to/rob117/my-aws-service-was-over-provisioned-by-1000-times-a-5-minute-guide-on-how-to-check-app-resource-use-on-fargate-159j</guid>
      <description>&lt;p&gt;&lt;em&gt;cover image by &lt;a href="https://unsplash.com/@markuswinkler"&gt;@marcusWrinkler&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Very quick backstory:&lt;/p&gt;

&lt;p&gt;I built and am working on an app called &lt;a href="https://learnkichi.com?utm_source=dev_to&amp;amp;utm_medium=article&amp;amp;utm_id=saving_money_metrics"&gt;Kichi&lt;/a&gt;. It's an app to help intermediate learners continue to learn Japanese and English at a very fast pace.&lt;/p&gt;

&lt;p&gt;I've done a lot of deploys in my software career, and I've found a really good recipe for starting any new deploy. In AWS speak, you want to use RDS with a &lt;code&gt;db.t4g.small&lt;/code&gt; wired up to two &lt;code&gt;t4g.medium&lt;/code&gt;. This makes sure that you can handle unexpected loads if your service suddenly spikes, and that your DB won't go down assuming that your app is more process-intense than it is DB-intense. You then want your DB to be AZ-multi-instanced so that you don't have to worry about an outage taking you offline and so that your maintenance window doesn't take your service offline.&lt;/p&gt;

&lt;p&gt;This is an excellent strategy for launching a service for a company. This is a terrible strategy for launching your own service from scratch. For reference - I knew my service would need to start small, so I set my db to &lt;code&gt;micro&lt;/code&gt; and my two containers to &lt;code&gt;1 GiB memory&lt;/code&gt; with &lt;code&gt;.5 vCPU&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to actually profile your production app
&lt;/h2&gt;

&lt;p&gt;So, something that I found &lt;em&gt;profoundly annoying&lt;/em&gt; is that everyone seemed to tell me "profile your app to see how many resources you need", but no one actually told me how to do that. So, I found out.&lt;/p&gt;

&lt;p&gt;1) Put your app on Fargate. I only say this because this is my current setup.&lt;br&gt;
2) Click "Enable container insights" when you deploy. This will send a ton of metrics to CloudWatch. &lt;strong&gt;Note&lt;/strong&gt;: this is very, very expensive to maintain long term.&lt;br&gt;
3) Use your service for a little bit. Send a few of what you think might be your most demanding requests.&lt;br&gt;
4) Go to the CloudWatch Management Console, click "Logs", then "Log insights".&lt;br&gt;
5) Click 'Select Log Groups' on the top of the screen, and pick your logs that look something like &lt;code&gt;aws/ecs/containerInsights/{clusterName}/performance&lt;/code&gt;&lt;br&gt;
6) Prepare to be shocked at how efficient your app probably is.&lt;/p&gt;

&lt;p&gt;Please note that for each query, simply change &lt;code&gt;avg&lt;/code&gt; to &lt;code&gt;max&lt;/code&gt; or vice-versa to see the average or max for that metric.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory Usage (in MiB)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stats max(MemoryUtilized) by bin (30m) as period, TaskDefinitionFamily, TaskDefinitionRevision
                | filter Type = "Task" | sort period desc, TaskDefinitionFamily |  limit 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The number that comes out from this query will be the maximum memory that your containers have actually consumed, in MiB. I had provisioned 1GB per container. My max was ~299, so I dropped it to 512MB per container. Saved 50%.&lt;/p&gt;

&lt;h3&gt;
  
  
  CPU Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stats max(CpuUtilized) by bin (30m) as period, TaskDefinitionFamily, TaskDefinitionRevision
                | filter Type = "Task" | sort period desc, TaskDefinitionFamily |  limit 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one &lt;em&gt;blew me away&lt;/em&gt;. So, the number that came out of this search was &lt;code&gt;0.7&lt;/code&gt;. I thought "Okay, so that's like 0.7 vCPU, that's not too bad."&lt;/p&gt;

&lt;p&gt;Then I ran a different query to see what the container itself had provisioned for maximum CPU usage, just to double-check (that query can be found in the metrics source link at the bottom). The number that came back was &lt;code&gt;512&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Not &lt;code&gt;.5&lt;/code&gt;. &lt;strong&gt;512&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;My app, with all of its OCR and DB access and sync and whatnot, only used about 1/100th of a vCPU in production.&lt;/p&gt;

&lt;p&gt;I immediately reduced my docker containers from 2 to 1, and reduced the CPU allotment to 256. This saved me 75%. Then I turned off container insights, because CloudWatch was getting expensive and I wouldn't need to profile again for a long time.&lt;/p&gt;

&lt;p&gt;So yeah. That's how you actually profile an app and see how much Memory/CPU it takes, and figure out how over-provisioned you are.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

&lt;p&gt;Source for all metrics: &lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-metrics-ECS.html"&gt;https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-metrics-ECS.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>metrics</category>
      <category>billing</category>
      <category>profiling</category>
      <category>aws</category>
    </item>
    <item>
      <title>Working in Japan 2: Freelancing, Job Hopping, More Salary, Visa Types, Learning Japanese</title>
      <dc:creator>Rob Sherling</dc:creator>
      <pubDate>Sun, 08 Aug 2021 12:58:18 +0000</pubDate>
      <link>https://dev.to/rob117/working-in-japan-2-freelancing-job-hopping-more-salary-visa-types-learning-japanese-4bee</link>
      <guid>https://dev.to/rob117/working-in-japan-2-freelancing-job-hopping-more-salary-visa-types-learning-japanese-4bee</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@themcny"&gt;https://unsplash.com/@themcny&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is a follow-up to &lt;a href="https://dev.to/rob117/working-in-japan-myths-realities-compensation-culture-by-a-software-engineer-2lh"&gt;Part one&lt;/a&gt;. This is an English article - I will only use Japanese when &lt;em&gt;not&lt;/em&gt; using it would make it harder to convey a point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt; - In the language section, I'm going to talk about &lt;a href="https://learnkichi.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=software_engineering_japan_two_en&amp;amp;utm_content=top"&gt;Kichi&lt;/a&gt;, an app to help you learn Japanese to an advanced level by helping you read material that you are interested in. I made this app. It's incredible, and I use it every day.&lt;/p&gt;

&lt;h1&gt;
  
  
  Table of Contents
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
Types of freelance

&lt;ul&gt;
&lt;li&gt;Freelance company&lt;/li&gt;
&lt;li&gt;Direct contract&lt;/li&gt;
&lt;li&gt;Companies that aren't freelance but look like it&lt;/li&gt;
&lt;li&gt;No need to network&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Benefits over being a regular employee

&lt;ul&gt;
&lt;li&gt;Salary differences&lt;/li&gt;
&lt;li&gt;Meritocracy&lt;/li&gt;
&lt;li&gt;Remote work is easier to get&lt;/li&gt;
&lt;li&gt;Fewer meetings&lt;/li&gt;
&lt;li&gt;Easy access to cooler problems&lt;/li&gt;
&lt;li&gt;No code tests&lt;/li&gt;
&lt;li&gt;So much time off&lt;/li&gt;
&lt;li&gt;Flexibility in work hours&lt;/li&gt;
&lt;li&gt;True freedom&lt;/li&gt;
&lt;li&gt;One interview&lt;/li&gt;
&lt;li&gt;Job hopping isn't a big problem&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Downsides

&lt;ul&gt;
&lt;li&gt;No stability&lt;/li&gt;
&lt;li&gt;No friends&lt;/li&gt;
&lt;li&gt;Language&lt;/li&gt;
&lt;li&gt;Skill&lt;/li&gt;
&lt;li&gt;Benefits&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Compensation

&lt;ul&gt;
&lt;li&gt;How much to charge?&lt;/li&gt;
&lt;li&gt;Health insurance&lt;/li&gt;
&lt;li&gt;Taxes&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Visa - Highly skilled professional visa&lt;/li&gt;
&lt;li&gt;
Learning Japanese

&lt;ul&gt;
&lt;li&gt;Full explanation&lt;/li&gt;
&lt;li&gt;Very Short Version&lt;/li&gt;
&lt;li&gt;An app to help you learn&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Types of freelance
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Freelance company
&lt;/h2&gt;

&lt;p&gt;Like everything on this list, a freelance company is a mixed bag. They manage invoicing/billing and will arrange interviews on your behalf. In exchange, they take a cut behind the scenes. You typically get paid the next month, e.g. you worked the month of May, and get paid in June. Of course, their cut means less money that can go to you.&lt;/p&gt;

&lt;p&gt;The way it works is that they have a bunch of job listings on their site. You create a profile, talk to an agent, and they match you with listings based on your needs.&lt;/p&gt;

&lt;p&gt;I've seen some shady freelance companies that were like "we keep your profile on record and forward your information to prospective companies. You get paid after they pay us, so two months from the date of work. Also, we have 'incident insurance' that you can buy. If the company doesn't pay us, you still get paid half. Don't worry, that never happens. But still. We have the insurance".&lt;/p&gt;

&lt;p&gt;The company I ended up choosing to help me find freelance jobs wanted to come with me on every interview, which was a bit awkward. Something I didn't realize was that them coming with you on each interview is also a big advantage - they typically give you &lt;em&gt;very&lt;/em&gt; honest feedback about what went well or poorly in an interview based on the company's feedback. They get this feedback by asking you to wait outside the interview room right after the interview and get the company's immediate impression of you.&lt;/p&gt;

&lt;p&gt;This works because the client company needs to be honest with them about how the interview went so that the freelance company can find better candidates, which will help the freelance company get paid. In turn, the freelance company can pass that feedback onto you so you can be hired more easily which will &lt;em&gt;also&lt;/em&gt; help the freelance company get paid. It can help you realize areas you might need to work on or skills you might want to project better.&lt;/p&gt;

&lt;p&gt;These types of places always pay you directly month-on-month. You don't need to send an invoice. Just do the work, file a report at the end of each day summarizing what you did (mine were usually about one line of text), and get paid. Simple.&lt;/p&gt;

&lt;p&gt;I chose a company called "Crowdtech". I'd recommend them but you'll need some experience and language skill, covered below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Direct contract
&lt;/h2&gt;

&lt;p&gt;You reach out to a company directly. Use normal job hunting platforms and when you apply just tell them that you want to freelance. It's pretty surprising - a lot of companies are willing to do this because for them it's less risk. A lot of the protections that full-time "regular" employees have don't apply to a freelancer, i.e. they can just not renew your contract if it doesn't work out. Of course, you make more money compared to "salaried" workers because you lose those protections. Caveat - you can't negotiate a starting bonus as a freelancer, so take this into account. A starting bonus is for employees who will work long term, and freelancer implies leaving at any time.&lt;/p&gt;

&lt;p&gt;They may pay you directly month-on-month without you doing anything.  Alternatively, you may need to send them an invoice on the last of the month and they pay it on salary day the month after. For example, at the end of April, you create an invoice for April's work and give them a copy, and they pay you sometime in late May. &lt;/p&gt;

&lt;p&gt;If you're going to send an invoice, use a program called "Misoca." It's a bit tough to register for but super helpful and free. Strongly recommend.&lt;/p&gt;

&lt;p&gt;This is nice because there is no middle-man to take a cut of your salary, but it does require marginally more work. Still, this is my recommended method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Companies that aren't freelance but look like it
&lt;/h2&gt;

&lt;p&gt;Two types of companies: SES and 派遣会社. They hire you full-time and then send you out to different client companies so you can work side-by-side on the client's projects. This is the opposite of freelancing. You don't have a freelance contract, you don't control your freedoms, you stick to the client's schedules and expectations, etc. Would not recommend.&lt;/p&gt;

&lt;h2&gt;
  
  
  No need to network
&lt;/h2&gt;

&lt;p&gt;A note on finding independent jobs and work on things like Upwork / Crowdworks. It seems like in other countries it is common to build your freelance career by networking and warm introductions and connections. In my experience in Japan, you can just job hunt like everyone else and simply ask to be freelance. You can go the networking route if you'd like, though. I've seen it happen - I've even seen a few freelancing companies that were started that way.&lt;/p&gt;

&lt;p&gt;Please note: I don't do bill-by-the-hour freelancing or Upwork or any of that stuff. Bill-by-the-hour work is not as common in Japan as it is in America. If this is the type of freelance that you are interested in, I would recommend googling it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Benefits over being a regular employee
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Salary differences
&lt;/h2&gt;

&lt;p&gt;You make more. Like, much more. It's further down the article, but you're taking on more risk so it makes sense that you make more. The exception here being starting bonuses, as mentioned above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meritocracy
&lt;/h2&gt;

&lt;p&gt;When you have a normal "desk job", you have to be in that building for at least 8 hours. With freelancing, If you get the work done, people rarely care what hours you work. I've had freelancing gigs where I worked remote 4 days/week and on my office day I was there from about 9:15 am to lunch. Your time is your own, and it's great.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remote work is easier to get
&lt;/h2&gt;

&lt;p&gt;Remote has become far more common during the pandemic, but it's easy-peasy to work at least a few days a week from home and just do the office 1/week thing. It's a really big perk of being expected to crank out quality work constantly - no one cares where you are when you do it, as long as it gets done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fewer meetings
&lt;/h2&gt;

&lt;p&gt;Double-edged sword. This contributes to a feeling of not being a part of the team, but I will take that trade 10 out of 10 times if it means that I only get roped into essential meetings. Counter-intuitively, I &lt;strong&gt;strongly recommend&lt;/strong&gt; doing a 15-minute stand-up meeting each day if you're mostly remote. It helps people keep track of what you're doing and keeps you in the mind of your project manager, which is important for a lot of political reasons. Plus, it helps you do your job by keeping you abreast of sudden organizational changes and developments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Easy access to cooler problems
&lt;/h2&gt;

&lt;p&gt;This certainly isn't exclusive to freelancing, but you can get some crazy problems that no one else on a team can deal with, like build tools, profiling, or migrating systems. If the idea of minimal onboarding followed by "We need you to build a prototype in 2 weeks, can you do it?" is exciting, you shouldn't have any issues finding that kind of work. Also a huge upshot - as a freelancer I never get assigned to routine bug fixes or maintenance code, because we're expensive and prone to change jobs often. Interesting, hard problems are in everyone's best interest.&lt;/p&gt;

&lt;h2&gt;
  
  
  No code tests
&lt;/h2&gt;

&lt;p&gt;I like code tests (think whiteboard interviews, not hacker rank) but it turns out that according to Japanese law you cannot be asked to take a code test if you are a freelancer. Polish those side projects if you don't have a large work history, because they can't directly test your aptitude so they'll need to see something.&lt;/p&gt;

&lt;h2&gt;
  
  
  So much time off
&lt;/h2&gt;

&lt;p&gt;If you finish the work, it's stupid easy to take days off. These are often not paid days off, but most freelance contracts are written like "service provider will work between 140 and 180 hours per month." If you get all of your work done, 140 hours is a little more than 2 days off / month. Also, if you work well with the company, most companies will still pay you a full salary even if you take a week off once in a while. Seriously. It's the wildest thing, and I can't explain it, but I've had it happen at more than one company where they told me "If you make the hours back here and there, we aren't worried about a week."&lt;/p&gt;

&lt;p&gt;Another big advantage is that taking unpaid time off as a regular employee can damage relations with your company. Not so for a  freelancer - all time off is unpaid, so no worries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flexibility in work hours
&lt;/h2&gt;

&lt;p&gt;This goes hand-in-hand with everything else, but &lt;strong&gt;screw a 9-6 workday&lt;/strong&gt;. If you work best in the morning, put in a few hours first thing, enjoy your day, and then finish up in the evening or at night. It's up to you to make sure you get the work done and fulfill your contract hours, of course, but I've worked 5-hour days for a couple of days a week and finished out the time on a Saturday where I had no plans. You have infinity-flextime - use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  True freedom
&lt;/h2&gt;

&lt;p&gt;All of the above means that you get to experience the absolute best life that engineering can offer (in my &lt;em&gt;incredibly&lt;/em&gt; humble opinion). If you want to work from another country (a little overrated, actually, but still nice!) or travel from Tuesday to Thursday because tickets to Wakayama were dirt cheap and that Airbnb with the rooftop pool lounge was only like 7,000 yen a night, but you don't want to suffer from bad work karma for taking time off? This is it. I &lt;em&gt;despise&lt;/em&gt; being chained to a desk, and freelance is giving me everything I could ever want.&lt;/p&gt;

&lt;h2&gt;
  
  
  One interview
&lt;/h2&gt;

&lt;p&gt;Most freelancing gigs are one or two interviews, but it isn't uncommon to just have one 45-minute interview and then be hired. Lower risks for the company means faster turn-around. Regular employee interviews can also be short, but I find that freelancing interviews on average tend to be shorter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Job hopping isn't a big problem
&lt;/h2&gt;

&lt;p&gt;Changing jobs often as a freelancer, especially if you have fulfilled your current project, is usually fine. The conventional wisdom in Japan is 3 years of employment. I usually change jobs 1/year, so freelancing is perfect for me.&lt;/p&gt;

&lt;h1&gt;
  
  
  Downsides
&lt;/h1&gt;

&lt;p&gt;If it isn't clear that I'm very biased in favor of freelancing, I am. But there are some real downsides.&lt;/p&gt;

&lt;h2&gt;
  
  
  No stability
&lt;/h2&gt;

&lt;p&gt;In short - Your contract can just be gone if they opt not to renew.&lt;/p&gt;

&lt;p&gt;Most contracts are one-to-three month automatic renewing, but the details depend on the contract. That being said, I think because of the way these things are handled in Japan you are more likely to have a warning before your contract suddenly ends - my last freelance company had no more work for me but extended the contract by a month to let me start job hunting because they only realized about a week before my contract ran out. They kept me on longer so I could job hunt from a place of security.  I'm still good friends with the people there by the way - amazing place.&lt;/p&gt;

&lt;h2&gt;
  
  
  No friends
&lt;/h2&gt;

&lt;p&gt;This has more to do with the remote nature of freelance work compared to freelancing per-se, but you get to skip out on a lot of the meetings because you aren't part of the regular culture there. You also don't get access to certain slack channels because of company security reasons. That means missing out on social interactions with your coworkers. You can certainly make friends, but you don't interact socially with people as much if you're aiming for a full-remote type of thing. If you tend to change jobs more often you also won't form a lot of deeper bonds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Language
&lt;/h2&gt;

&lt;p&gt;I am going to talk about this extensively below in language learning, but in short - if you don't speak Japanese to a comfortable conversational level, you're going to have a really hard time getting hired as a freelancer. There are opportunities out there, of course, but you need to be able to demonstrate that you can take tasks and work them out without miscommunication. A company isn't going to work with you and wait for you to grow your Japanese ability as you work together because you have no long-term relationship. They hire you for your skills &lt;em&gt;now&lt;/em&gt;, not what they can grow you into over the next 3 years. This brings me to my next point:&lt;/p&gt;

&lt;h2&gt;
  
  
  Skill
&lt;/h2&gt;

&lt;p&gt;You need to have previous job experience and skills. In my experience, most people won't consider your first job for freelance even with an insane portfolio. Job experience tends to gets you the interview while skills will keep the contract renewing. Because companies aren't interested in "growing you", if you don't have skills you won't be hired. A big part of that salary bump is that they aren't investing other resources in you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;p&gt;If you are going to have a child, &lt;strong&gt;strongly&lt;/strong&gt; consider becoming a regular salaried employee (the word in Japanese is 正社員). After one year of salaried employment, you are eligible for 1 year of paid maternity or paternity leave. You also become eligible for paid leave if you have a disability that stops you from working. The amount of time for disability leave can be based on your circumstances, so I'd encourage looking it up if you think it might apply to you.&lt;/p&gt;

&lt;p&gt;You get paid leave when someone close to you dies, you usually get more money based on family conditions (for example, if you have kids, your salary goes up by 10,000 yen/month per kid), and it's very, very hard to fire you.&lt;/p&gt;

&lt;p&gt;Another big benefit is for apartment hunting and taking out loans / getting credit. Big, stable companies especially look great on any kind of credit-based application.&lt;/p&gt;

&lt;h1&gt;
  
  
  Compensation
&lt;/h1&gt;

&lt;h2&gt;
  
  
  How much to charge?
&lt;/h2&gt;

&lt;p&gt;TLDR: Your normal salary + 30%.&lt;/p&gt;

&lt;p&gt;Whatever you want to make normally, add about 30%. For example, I usually charge about 750,000 yen/month for my work, so for freelance I tend to charge about 1,000,000 yen/month depending on the project and the time I need to put in. Keep in mind that if you are going through a contracting company they take a cut, so you might not get the exact salary bump you're hoping for. Also, if your output doesn't justify your salary, you are far more likely to be fired instead of the company working to improve your performance, so make sure you deliver that value consistently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Health insurance
&lt;/h2&gt;

&lt;p&gt;Go to city hall whenever you want, apply for health insurance, pay pretty much the same amount as a regular employee, get the same affordable coverage. It's awesome. America should try this sometime ;P (cue angry comments)&lt;/p&gt;

&lt;h2&gt;
  
  
  Taxes
&lt;/h2&gt;

&lt;p&gt;This could be an entire article, but they're surprisingly straightforward.&lt;br&gt;
How much money did you get paid all year? Revenue. What did you spend on equipment and train commutes? Expenses. &lt;/p&gt;

&lt;p&gt;e.g. You work from home? Part of your internet bill, the electric bill, water, gas, and the portion of your apartment that is a dedicated office are all expenses. Expense &lt;strong&gt;everything&lt;/strong&gt; that's reasonable. Eat lunch with your coworkers? Business lunch. Expensed. Go out drinking as part of a work event? Expensed. Keep receipts.&lt;/p&gt;

&lt;p&gt;From year two onward, they'll pre-collect 2/3 of your estimated taxes as two separate payments made throughout the year. At tax time, you take the calculated expenses, any pre-paid taxes, and your revenue. Go down to the tax office, punch some buttons on a computer, and it gives you a number that you either pay (most likely) or get deposited into your bank account (less likely). You can even do the whole thing from home from your second year onward and just bring in the finished forms.&lt;/p&gt;

&lt;p&gt;When in doubt, grab all your paperwork and go to your local tax office. They are shockingly helpful.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bonus #1 - ふるさと納税
&lt;/h4&gt;

&lt;p&gt;The scope is too big for this article, but google ふるさと納税。 Prepay your taxes (to a limit determined by last year's income), get crab/cake/strawberries/wagyu for free. For example, last year I got like 4 kilos of crab and I only had to pay the taxes I would normally pay + a 2000 yen flat fee for using the ふるさと納税 system. This isn't even a freelancer exclusive thing, but you should definitely do it if you are a freelancer. So much free stuff for the taxes you were going to pay anyway. &lt;/p&gt;

&lt;h4&gt;
  
  
  Bonus #2 - American? Read this
&lt;/h4&gt;

&lt;p&gt;Global income and taxes as an American, the ultra-abridged version. Google what you don't understand.&lt;/p&gt;

&lt;p&gt;This is the one place that it sucks to be a freelancer in a weird way - you get taxed on your revenue in Japan, and as a freelancer, your revenue is higher. Hence, you pay more - whereas in a company many benefits are taken into consideration before you are paid, so you make less but enjoy a lot of perks.&lt;/p&gt;

&lt;p&gt;Federal tax: You MUST file every year, full stop, freelancer or not. File form 2555. If you make less than ~$100k in Japan, take the FEIE so you owe nothing in tax. Follow the steps, remain calm, and you'll be fine. It's not too complicated in most places. In certain situations (you make more than 100k in Japan), you might want to instead take a tax credit for the tax you already paid in Japan. That's too hard to put into the abridged version, so get ready to read a lot of paperwork.&lt;/p&gt;

&lt;p&gt;If your rent is more than (I think) $1400/mo, you can deduct some of it from your American taxes depending on where you live in Japan. Check out the foreign housing deduction/exclusion.&lt;/p&gt;

&lt;p&gt;If you have more than $10k (combined) at any point in the year in all of your Japanese accounts, file an FBAR. If you don't, the penalties will rip you in half. This also triggers if you have $5k in one account and then move it to another account.&lt;/p&gt;

&lt;p&gt;Lastly, some states don't charge you state taxes if you live overseas. I am fortunate in that New York does not. Note to residents of California - they seem to charge you state tax on your overseas income the vast majority of the time. You should look into that.&lt;/p&gt;

&lt;h1&gt;
  
  
  Visa - Highly skilled professional visa
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://eng.visa-immi.com/list/highlyskilled/"&gt;Explanation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You get 5-year visa renewals, fast tracked permanent residence, and your spouse can work full time instead of just part-time. You can bring a domestic helper from your country if your spouse works, is ill and "can't do housework", or if you have kids. It's on a point-based system, but in short: Get the JLPT N1, have a bachelor's degree or higher, make a bunch of money, and you'll probably qualify.&lt;/p&gt;

&lt;p&gt;The huge catch: In this specific case, the company you work for owns the visa, not you. If you change companies, you lose the visa. This is completely different from a normal visa. I would not recommend it for freelance workers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Normal work Visa
&lt;/h2&gt;

&lt;p&gt;Many companies have no issue sponsoring you as a freelancer to renew your visa. They might not want to sponsor you to come to Japan to work (few companies do), but renewing tends to be very easy.&lt;/p&gt;

&lt;h1&gt;
  
  
  Learning Japanese
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Full explanation
&lt;/h2&gt;

&lt;p&gt;If you are interested in my take on how to learn Japanese and how I did it, please read this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@robsherling/how-i-studied-japanese-to-fluency-as-a-translator-and-software-engineer-with-jlpt-n1-abc0d248f4f0"&gt;How I learned Japanese to N1 as a translator and software engineer&lt;/a&gt;. If you like that article please clap a bunch for it because I have no idea how Medium works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Very Short Version
&lt;/h2&gt;

&lt;p&gt;This is the &lt;strong&gt;omega&lt;/strong&gt; TLDR of the above article:&lt;/p&gt;

&lt;p&gt;What level of Japanese should I have?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I recommend ~JLPT N2. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;That's the level that your conversation really starts to flow. Read the above to learn more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do I need to know kanji / hiragana / katakana?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Yes. You should be able to read and type all of the &lt;a href="https://en.wikipedia.org/wiki/J%C5%8Dy%C5%8D_kanji"&gt;standard kanji&lt;/a&gt;, more or less. Note: not write, no one cares if you can't remember how to write the kanji for 納税 by hand.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How should I study?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In short - 1) have fun, 2) immerse when you can, 3) review religiously but delete flashcards you don't need anymore as if they are costing you money to keep around.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I still make a lot of mistakes when speaking - is that going to be an issue?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usually, no. If people can understand what you want to say, you're probably fine. Flip the script here - if someone was talking to you in English and said "I am wanting to go to the lunch together, let's eat some roast foods!", you might find that grammar endearing, and it certainly wouldn't stop you from going to lunch. The inverse, however, "The server is down because static page on CDN was eaten by the node." -&amp;gt; Not being able to understand what this person is saying would be intensely frustrating. In short: if you know how to make yourself understood and are comfortable learning specialty words for your job as you go, no problem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  An app to help you learn
&lt;/h2&gt;

&lt;p&gt;I covered this in my language article above, so I won't plug it too much here - I built a language learning app that helps you learn Japanese from things you're interested in. I used Anki to do this, but I got frustrated with some parts of Anki and wanted to do some things differently. You take images of things you like (menus, games, subtitles, physical books, screenshots of the kindle app, etc.) and it processes them. Tap a word in the image and it will give you the pronunciation, translation, more lookup options, and use the sentence you learned it from as an example sentence in a flashcard. It is specifically designed to help you customize your study to read the things you find fun instead of pre-made decks. I use it to read boatloads of Manga and kindle books, and sometimes play Japanese games.&lt;/p&gt;

&lt;p&gt;If you're interested, check out &lt;a href="https://learnkichi.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=software_engineering_japan_two_en&amp;amp;utm_content=bottom"&gt;https://learnkichi.com&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Everything here is just based on my own experiences. Every situation is different - some people really, really prefer the structure and security of salaried work, and there is nothing wrong with that.&lt;/p&gt;

&lt;p&gt;Did I miss anything? I feel like there isn't a lot of information like this online, and I'm trying my best to post relevant updates. If you want to see an article on something, please let me know. You can leave a comment, track down my email, or just DM / follow me on twitter (link in my profile).&lt;/p&gt;

&lt;p&gt;Again, if you want to know more, &lt;a href="https://dev.to/rob117/working-in-japan-myths-realities-compensation-culture-by-a-software-engineer-2lh"&gt;Part one&lt;/a&gt; is here.&lt;/p&gt;

</description>
      <category>salary</category>
      <category>japan</category>
      <category>japanese</category>
      <category>freelance</category>
    </item>
    <item>
      <title>I'm a programmer changing jobs in Japan. This is a list of all the stuff I've learned on my job hunts.</title>
      <dc:creator>Rob Sherling</dc:creator>
      <pubDate>Wed, 12 Feb 2020 11:52:55 +0000</pubDate>
      <link>https://dev.to/rob117/i-m-a-programmer-changing-jobs-in-japan-this-is-a-list-of-all-the-stuff-i-ve-learned-on-my-job-hunts-2afb</link>
      <guid>https://dev.to/rob117/i-m-a-programmer-changing-jobs-in-japan-this-is-a-list-of-all-the-stuff-i-ve-learned-on-my-job-hunts-2afb</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@gk3"&gt;https://unsplash.com/@gk3&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Before we begin - &lt;a href="https://www.kalzumeus.com/2011/10/28/dont-call-yourself-a-programmer/"&gt;never call yourself a programmer&lt;/a&gt;. Software engineer would have made my title too long for Dev.to to allow, so I used shorthand. &lt;/p&gt;

&lt;p&gt;Okay. Let's talk about interviewing. This is a collection of advice and useful questions that I've personally collected. If you're in a rush and only want the TL;DR, read the bolded headlines.&lt;/p&gt;

&lt;p&gt;I've already written up a really extensive history of my career, complete with past salaries, some negotiation tactics, and a discussion of Japanese work culture &lt;a href="https://dev.to/rob117/working-in-japan-myths-realities-compensation-culture-by-a-software-engineer-2lh"&gt;here&lt;/a&gt;. I'll be skipping all that to save time along with all the obvious interview questions that I see like "what does a typical day here look like?" - that information is everywhere.&lt;/p&gt;

&lt;p&gt;These views will be based on me and what I value - every situation is different, but everyone should get good mileage out of the interview questions at the very least because they grant insight into the place you might be working.&lt;/p&gt;

&lt;h2&gt;
  
  
  Questions
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Question set #1: What do you, personally, like the most about the company? What do you want to improve the most? (do not use the word dislike)
&lt;/h4&gt;

&lt;p&gt;Most people give very safe answers to this question. This question serves two really good purposes, though.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If they give a genuine answer (huge bonus points from me, by the way) that isn't immediately obvious, I ask them to tell me why they feel that way so I can learn more about the company as well as the interviewer who I will probably see again at some point in my life should I chose to work there.&lt;/li&gt;
&lt;li&gt;I forgot literally every single question I had prepared / they were all answered and I want to seem unorthodox and insightful.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you ask what they like the most, they should give a genuine answer. "I like that we have good communication and work as a team / I like that we have a new coffee machine that does cappuccino and it's become the morning hangout spot / I like that we've got a very direct work culture." This is a fairly easy thing to answer, and I mostly gloss over the reply unless the answer is actually interesting.&lt;/p&gt;

&lt;p&gt;When you ask what they like the least, this is where you learn about them. Do they give safe answers like "I wish we had more people"? That doesn't necessarily count against them, but it says more about the company culture if they can say (especially in front of their teammates) "We're working on being more honest and more forthcoming with our opinions so we can work more efficiently / We desperately need more people in leadership positions because we need someone to guide the less experienced devs / We got our overtime work down to an hour a day, but we want that to be even less". If you hear this, that is an excellent sign of honesty and wanting to genuinely improve the company. Huge plus.&lt;/p&gt;

&lt;p&gt;Write down the positive point if you find it even remotely interesting. Before the next interview, take 10 seconds to look at your notes. If you're going to see that person again, it's impressive to say "Oh, John, I remember you telling me about the coffee machine! You do a cappuccino talk session today?". They will love you if you do this in a natural way.&lt;/p&gt;

&lt;p&gt;Write down the negative points in your notes so you can come back next interview and talk or demonstrate in a round-about way about how great you would be at solving those things and how honest/communicative/not-overtimey you are.&lt;/p&gt;

&lt;h4&gt;
  
  
  Question #2: How many people have quit in the last year / what percentage of people quit this year?
&lt;/h4&gt;

&lt;p&gt;Super small Japanese note because I found this super useful, the word you want here in Japanese is 離職率(rishokuritsu).&lt;/p&gt;

&lt;p&gt;This number is incredibly important. Whether you should ask for a percentage or just a total number depends on your culture, but if they tell you a number that seems high, you should be concerned. I don't know what it's like in other parts of the world, but in Japan, for engineering anything higher than 5% is a problem.&lt;/p&gt;

&lt;p&gt;I found out once by asking this question that the entire engineering team for a startup had at one point all quit. Literally every single person left, in the span of like two weeks. Ask the question. If you're afraid to ask, that says volumes about the work culture and you don't want to be there.&lt;/p&gt;

&lt;h4&gt;
  
  
  Question #3: What are your hobbies?
&lt;/h4&gt;

&lt;p&gt;This is nice because it is polite conversation that isn't work focused. You get to see their passion for something outside of work, and you might get to see what their work-life balance is like. If they don't come up with anything (some people don't), no pressure. Just move on smoothly, or wait for the rebound and talk about something you like to do outside of work.&lt;/p&gt;

&lt;h4&gt;
  
  
  Question #4: Do you have a process for meetings?
&lt;/h4&gt;

&lt;p&gt;I ask this for bigger places. What are your meetings like? Are there a lot of them? Do you like them? Is there a rule on how long one can go on? Do the engineers go to them often? Etc.&lt;/p&gt;

&lt;p&gt;Because meetings usually suck. They don't have to - if everyone in a meeting room is arguing / laughing / getting angry / brainstorming, that meeting is worth having. If no one has said anything of substance in two minutes, or if the meeting could have been an email, you're wasting your time.&lt;/p&gt;

&lt;p&gt;This also, if you're lucky, can lend some insight into how fast the company moves and how much bureaucracy they have. A company with a lot of meetings rarely is process-free in other areas.&lt;/p&gt;

&lt;h4&gt;
  
  
  Question #5: When is the code interview?
&lt;/h4&gt;

&lt;p&gt;Ask for a code interview. It does two things:&lt;/p&gt;

&lt;p&gt;1) You get to show off your skills if you know something, and learn a new type of problem if you don't.&lt;br&gt;
2) It shows you what they value in their engineers.&lt;/p&gt;

&lt;p&gt;If they ask you to architect a system or design a database for a realistic use-case, you are in good shape. If they ask you to do a quick sanity-test for coding like Fibonacci numbers, that's fine too if you're more junior / they scanned your Github and just need to check that you actually wrote that stuff.&lt;/p&gt;

&lt;p&gt;You are not in good shape if they ask you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A math question disguised as a programming question.&lt;/li&gt;
&lt;li&gt;A pointless, easily googleable question about syntax like &lt;a href="https://www.joelonsoftware.com/2006/10/25/the-guerrilla-guide-to-interviewing-version-30/"&gt;What’s the difference between varchar and varchar2 in Oracle 8i&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A general algorithms question. Hear me out on this one: If you are working for a place that requires novel solutions and original code, good. This is a valid question. Otherwise - if you won't use this in your day-to-day, why are you being asked it?&lt;/li&gt;
&lt;li&gt;An abstract question like "How many stop lights are there in Seattle?" to see how you think.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am sure that you will find avid defenders of the above four questions in the comments, especially of that algorithms point. I stand by my views.&lt;/p&gt;

&lt;h4&gt;
  
  
  Question #6: What did you do before this, and why did you change?
&lt;/h4&gt;

&lt;p&gt;Useful for building rapport and general conversation with the interviewer. Also, if you care about career advancement, there's a bonus to asking this: The answer often tells you if they got promoted to that position or hired in as a manager already.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advice
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Advice #1: Do &lt;em&gt;not&lt;/em&gt; write most things down.
&lt;/h4&gt;

&lt;p&gt;I'm serious. Spend most of your time just listening because eye contact, genuine expression, and communication &lt;em&gt;are infintely better&lt;/em&gt; than extensive notes. Only write down answers to questions about things that you care about, things you forget easily that you'd wish you hadn't (names, for me), and impressions of the company and people.&lt;/p&gt;

&lt;p&gt;I've found that writing down "seems overly serious at first, but actually really funny" helps me remember that person's personality a little more accurately later on. I've also found that it helps confirm any good or bad vibes that I had when I go in for another interview later. When I look at my notes and see something like "This engineering manager seems like they are painfully strict and don't respect their employee's free time" from last week, followed by "this HR manager seems like they don't care about their employee's time", that's some pretty hard evidence that I should stop there.&lt;/p&gt;

&lt;p&gt;You can always send a followup email asking about a particular process or system or something that you forgot about or didn't write down. It's much harder to recall a hiring manager's attitude on work-life balance a few days after the interview, much less the week after when you're trying to decide what upcoming thing to cut from your schedule because you realized that smashing yes on each casual interview offer was a terrible idea.&lt;/p&gt;

&lt;h4&gt;
  
  
  Advice #2: Don't smash yes on each casual interview offer.
&lt;/h4&gt;

&lt;p&gt;Note: This is not saying that you shouldn't look into each interview offer, just don't smash yes.&lt;/p&gt;

&lt;p&gt;I was super, super guilty of this. I would get a bunch of offers to "come to the office to chat about the position", took a bunch of them, got there, and this would happen like clockwork:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;15 minutes of conversation&lt;/li&gt;
&lt;li&gt;I ask what the salary range is / overtime is like&lt;/li&gt;
&lt;li&gt;They answer with 1/2 my current salary / 20 hours a week&lt;/li&gt;
&lt;li&gt;I now have an hour and 45 minutes until my next interview, so I get to go pay Starbucks money again so I can sit there and wait until I can repeat this process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It costs a company nothing to have you come to their office for one of these. If the casual interview goes badly, they just go back to work. You lost all that time to get there and do all the research to make it seem like you knew a bunch about their company.&lt;/p&gt;

&lt;p&gt;I actually went to one casual interview to have the interviewer ask me if I had big data experience at a &lt;strong&gt;Facebook or Google&lt;/strong&gt; scale. When I told him that I had not, in fact, worked at a company even close to that size, he was surprised. I think that if I had actually read the job description (and if he had read my resume), we would both have saved a lot of time. We talked about Russian face-recognition technology, which was kind of cool, but we could have done that over the phone.&lt;/p&gt;

&lt;p&gt;If you see a place reach out to you that wants 3 years of front end experience but, like me, you would rather drink a mild poison than work with CSS, think about it. I'm not saying to skip the opportunity, but absolutely send them a message first. Mine is almost always:&lt;/p&gt;

&lt;p&gt;"Hi! Thanks for sending me an invitation to come talk. I have a concern that I'd like to address first, if possible. You said that you specialize in X technology, but I've literally never heard of that before and don't even know how it's pronounced. I'm more of a Y technology type of person - is that still a good fit?"&lt;/p&gt;

&lt;p&gt;Half the time, no response. Half the time, "Actually, that's an old job ad / a job for a different position, but we saw your skill set it matches something we have opening up." &lt;/p&gt;

&lt;p&gt;Rarely, "You look like you have a lot of experience - I'm sure you can get good with X technology quickly, so I'm not worried."&lt;/p&gt;

&lt;p&gt;Go to those.&lt;/p&gt;

&lt;h4&gt;
  
  
  Advice #3: Never talk salary with anyone who isn't HR/manager at final stage
&lt;/h4&gt;

&lt;p&gt;I realize this might be obvious, but trying to talk salary with another engineer or someone who can't decide in an interview is usually not a good idea (and I have done this). Focus on the fit, then the money. If a manager without salary-deciding power comes out of an interview and says to HR "they wanted to know how much we can pay", it does not come off as "This person wants to work with us." &lt;/p&gt;

&lt;h4&gt;
  
  
  Advice #4: Salary discussion in the first interview should raise suspicion.
&lt;/h4&gt;

&lt;p&gt;You asking for numbers in the first interview can be totally normal if that's your negotiation strategy. I do it occasionally to get a range of acceptable salary. If they ask you for your expected salary, they are not doing you a favor, they are trying to determine how much you'll cost before even seeing if you have what they want.&lt;/p&gt;

&lt;p&gt;Let me put it this way - if I told you I was going to buy you a mysterious fruit that I had never seen before from an old man in a wizard robe on the street, your first question would not be "How much does it cost?" because there is so much more that needs to go into that decision before price even becomes a factor. People who decide on price at that stage are not people you want to be with.&lt;/p&gt;

&lt;p&gt;That being said, if they ask and you respond with "what's the range of salary?" and they tell you, no problem. If they insist/are pushy, walk.&lt;/p&gt;

&lt;h4&gt;
  
  
  Advice #5: The questions they don't answer are the most important.
&lt;/h4&gt;

&lt;p&gt;If you get to a company that answers every question you ask, or follows up if they don't have that info on hand, it is probably a great place to work if you value honesty and communication. If they don't answer the question, assume the worst. Sometimes this doesn't mean anything, sometimes it's incredibly important.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;p&gt;"How many engineers are working on your level 3 customer support team right now?"&lt;/p&gt;

&lt;p&gt;"Can't say, sorry."&lt;/p&gt;

&lt;p&gt;Completely fine, probably a business secret or something.&lt;/p&gt;

&lt;p&gt;"You said that you're looking to grow a lot this year. How many engineers are you planning on hiring?"&lt;/p&gt;

&lt;p&gt;"Can't say, sorry."&lt;/p&gt;

&lt;p&gt;That shouldn't really be guarded information. Not a red flag by itself, but pay close attention and double check to make sure the company actually involves engineers in the business decisions.&lt;/p&gt;

&lt;p&gt;"How many people have quit in the past year?" "How much runway do you have left?"&lt;/p&gt;

&lt;p&gt;"Can't say, sorry."&lt;/p&gt;

&lt;p&gt;Walk.&lt;/p&gt;

&lt;h4&gt;
  
  
  Advice #6: Imagine being a Toxic Person
&lt;/h4&gt;

&lt;p&gt;Okay, weird title, but I'm serious.&lt;/p&gt;

&lt;p&gt;If I'm going to work with a company, I am painfully honest and try to communicate as much as possible before the hiring stage. But I also try to think of the hiring process from the mind of someone who would have a toxic affect on the work environment and see if they've done anything that would have weeded me out.&lt;/p&gt;

&lt;p&gt;If they talk a lot and don't let me talk much or ask many questions - I could be skilled but not a good person to be around. If I'm not introduced to anyone on the engineering team, they won't know if I have a clashing personality with our front-end engineer.&lt;/p&gt;

&lt;p&gt;The reason this is important, of course, is because you want to know that the process is good so that when you join it is less likely that you will have to deal with a toxic person joining after you.&lt;/p&gt;

&lt;h4&gt;
  
  
  Advice #7: Pay attention to your gut.
&lt;/h4&gt;

&lt;p&gt;If you feel off about a single person that you interview with, strongly consider walking. Like a relationship - you have a few hours to decide maybe years of your life. Be smart about it.&lt;/p&gt;

&lt;p&gt;If you feel like a company's atmosphere is too formal or casual, or the engineering area looks like a sterile hamster cage, or the sales people look like they'd rather be dead than at work, consider passing on it.&lt;/p&gt;

&lt;p&gt;You get a bad gut feeling, walk.&lt;/p&gt;

&lt;p&gt;Misc:&lt;br&gt;
When you see a job advertisement, that's actually the first chance you get to see what that company chooses to present to potential hires. If you see some copy-paste HR spiel (The successful candidate will have...), you're going to be working at a place with a very different vibe than a place that writes job ads like Google does. Prioritize applications accordingly.&lt;/p&gt;

&lt;p&gt;Once, in an interview, I went in to find the CTO who was supposed to be interviewing me was going to be late. Not a problem, it happens. He came in later, picked up my resume that the HR person had left on the table in front of him, casually flipped through it like I would flip through a pamphlet on the benefits of pistachio water, and then asked me to introduce myself and all my skills.&lt;/p&gt;

&lt;p&gt;Then he asked me about part of the Unity game I had been working on - specifically, sending data over a network. I told him, then he told me that couldn't be accurate. I told him it was. He then told me that TCP/UDP cannot be used over phones and asked me &lt;em&gt;how the Unity game engine implemented networking on a fundamental level&lt;/em&gt;. I told him truthfully that I had no idea, but I was pretty sure that the online multiplayer realtime rpg I was working on had UDP. He did not believe me. He later went on to say that everyone in the company, regardless of level or performance, received the same bonus amount and suggested that if my performance did not meet expectations they would decrease my salary until it did.&lt;/p&gt;

&lt;p&gt;They actually gave me an offer. I did not take it.&lt;/p&gt;

&lt;p&gt;Really, if I had to sum this article up:&lt;/p&gt;

&lt;p&gt;Company culture is everything. Ask the questions that give you the information you need to decide in two hours if you want to spend 8 hours a day working with these people.&lt;/p&gt;

&lt;p&gt;I think I'm going to write an article about freelance/consulting vs. full time work (at least here, in Japan) and how my current job hunt is going. It might be after I've chosen where I'm going to work, so a few weeks at shortest. It will hopefully be shorter than this article. If there's anything you'd like me to talk about, mention it below. I have no idea what people want to hear about and I'd like to help.&lt;/p&gt;

&lt;p&gt;Thank you for reading.&lt;/p&gt;

</description>
      <category>interview</category>
      <category>japan</category>
      <category>advice</category>
      <category>jobhunting</category>
    </item>
    <item>
      <title>Working in Japan: Myths, Realities, Salary, Culture (By A Software Engineer)</title>
      <dc:creator>Rob Sherling</dc:creator>
      <pubDate>Wed, 28 Aug 2019 05:56:24 +0000</pubDate>
      <link>https://dev.to/rob117/working-in-japan-myths-realities-compensation-culture-by-a-software-engineer-2lh</link>
      <guid>https://dev.to/rob117/working-in-japan-myths-realities-compensation-culture-by-a-software-engineer-2lh</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@manucosen" rel="noopener noreferrer"&gt;https://unsplash.com/@manucosen&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Edit (Aug. 5th, 2021): I wrote some new articles about how I learned Japanese and my language learning app &lt;a href="https://learnkichi.com?utm_source=dev_to&amp;amp;utm_medium=article&amp;amp;utm_campaign=software_engineering_1" rel="noopener noreferrer"&gt;Kichi&lt;/a&gt;. You can read about how I learned Japanese &lt;a href="https://medium.com/@robsherling/how-i-studied-japanese-to-fluency-as-a-translator-and-software-engineer-with-jlpt-n1-abc0d248f4f0" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Programming in Japan
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Intro&lt;/li&gt;
&lt;li&gt;Qualifications&lt;/li&gt;
&lt;li&gt;Starting My Career Here&lt;/li&gt;
&lt;li&gt;
Working Conditions

&lt;ul&gt;
&lt;li&gt;Hours&lt;/li&gt;
&lt;li&gt;Paid Leave&lt;/li&gt;
&lt;li&gt;Contracts and Rules&lt;/li&gt;
&lt;li&gt;Working in Games&lt;/li&gt;
&lt;li&gt;Company Rigidity and Change&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Employment Overall

&lt;ul&gt;
&lt;li&gt;I Was "Let Go" Once&lt;/li&gt;
&lt;li&gt;Excellent Job Security, But Not Guaranteed&lt;/li&gt;
&lt;li&gt;Bad Bosses, Harassment, Options&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;The Really Good Parts!&lt;/li&gt;

&lt;li&gt;Japanese Attitudes Towards People Who Are Not Japanese&lt;/li&gt;

&lt;li&gt;Overtime&lt;/li&gt;

&lt;li&gt;

Interviews and Perception of Programmers

&lt;ul&gt;
&lt;li&gt;Attitudes Towards Programmers&lt;/li&gt;
&lt;li&gt;Interviews, Competition, Company Size&lt;/li&gt;
&lt;li&gt;Working With Recruiters&lt;/li&gt;
&lt;li&gt;Freelancing&lt;/li&gt;
&lt;li&gt;Jobs That You Can Do Without Japanese&lt;/li&gt;
&lt;li&gt;Money, Visa, Location&lt;/li&gt;
&lt;li&gt;Salary and Cost of Living&lt;/li&gt;
&lt;li&gt;Apartments&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;This is a massive, nearly 30-minute read. If you're just interested in salary, click the indexed link above. I promise the whole thing is a great read, though.&lt;/p&gt;

&lt;p&gt;This last year working in Japan has been a &lt;em&gt;wild&lt;/em&gt; one. I wanted to take the time to offer the perspective of someone who's working successfully in Japan as a software engineer in mostly-or-entirely Japanese companies. Also, I want to give a perspective that hopefully offers some contrast against the mountain of horribly misinformed comments I see regurgitated on social media (&lt;em&gt;looking directly at you, Reddit&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;I'm writing the article that I wish I had going into all this - how hard is it to get that first programming job? What do I need to do to make it happen? How do I become a freelancer, and why would I do that? How much - exactly - does one make?&lt;/p&gt;

&lt;p&gt;To that end, I have year-by-year breakdowns of my salary, a brief background of my pre-engineering start here, and much more.&lt;/p&gt;

&lt;p&gt;A few things before we get started: I have mostly self-taught Japanese. I am fluent in Japanese and have native English. I am a very confident person. I am comfortable negotiating and saying no. I have never worked for a non-Japanese company in a career capacity. All of the companies that I've worked for were overwhelmingly Japanese in both nationality and language.&lt;/p&gt;

&lt;p&gt;I'll do my best to list the upsides and downsides of my own experiences, but as always &lt;strong&gt;every situation is different&lt;/strong&gt;. Now that we're prepared for the &lt;em&gt;wave&lt;/em&gt; of "but your experience is not normal because X" comments, let's do this!&lt;/p&gt;

&lt;p&gt;Also, this post will contain no Japanese. While I can understand the choice to sprinkle Japanese into a post about Japan, I think it would make this post harder to understand without adding anything of value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qualifications
&lt;/h2&gt;

&lt;p&gt;As of this article, I have about 4 years of experience as a programmer - mainly back end. Experience matters, of course, but what you do when you're gaining that experience matters more.&lt;/p&gt;

&lt;p&gt;I did not learn to program in school or boot camp. I learned to program by reading books on the fundamentals (what is an int, stack vs. heap, etc.) and then just doing a lot of things.&lt;br&gt;
As I mentioned above, I'm very comfortable with Japanese.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting My Career Here
&lt;/h2&gt;

&lt;p&gt;I came over as a Human Biology grad with no programming experience and pretty good Japanese (JLPT ~N3 for those who know the test). I could read some utility bills, some letters, and documents, and get by just fine with no English.&lt;/p&gt;

&lt;p&gt;I came over as an English teacher. I decided I wanted to be a games programmer, bought a physical copy of programming for dummies, and read on the 40-minute trains between my house and whatever school I was teaching at while I was situated up in Sendai (north-east Japan).&lt;/p&gt;

&lt;p&gt;I was worried about telling people that I was an English teacher when I changed into programming. I was concerned that they wouldn't take me seriously, or that it would somehow diminish my credibility. There is a perception with some truth to it that many people come to teach English here because it's an easy, paid way to experience Japan.&lt;/p&gt;

&lt;p&gt;I was wrong. If anything, it deepened my peer's respect for me because I was learning something outside of my field, and there's a pretty healthy respect for teachers here anyway.&lt;/p&gt;

&lt;p&gt;I studied Japanese and programming intensely for about two years. I got my N1, released a game, and then applied for a programming job. In retrospect, I should have done things pretty differently.&lt;/p&gt;

&lt;p&gt;I put way, way too much value on the N1. For those who don't know, JLPT is a test of your Japanese ability. Like all tests, it can be gamed, and it can be very flawed. I thought that I would need the N1 (highest level) to be viable in the Japanese workforce. The level before that, the N2, was straightforward and didn't require much study apart from grammar. The N1 was just all study. So much boring, grindy study.&lt;/p&gt;

&lt;p&gt;Day of the test, I fell asleep in the listening and woke up 10 questions later with someone talking about selling lemon-flavored baked goods. I went with the tried-and-true method of choosing all "C" for the questions I missed.&lt;/p&gt;

&lt;p&gt;I passed by four points.&lt;/p&gt;

&lt;p&gt;Then I got into the workforce and used almost &lt;em&gt;none&lt;/em&gt; of what I learned after the N2. I should have just focused more on programming from there.&lt;/p&gt;

&lt;p&gt;Also, entering the workforce months sooner would have been wise. I released a small, fairly well-polished game and then started studying Ruby for a few months. My Ruby study had very little to do with me getting hired. I could have gotten hired right after my release.&lt;/p&gt;

&lt;p&gt;If I can do it, you can too. Just put the work in.&lt;/p&gt;

&lt;p&gt;Edit (Aug. 5th, 20201): Check &lt;a href="https://medium.com/@robsherling/how-i-studied-japanese-to-fluency-as-a-translator-and-software-engineer-with-jlpt-n1-abc0d248f4f0" rel="noopener noreferrer"&gt;here&lt;/a&gt; for more about language learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working Conditions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Hours
&lt;/h3&gt;

&lt;p&gt;Just like in America, the conditions are as varied as the jobs. Japan can offer jobs that follow 10-7 work hours with an hour lunch - I would consider this the normal schedule in the tech scene. You can certainly find 9-6 jobs, jobs with flex time and core working hours, etc. Meritocracies are rare but exist - often (but not always!) when a contract stipulates that you can work whatever hours you want, it's used to have you work horrific amounts of overtime. I have worked in places where they were willing to change my contract to a meritocratic one. They exist, and the system can be excellent - work hard, go home early. &lt;/p&gt;

&lt;h3&gt;
  
  
  Paid Leave
&lt;/h3&gt;

&lt;p&gt;Like pretty much every first-world country except the states, Japan has mandatory holidays. 10 days a year, minimum, with a bunch of public holidays. It is true that many companies in Japan make you feel bad for taking paid time off, but from what I've directly experienced this is often less about a boss giving you flak and more about not wanting to abandon your team - a sentiment I've seen echoed in other countries as well. This seems to be less common in the tech scene - competition here is so fierce that you really can't risk losing programmers to that kind of thing, and the government cracks down very hard on stopping people from taking days off. On a personal note, I have never had an issue with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Contracts And Rules
&lt;/h3&gt;

&lt;p&gt;Contracts are really, really short. Usually a single page, and very loose. &lt;/p&gt;

&lt;p&gt;You have a few kinds of contracts. I'm not going to get into the details here, but basically, you either have contracts that renew and ones that are just permanent. Make sure you understand exactly what is in your contract - it's usually just boilerplate. Side note - check if they pay your taxes from your check or if you're expected to set aside money to pay them yourself. The tax issue is a bit complicated, so just ask.&lt;/p&gt;

&lt;p&gt;Similarly, all companies are required to have rules of operation for their employees. If you are unclear on anything, ask to see the rule of operation governing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Working in Games
&lt;/h3&gt;

&lt;p&gt;I do not recommend working in games. The entire state of working in games is a sham globally - low pay, bad conditions, churn - but I can only comment on my experience in Japan.&lt;/p&gt;

&lt;p&gt;Working in games in Japan is probably pretty similar to working in games in America. The pay is usually lower than in other fields. You can easily expect something south of 300k JPY / 3k USD a month. Not bad if you're totally inexperienced, but the raises and the salary cap are terrible. Ironically, if you want to draw a really good salary in this field, become specialized in either infrastructure or backend systems, then enter the field - you'll easily make double. Again, just my observations.&lt;/p&gt;

&lt;p&gt;I worked for a games company in Osaka called Aiming. I wasn't a fan of most of the management, but the people were &lt;em&gt;gold&lt;/em&gt;. We had a game area in the company where people gamed during lunch. Fridays, we'd bring alcohol and snacks, drink, go drink somewhere else, come back and drink, etc. - there were, of course, plenty that didn't drink and it was always a great time.&lt;/p&gt;

&lt;p&gt;I also interviewed at a few different game companies. One, let's call them Schmooby-Loft, had a particularly interesting interview process. At one point a gentleman from HR made it clear to me that I was technically entitled to take my time off when I pleased under Japanese law. He also made it very, explicitly, painfully clear that it would also almost certainly "be reflected" on my performance review and salary adjustments if I chose to take time off during busy periods.&lt;/p&gt;

&lt;p&gt;Not that it's taking time off during busy periods should be encouraged. But they made a show of conveying that in the most intimidating way they could.&lt;/p&gt;

&lt;p&gt;I turned down their flattering offer of "my current salary at the time but with more overtime."&lt;/p&gt;

&lt;h3&gt;
  
  
  Company Rigidity and Change
&lt;/h3&gt;

&lt;p&gt;Japanese companies are famously bureaucratic. However, you can make a massive difference at your company if you chose the right one.&lt;/p&gt;

&lt;p&gt;I've changed my pay, my working hours, my team, and my job tasks just by having conversations. Much like anywhere else, it depends on the people you work with and your ability to be persuasive - in this case, in a language that you may not have grown up with.&lt;/p&gt;

&lt;p&gt;My approach is always the same - find out who to talk to, and tell them what I need. Managers are usually more than willing to accommodate you if you ask - often the problem is them not knowing what you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Employment Overall
&lt;/h2&gt;

&lt;h3&gt;
  
  
  I Was "Let Go" Once
&lt;/h3&gt;

&lt;p&gt;I've been let go from one job. I'm gonna be honest - I technically chose to leave, but it was a dark situation to be in.&lt;/p&gt;

&lt;p&gt;When I was working at a pretty famous (in Japan) programming company, I had a medical issue. I won't get into the specifics, but the company that I was working for initially seemed supportive. I got medical leave, was put on government-paid benefits while we worked things out, etc.&lt;/p&gt;

&lt;p&gt;Unfortunately, after it became clear that I wouldn't be able to return to work for a while, my company decided to let me go. That's not the part that upsets me - I understand their position, I was still eligible for medical assistance, etc.&lt;/p&gt;

&lt;p&gt;The part that upsets me is that they &lt;em&gt;asked to talk directly to my doctor to confirm my situation&lt;/em&gt; despite my showing them appropriate medical documentation including a certified letter from my doctor. After my doctor said (rightfully so) that that was insane and illegal, they reduced my pay citing work performance - while I was on medical leave. If I returned to work before my medical situation was resolved, and had to take leave again, my new medical leave benefits would have been at the  reduced rate.&lt;/p&gt;

&lt;p&gt;They then asked me to leave. I did.&lt;/p&gt;

&lt;p&gt;I want to make it clear - there's a lot of nuance to this situation and this short description doesn't do it justice, but it does segue nicely into:&lt;/p&gt;

&lt;h3&gt;
  
  
  Excellent Job Security, But Not Guaranteed
&lt;/h3&gt;

&lt;p&gt;In Japan, it's almost impossible to fire someone. Company restructuring, a flagrant violation of valid company policy, or gross incompetence. That's about it.&lt;/p&gt;

&lt;p&gt;In reality, one of the following will happen - and I have seen some happen to people I know- in lieu of being fired.&lt;/p&gt;

&lt;p&gt;1) You will be pressured into leaving. This takes the form of management putting stress on you in any way they can until you quit. If this happens, leave. Not because you're wrong - because you're in demand and there are dozens of companies &lt;em&gt;lined up&lt;/em&gt; to hire you, so why work for shitty people that do this?&lt;/p&gt;

&lt;p&gt;For clarity - I have had an acquaintance of mine in HR talk casually to me about how they were actively doing this to someone. It is very, very real.&lt;/p&gt;

&lt;p&gt;2) Restructured. Not a lot to be said about this - if they downsize, which is pretty hard to do here, you can get downsized too. Not very common in tech, and you get paid unemployment anyway.&lt;/p&gt;

&lt;p&gt;3) Assigned meaningless jobs. I've never seen this happen in tech, but I'm aware of it in other fields. Boredom until you leave.&lt;/p&gt;

&lt;p&gt;4) Contract not renewed - this one's kind of interesting. Your contract isn't renewed citing some reason. If you think it's bogus, you can fight for damages. That's about it, the rest depends on your circumstances.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bad Bosses, Harassment, Options
&lt;/h3&gt;

&lt;p&gt;In America, I think it would be safe to say that a lot - the majority, even - of the workforce has worked for a boss that they did not think was a good boss. Some have even unfortunately - in one form or another - experienced harassment. In this regard, Japan is no different.&lt;/p&gt;

&lt;p&gt;I have worked under several kinds of bosses, in several kinds of companies. I have worked for people who are hands-off, micromanagers, powerful leaders, and people that I believe have no business being in an office, much less leading. I have worked for bosses that inspire me to be a better person, and bosses that inspire me to stay home.&lt;/p&gt;

&lt;p&gt;I want to talk about something more specific here, something that I've experienced once to a pretty serious degree - harassment.&lt;/p&gt;

&lt;p&gt;Japanese law defines a lot of different kinds of harassment. Power harassment, mental harassment, sexual harassment, etc., but the takeaway is this - there are a lot of ways to harass someone, and the government comes down on them all &lt;strong&gt;very&lt;/strong&gt; seriously. A company can get into serious trouble for inadequately investigating a single claim of harassment. &lt;/p&gt;

&lt;p&gt;I don't know how my experience would be different if I were a native Japanese person or not a man. All I can offer is what I've learned from my own experiences.&lt;/p&gt;

&lt;p&gt;If your boss does something you think is harassing, for example: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;talks to you differently than they do to your peers, but in a negative way&lt;/li&gt;
&lt;li&gt;assigns you impossible or disproportionate workloads&lt;/li&gt;
&lt;li&gt;sets specific rules that only apply to you&lt;/li&gt;
&lt;li&gt;ever is physical with you in any way that you find uncomfortable&lt;/li&gt;
&lt;li&gt;undermines you in front of your peers&lt;/li&gt;
&lt;li&gt;excludes you from social events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bring it up to your CEO or HR, whichever you feel more of a connection to. You have a ton of power and resources here, and the government takes these claims extremely seriously.&lt;/p&gt;

&lt;p&gt;In my own experiences, I have had two things that I can describe as harassment. One was a drunk boss - who I was very casual and good friends with - smack the back of my head in a disciplinary fashion in a bar. He came to his senses in a few seconds and apologized profusely. I don't think it's an accurate reflection of his character and chose to let it go.&lt;/p&gt;

&lt;p&gt;The second one was much longer, and concerned a manager who went from not liking me to outright hostility. I did what anyone in that situation should do - I documented it extensively and talked to the CEO one-on-one. The CEO was an outstanding person, got directly involved, and did his best to reel the manager in. Unfortunately, it didn't work well, and I chose to leave the company. The CEO said that the situation was unacceptable and apologized to me personally for the situation. Again, the circumstances are way more complicated than a short paragraph can do justice.&lt;/p&gt;

&lt;p&gt;I consider my experience with this type of harassment to be both unusual and well handled. The CEO was willing to pursue the matter further but I chose to leave because it wasn't worth it to me. There are way too many job opportunities and great companies to have to work with terrible people like that manager. Life's too short.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Really Good Parts!
&lt;/h2&gt;

&lt;p&gt;We just covered a lot of negative things - and we're going to cover more - but I want to switch it up.&lt;/p&gt;

&lt;p&gt;I think exceptional cases make for better reading. I think that negative press gets more attention. But overall my time in the tech sector in Japan (and Japan overall) has been good. Aggressive pay raises on job change, a ton of job security, energized teams, and fun people. Like anywhere, the company culture defines how much you're going to like your job, but I've worked with people and at places that I had a blast almost every day at work.&lt;/p&gt;

&lt;p&gt;Working in tech was the first time in my life that work just didn't feel like work. Most days, I don't even think about it - I just go to a different building and keep having fun. The only time that changed was when the workplace got unhealthy - see the above sections.&lt;/p&gt;

&lt;p&gt;It's common to go out drinking/eating at least occasionally with your coworkers. You don't have to drink if you don't want to - many people don't. Some have one drink and are completely smashed. Some will drink you under the table. You can go for a quick bite at a host of restaurants - obviously Japanese, but Italian, French, Burgers, Thai, etc. are all available. You can, contrary to popular belief, have house parties. I've done escape rooms with my coworkers, been invited to theme parks, and been asked to come rock climbing.&lt;/p&gt;

&lt;p&gt;A misconception that I feel compelled to address: I have never, &lt;em&gt;ever&lt;/em&gt; been excluded because I wasn't Japanese, or invited as a "token foreigner". If you ever get that feeling, you should work with different people because those are just shitty human beings.&lt;/p&gt;

&lt;p&gt;My coworkers have, at times, been very enthusiastic to practice their English. You will find that many programmers can read English pretty well. That being said, if you have native or fluent English, you will have a huge advantage in the field because you can read Stack Overflow and error messages with high comprehension. I'm not even kidding - Japanese Stack Overflow is hot garbage, and this will be like a superpower for you assuming you can translate that knowledge back into Japanese if someone asks you the reasoning behind your code.&lt;/p&gt;

&lt;p&gt;The company that I'm currently freelancing for has a policy that you should leave when you're done. I have seen people come in at 10 am and leave at 3 pm, after taking an hour-something lunch. There is no stigma, no penalty - just do your job and have fun, and go home when you're done for the day.&lt;/p&gt;

&lt;p&gt;I have never had someone criticize me, to my recollection, for taking longer than an hour at lunch. I have been out for two hours at a time, with no issue.&lt;/p&gt;

&lt;p&gt;I regularly take 30-minute breaks to think, stretch my legs, etc., and except for a particularly difficult person, have not had an issue, ever.&lt;/p&gt;

&lt;p&gt;A serious weakness of mine is that for a large part of my tech career I was chronically tardy. Now I work for companies with no set schedule and remote work (and, ironically, get up at ~7:30 am every day) - but I have never had that be a serious issue for me. Like most things, negotiate it early and be honest. Monolithic companies tend to be less forgiving on this front, however.&lt;/p&gt;

&lt;h2&gt;
  
  
  Japanese Attitudes Towards People Who Are Not Japanese
&lt;/h2&gt;

&lt;p&gt;Disclaimer: this is a gray area that I have pretty strong feelings about. This is the most opinionated part of this article, and I totally understand if you don't agree with what I'm about to say. It certainly isn't essential reading and is more of a rebuttal to something I see endlessly regurgitated online. If that doesn't interest you, just hop on over to the Overtime section that follows.&lt;/p&gt;

&lt;p&gt;I often hear other non-Japanese people say "You will always just be seen as a foreigner". No matter how good your Japanese is or what you know about the culture, no one will make deep friendships with you or you will always be acknowledged as different. I find that often, but not always, this sentiment comes from people who don't have very good Japanese. I want to make something clear.&lt;/p&gt;

&lt;p&gt;If you have non-conversational Japanese, that could likely be the case. If we're talking about the government's infamous perspective that people born and raised in Japan aren't Japanese unless a parent was, that is correct (and tremendously shitty for those people at times). If you mean that every time you go to a store, people will assume you don't speak Japanese until proven otherwise / you'll get the English menu because they assume you need one to have a pleasant experience / people will try to practice their English on you as soon as you meet - I am in 100% agreement.&lt;/p&gt;

&lt;p&gt;But if you mean that no matter how good you are at Japanese and what kind of people you hang out with, that you'll always be seen as "the foreigner", the issue is more nuanced than that.&lt;/p&gt;

&lt;p&gt;I can't speak to other people's experiences, but I live a lot of my personal and work life using Japanese. I learned in Osaka, so I speak like a person from that area, and I can tell you with absolute certainty that people have straight-up &lt;em&gt;forgotten that I wasn't Japanese&lt;/em&gt; and I don't look even remotely Japanese. Not even a little.&lt;/p&gt;

&lt;p&gt;I've had more than one friend be surprised when we went out and they handed me the English menu, and when I told them it's because I don't look Japanese they laughed and said they forgot.&lt;/p&gt;

&lt;p&gt;My friend was asked by a coworker if he was going to vote in Japan's elections. When he said he couldn't, they asked why. He had to remind them that he isn't a Japanese national. He doesn't look "traditionally Japanese", but they assumed he at least had voting rights.&lt;/p&gt;

&lt;p&gt;Essentially, if you find yourself in a situation where you feel like you'll never be accepted on the same level because your skin or culture is different, that depends on how you mean it. If you mean that people will assume you aren't from around there at first impression, then of course - we assume a lot about people from the way they look or act.&lt;/p&gt;

&lt;p&gt;But if you mean that Japanese people you've gotten to know won't accept you for one of their own, that has not been the case in my experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overtime
&lt;/h2&gt;

&lt;p&gt;Oh boy, the big one.&lt;/p&gt;

&lt;p&gt;I've seen it all over the spectrum. I work, on average, about three or four hours of overtime. &lt;strong&gt;Per year&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I also personally had someone that called me - in distress - because their company had them working weekends and going home on the last train, every day. This company is known for being particularly abusive during the busy times of the year, and that's certainly not a rare story.&lt;/p&gt;

&lt;p&gt;I'm about to follow this with what I think is going to easily be the most controversial, polarizing part of this whole article.&lt;/p&gt;

&lt;p&gt;If you work in Osaka or Tokyo, in tech, and you regularly have overtime that makes you unhappy, that is most likely your fault. Hear me out. &lt;/p&gt;

&lt;p&gt;Every contract that I've seen in Japan includes a certain amount of "prepaid overtime." This means that every month, for the first x hours of overtime, you don't make anything extra. There are exceptions - significant weekend work, work past 10 pm, etc. can either get you paid more or get you a different day off in lieu. From what I'm aware, even this is a step up from some countries - like the states - where you don't make anything extra at all if you're a salaried worker above a certain pay bracket.&lt;/p&gt;

&lt;p&gt;However, if your employer is using this clause to regularly have you work overtime, &lt;em&gt;leave&lt;/em&gt;. Japan has an extremely well-developed public transport system, remote opportunities, and a shortage of tech jobs that can land you five interviews per day. I'm not exaggerating - per day. There is no fear of visa renewal for tech companies - it involves them printing off a few pieces of paper about company information, stamping something, and then waiting a few weeks. Many are even willing to sponsor outright. You'll find that there are plenty of companies that will strongly encourage you to leave either on time or early.&lt;/p&gt;

&lt;p&gt;I have found that the best way to deal with it is to be really, really upfront. Ask your interviewer what their day is like - what time do they usually come in, what time do they usually leave. If their answer isn't something along the lines of an enthusiastic "I love to leave on time to pursue my hobby of crab-shell collecting", make it very clear that you leave on time as a matter of principle. Actually, make it clear that you leave on time regardless. If that was a dealbreaker, no problem. Go to your other four interviews for that day with places that look cool to work for.&lt;/p&gt;

&lt;p&gt;It's a problem in the country - one that's gotten much better in recent years, but a problem just like anywhere else. The difference is, in tech you can leverage enormous demand for your skills to make sure it isn't &lt;em&gt;your&lt;/em&gt; problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interviews and Perception of Programmers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Attitudes Towards Programmers
&lt;/h3&gt;

&lt;p&gt;When I tell people that I'm a system engineer ("SE" as it's called here), I usually get the same sort of reaction I imagine programmers get elsewhere. People who have been in the game might talk shop a bit, people who don't get what you do will treat it with reactions ranging from "you must be smart" to a glazed look and a polite nod.&lt;/p&gt;

&lt;p&gt;From a corporate perspective, attitudes towards programmers tend to take one of two perspectives. Either programming is like a blue-collar job where you throw people into the code factory for their 10-hour shift, or programmers are a very expensive type of wizard that needs to be enticed with money and benefits to work their magic. Games and sales seemed to think the first, engineering firms and tech-driven products the second.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interviews, Competition, Company Size
&lt;/h3&gt;

&lt;p&gt;Disclosure - I love interviews. Even when I don't know the answer to a question, I get to learn a ton about something I've never experienced. Plus, if you do know the answer, you're getting paid to be a show-off (assuming you get the job), so revel in one of the few times in your life where that will be socially acceptable.&lt;/p&gt;

&lt;p&gt;You will often hear that "You need to work in one place your whole life in Japan." That system has been falling out of use for &lt;strong&gt;30 years&lt;/strong&gt; but I see it everywhere. Workers have been made replaceable, seen by an increase in contract work. The shift was so intense that it forced the government to make an initiative that if you renew someone's contract for five years, you need to make them a permanent employee. Yes, there are still many companies you can work at for life. You can also change jobs once a year and be fine.&lt;/p&gt;

&lt;p&gt;There is very, very little competition because the lack of skilled talent is enormous. If you're just starting out, you'll have an advantage if you have robust projects and fluent English, but if you have actual good domain knowledge in your area? No shortage of jobs. You can  get a job here starting at 400k (~4k USD) a month if you put the work in and speak Japanese. If you already have experience and have the chops to demonstrate that, you can pull down significantly more.&lt;/p&gt;

&lt;p&gt;I don't have any kind of interview prep advice because I'm sure the way you prep will matter more on your personality than anything else, but when you're in the interview, there are a few things you absolutely should do.&lt;/p&gt;

&lt;p&gt;Be honest. Don't mind overtime? Say that. Hate it? Say that too. Salary important for you? &lt;a href="https://www.kalzumeus.com/2012/01/23/salary-negotiation/" rel="noopener noreferrer"&gt;Negotiate&lt;/a&gt;. People say Japanese people don't negotiate. I can tell you with absolute confidence from being on the hiring side and working with the decision-makers, as well as being the interviewee - when HR gives you an offer, that is not their best offer.&lt;/p&gt;

&lt;p&gt;I have negotiated higher salaries, starting bonuses, more vacation days, and different working hours. You can do this - just do it in your style. Don't be afraid to ask over email, compare offers, etc.&lt;/p&gt;

&lt;p&gt;Avoid big titan companies (Rakuten, Line) unless salary and reputation beat everything for you because you don't get to negotiate things like flexible job hours and perks. Medium corporations offer a nice balance of salary and perks, startups are often all perks and you have a good chance to negotiate extra things.&lt;/p&gt;

&lt;p&gt;In general, if you want something or won't do something, bring that up. For example, I make it very clear in all my interviews that I am a backend specialist, and I don't know frontend - I have basic familiarity with it, I can reason my way around the concepts, but if you asked me to write a webpage the company would grind to a halt.&lt;/p&gt;

&lt;p&gt;Most companies do either basic code reviews (fizzbuzz) or some online code test. The online code tests are usually like "Array in an array, print as a grid" type of thing. True story - I was doing a timed code test, screwed up a comma in the output, and didn't have time to fix it before submitting. I submitted it and sent a follow-up email explaining the quick change I would make to have it pass.&lt;/p&gt;

&lt;p&gt;At an interview later that week one person said they saw it and had no issue, the other said they didn't even check the test results because they already decided to hire me.&lt;/p&gt;

&lt;p&gt;I had a cool interview that was a general whiteboard interview where they asked me to build an architecture for an API. The API was to count fan votes that were cast for their favorite member of a music group during a live broadcast of said group. The catch was that you could only cast a vote if you had a unique code from a cd that you had purchased. That was a blast.&lt;/p&gt;

&lt;p&gt;The hardest code review I ever got was at an English-speaking company, I loved it but I didn't know a good amount of the front-end questions.&lt;/p&gt;

&lt;p&gt;Line (Chat app and game company) wanted me to take a test to even be able to email their recruiter.&lt;/p&gt;

&lt;p&gt;My experiences with Rakuten have been weird - they invited me to a hiring party for mobile app developers, so I went because of free food. It was a fun party but I had two years of experience and none of it was in mobile apps. They wanted three years of app development experience. Weird situation.&lt;/p&gt;

&lt;p&gt;Lastly, on the time it takes for closing an offer. I find that the typical turnaround from the first message to offer is about two weeks. Some places are a bit longer, some are a single interview, but that's usually the case. You can expect a casual first interview, at least one follow-up, and then a final offer. It is not uncommon at all to meet the CEO for the final interview - it's often merely a formality, but they frequently sign off on every hire.&lt;/p&gt;

&lt;h3&gt;
  
  
  Working with Recruiters
&lt;/h3&gt;

&lt;p&gt;I have had the pleasure of working with a handful of good recruiters - just all-around excellent people. I became friends with two of them - one Japanese and one Swedish. I have also had recruiters message me on LinkedIn that have actually read my profile/website.&lt;/p&gt;

&lt;p&gt;That being said - much as in America, the vast majority of recruiters are hot trash at their job. Ghosting, mass spam messages, unsolicited friend requests to avoid paying LinkedIn mail fees. It's no better on Japanese platforms, either - mountains of spam that was so bad that I had a template letter (much as I do on LinkedIn) which says "Read my profile, I have x terms". This is often met with silence (LinkedIn) or an apology and an offer to keep in contact if those terms can be met (Japanese platforms).&lt;/p&gt;

&lt;p&gt;I have also worked with excellent job sites that I used to find jobs that met my terms. They do exist - just make sure that the site isn't recruiter-oriented. Smaller sites tend to be better, especially ones that follow the format of "Employer posts a job, you can click to show interest."&lt;/p&gt;

&lt;p&gt;For people seriously looking for jobs in Japan -&lt;br&gt;
Bizreach is full of spam. Avoid.&lt;br&gt;
Wantedly is usually for companies that have a ton of passion and criminally low salaries that take advantage of new grads. I directly saw this happen. You can find good things there, just be careful.&lt;br&gt;
Gaijinpot programmer jobs seem to have horrible conditions, but I imagine that's because they cater to an audience that might not be expected to have a lot of Japanese skill.&lt;/p&gt;

&lt;h3&gt;
  
  
  Freelancing
&lt;/h3&gt;

&lt;p&gt;Freelancing is actually surprisingly straightforward. I don't know if you can start as a freelancer without an already existing visa, but you just go to a freelancing company (you 100% need Japanese for this) and tell them you want to freelance. They do the rest of the work helping you find companies and arranging interviews.&lt;/p&gt;

&lt;p&gt;Finding work as a freelancer is fast, too. Most companies wanted me to start working as soon as I could.&lt;/p&gt;

&lt;p&gt;The primary advantage that I found in freelancing is you can work non-5-day weeks easily and because you don't get paid days off and included insurance you can get a higher salary relatively easily. Lots of freelance jobs have remote work as well.&lt;/p&gt;

&lt;p&gt;I work three to four days a week right now, and I love it. I worked a week in the Philippines and have long weekends every weekend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Jobs That You Can Do Without Japanese
&lt;/h3&gt;

&lt;p&gt;Easing back into meatier topics, there are a few kinds of jobs that you can do without speaking Japanese in Japan, and it comes down to one basic thing - companies that have strong international ties.&lt;/p&gt;

&lt;p&gt;This typically means a few choices. If you want a huge salary you should work at a bank, a Japanese branch of a global company, or any similar company owned by foreign interests. If you're interested in passion over money, there are English-only startups that sponsor visas- they are few and far between, but they exist. If you want something in the middle, Fintech is a good middle balance - decent salary, good passion.&lt;/p&gt;

&lt;p&gt;All of the above require you to be good at what you do - if you don't have sufficient experience, it's very unlikely that you'd be hired over an inexperienced-but-English-proficient local.&lt;/p&gt;

&lt;h2&gt;
  
  
  Money, Visa, Location
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Salary and Cost Of Living
&lt;/h3&gt;

&lt;p&gt;I want to get a frame of reference before we start talking about salary - and we will, in very concrete detail, with numbers. There is an opinion that in general, Japan pays programmers poorly and Tokyo is crazy-expensive.&lt;/p&gt;

&lt;p&gt;We need to tackle these things one by one, and I'm going to start with the "Tokyo is crazy-expensive" one first.&lt;/p&gt;

&lt;p&gt;You can live in a great apartment for very cheap (well less than 100k yen/$1k per month) if you're willing to commute an hour or more on trains. I mean like shiny, attractive apartments with a ton of space. Houses with parking spaces. You can also pay easily more than that for a single room about 10 minutes from Shibuya (a main hub of Tokyo).&lt;/p&gt;

&lt;p&gt;Japanese apartments are undeniably smaller than their western counterparts. Tokyo is no exception, and neither was Osaka. That being said, in Osaka I lived in a one-bedroom, living room, dining/kitchen for 60k (~$600)/month. In the greater Tokyo area, I've lived an hour from work in a two-bedroom, dining-kitchen with a living room for about 90k (~$900) and a one-bedroom dining-kitchen with a living room in a more expensive, nicer area of Tokyo for 120k (~$1,200).&lt;/p&gt;

&lt;p&gt;Right now, I live in an apartment that was built the month before I moved in. It's 30 minutes from Shibuya (4-minute walk to my station). 10 minutes to a different close-by main station. One bedroom, separate sunlit study, combo living-dining room, and a bar-kitchen that runs 155k (~$1,550)/month. From what I've gathered that is insanely cheap compared to NYC or the Bay Area. That being said, those are still big numbers depending on your fiscal status.&lt;/p&gt;

&lt;p&gt;I move next month (working remote means I can live farther now for cheaper) to a slightly bigger place with the same layout and parking for about half the cost.&lt;/p&gt;

&lt;p&gt;As far as where to live - Osaka for the people and culture, Tokyo for the pay and job opportunities. I was very happy in Osaka, but I hit a pay ceiling after my first job. Tokyo has a massive amount of work and good pay to boot.&lt;/p&gt;

&lt;p&gt;Now, salary and how Japan pays programmers.&lt;/p&gt;

&lt;p&gt;I'm going to list all of my jobs and the salary that I made. This doesn't include personal jobs, my side business, etc.&lt;/p&gt;

&lt;p&gt;Starting - Games. Osaka. 280k(~$2.8k)/mo. In Osaka as a single male, this was enough to have an okay standard of living.&lt;br&gt;
Next year - Outsourcing Shop. Yokohama (near Tokyo) - 400k (~$4k)/mo. This was pretty comfortable, but not great.&lt;br&gt;
Next year - Engineer at a sales and recruiting place. Tokyo. 708k (~$7k)/mo, with 300k (~$3k) signing bonus to cover moving costs. A comfortable lifestyle.&lt;br&gt;
Now - Freelancer. My current rate depends on the job, but I charge about 750k (~$7.5k)/mo, some jobs could cost more, rarely less. Comfortable lifestyle. Note that this is technically less because of the way that taxed and health insurance work here.&lt;/p&gt;

&lt;p&gt;At each job, I went home and studied/built things that I wasn't doing at work. As soon as I had studied the essentials of whatever tech we were using at the office, I would chase some side project or build something for money. As a result, my salary may be higher than "normal" because of my deeper skillset.&lt;/p&gt;

&lt;p&gt;At each step, I negotiated. From job one. If you don't mind working in more traditional "10-7 C++ or C#" types of jobs, there are plenty that break 10m ($100k)/yr.&lt;/p&gt;

&lt;p&gt;I found that job offers start to thin around 8m ($80k) a year. This is where you'll have fewer interviews because fewer companies can afford you - this is a sign you're rising above the market average.&lt;/p&gt;

&lt;p&gt;There is this commonly touted number online that engineers make 100K+ right out of graduating. What is less touted is the number of those that still need a roommate to live close to work.&lt;/p&gt;

&lt;p&gt;Seattle, NY, Bay-area, you can expect to make a lot of money, and pay a lot in rent. Tokyo is not a cheap place to live, but the only real difference is apartment size. By the square foot, Tokyo is very expensive. Apartments tend to be smaller, but I can live without roommates comfortably. I have tons of space and live in a relatively expensive area of Tokyo - other similar places would have set me back much less but be further out. There is no Tokyo hustle-and-bustle in my area - no train sounds, no traffic noise. Aside from me, my area is super quiet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Apartments
&lt;/h3&gt;

&lt;p&gt;Ugh. I have had such a mixed bag with this. Hunting for them has been JAM PACKED with racism at times, and incredible easy at others. Finding a job is fairly trivial, finding a place to live was insane.&lt;/p&gt;

&lt;p&gt;I am in no way exaggerating when I say that some of the moving experiences I had in Tokyo and Sendai were the most discriminated against I have ever been in my life. When house hunting once, out of the exactly 30 apartments that I wanted to see in Tokyo, only &lt;strong&gt;3&lt;/strong&gt; would even let me look. The rest straight-up said non-Japanese not welcome. Japanese skill, salary, relationship status - none of it mattered. The apartment I got I liked, though.&lt;/p&gt;

&lt;p&gt;Outside of that specific time, every other time I've done this in either Tokyo or Osaka it was really easy and super cool. The real estate agents were helpful (if your real estate agent isn't aggressively finding places for you and calling them, go across the street to another one). Every apartment was super cool about having me move in except for one oddball that wanted me to be double-insured because I wasn't Japanese. I laughed and said no. In general, they pretty much asked: "Does he speak Japanese?" They didn't ask about my salary or anything. I think a few asked how long I'd been/be in Japan, and if I had some kind of job already, but that was it. My Osaka one wanted to know how long my visa was good for - and threw in an air conditioner for free because they thought I was a fun person.&lt;/p&gt;

&lt;p&gt;Unfortunately, my next move to the countryside involved all of my candidate homes allowing me to come to take a look, but a Japanese person would have to be my guarantor or I couldn't move in (be double insured). They made it very clear that it was because I was not Japanese. I've heard that the reason may be that it's the countryside where there are fewer non-Japanese, and I'm inclined to believe that reason.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Just like every other country, it's a mixed bag. You'll have companies that you dislike strongly, you'll have companies that you love.&lt;/p&gt;

&lt;p&gt;You'll have people that frustrate you endlessly, and people that will leave positive lasting impressions on you for the rest of your life.&lt;/p&gt;

&lt;p&gt;You'll feel underpaid, you'll feel overpaid. You have expensive apartments in the heart of the city, and cheap ones on the edge.&lt;/p&gt;

&lt;p&gt;You'll make well more than the average earner in Tokyo, and have a comfortable life if you can speak Japanese or have intense skill.&lt;/p&gt;

&lt;p&gt;Life here is really good - for me. Your experience might be different, but from what I've seen it's really the same here as it is everywhere else.&lt;/p&gt;

&lt;p&gt;It's what you make of it.&lt;/p&gt;




&lt;p&gt;If you have questions or comments about living in Japan, please leave a comment and I'll do my best to get back to you.&lt;br&gt;
Also, I now have a Twitter! My DMs are open, so shoot me a message if you need anything.&lt;/p&gt;

</description>
      <category>japan</category>
      <category>salary</category>
      <category>softwareengineering</category>
      <category>culture</category>
    </item>
    <item>
      <title>How to use REST clients / native apps to make Shrine client uploads and S3 work for you (no Javascript, just backend)</title>
      <dc:creator>Rob Sherling</dc:creator>
      <pubDate>Tue, 26 Feb 2019 04:52:18 +0000</pubDate>
      <link>https://dev.to/rob117/how-to-use-rest-clients--native-apps-to-make-shrine-client-uploads-and-s3-work-for-you-no-javascript-just-backend-322h</link>
      <guid>https://dev.to/rob117/how-to-use-rest-clients--native-apps-to-make-shrine-client-uploads-and-s3-work-for-you-no-javascript-just-backend-322h</guid>
      <description>&lt;h1&gt;
  
  
  Shrine and AWS
&lt;/h1&gt;

&lt;p&gt;I wanted a direct upload (client uploads a file, and then passes a link to the server) solution for a new app that I'm writing. The backend was going to be shared amongst a lot of different services. I looked around - Shrine seemed the most promising, so I went for it.&lt;/p&gt;

&lt;p&gt;A lot of this info just applies to S3 direct uploads and API signing in general, so if that confuses you, read it anyway.&lt;/p&gt;

&lt;p&gt;I didn't want to use a front end solution with a premade library, because I was trying to figure this out for a mobile app. I think I did - if you can do it in REST, you can do it anywhere.&lt;/p&gt;

&lt;p&gt;I'm writing this as I have &lt;em&gt;just&lt;/em&gt; figured out how to make Postman/Insomnia work, and I'm not gonna lie - I'm pretty annoyed. It really should not have taken days to get an easy example of how to use Shrine without subscribing to GoRails (I did) or using the Uppy library (Not an option a lot of the time).&lt;/p&gt;

&lt;p&gt;Quick aside - While GoRails really wasn't worth it for me and I cancelled almost immediately when they used JS as well, Chris (one of the tutorial guys) was super cool and easy to understand in his videos. Not knocking the service as a whole, they just didn't have what I needed. Well, except for the sweet, sweet test image I used (Google "Money Sloth").&lt;/p&gt;

&lt;p&gt;Okay. On to the main part.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Set Up - The Break Down
&lt;/h2&gt;

&lt;p&gt;Setting up Shrine is actually pretty straight forward for the server side. I'm going to skip the entire thing because the tutorials are really straight forward, I just want to explain the AWS part and give you a quick tip. Make sure to set up your bucket with CORS like shrine tells you, except insofar as we are concerned, leave the accepted domains to &lt;code&gt;*&lt;/code&gt; because we're rest-client testing.&lt;/p&gt;

&lt;p&gt;Quick tip - if you're hesitant to use shrine because you want to use devise or some kind of auth solution to protect your presign endpoints (and you should!), rest easy. &lt;a href="https://github.com/shrinerb/shrine/wiki/Authenticating-Endpoints"&gt;The docs are straightforward&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We use POST over PUT because of a buncha reasons that are best articulated &lt;a href="https://stackoverflow.com/questions/44341734/aws-s3-should-i-use-post-or-put-requests-to-upload-a-file"&gt;here&lt;/a&gt; (read the link, read the answer).&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick overview of how it all works
&lt;/h3&gt;

&lt;p&gt;You want the client to upload images to S3 without your server having to handle them. However, if you just let anyone upload anything, you're going to have a terrible day some day when you find out that someone has been using your AWS account to store their exotic collection of Giraffe Dancing videos. All 20 terabytes of it.&lt;/p&gt;

&lt;p&gt;Signed posts let you avoid that problem by doing the following, in order - &lt;/p&gt;

&lt;p&gt;1) Be authenticated and ask your server for permission to upload a file. You tell them what type of file (you CAN tell them the filename, but no. No need). For example, "I will upload a jpeg."&lt;/p&gt;

&lt;p&gt;2) Shrine runs its magic and generates a BUNCH of specific stuff to let you do that. Like, and I am serious, &lt;strong&gt;8 things&lt;/strong&gt; that you will need to upload the file in addition to the file itself.&lt;/p&gt;

&lt;p&gt;3) You take that mountain of information and do the upload.&lt;/p&gt;

&lt;h3&gt;
  
  
  ERROR LIST
&lt;/h3&gt;

&lt;p&gt;If you see one of these errors, here is how you fix it:&lt;/p&gt;

&lt;p&gt;Some error related to expired request - Expiration time has passed, do it again.&lt;br&gt;
Some error related to 403 expired request policy something - your server time is messed up. In my ABSURD case, I had updated Postgresql through homebrew which screwed up the database clock. I restarted. Solved.&lt;/p&gt;

&lt;p&gt;Some error related to signing - One of your headers is messed up. Of note - some policies, when generated, have an &lt;code&gt;=&lt;/code&gt; sign at the end of them. Make sure that is written / deleted correctly when copy pasting.&lt;/p&gt;

&lt;p&gt;Some error that says "Policy something something &lt;code&gt;"eq", "Some header", "some value"&lt;/code&gt;" - you're missing that value. Put that value IN THE FORM DATA with the key/value that it says in the error. i.e. "You are missing &lt;code&gt;eq, content-type, image/jpeg&lt;/code&gt; go into your form data and add key:content-type, value:image/jpeg&lt;/p&gt;
&lt;h3&gt;
  
  
  Before we even start
&lt;/h3&gt;

&lt;p&gt;The post request that you send to S3 must be form-data. You don't need any headers, at all, because the form data will have everything you need. It must, obviously, be a post request. This next part is super, super, super important: &lt;strong&gt;the key for the object to be stored in the bucket MUST COME FIRST, and the attached file MUST COME LAST&lt;/strong&gt;. Your post will not work if that doesn't happen. Also, once you write the whole request, if you aren't getting the file to post go ahead and check the actual curl code behind the request. Look for the part that says &lt;code&gt;"filename="&lt;/code&gt; and make sure the filename is actually attached. Mine didn't until I upgraded to the latest version of postman.&lt;/p&gt;
&lt;h3&gt;
  
  
  Now we can start
&lt;/h3&gt;

&lt;p&gt;Okay. Wow. Let's actually start this.&lt;/p&gt;

&lt;p&gt;First send a simple get request to your presign endpoint on your server. I set mine to &lt;code&gt;http://localhost:3000/api/s3/params&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The get request should have one query parameter - "type: "&lt;/p&gt;

&lt;p&gt;For example, if your rails code looks like this in your presign endpoint(and it should, more or less):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Shrine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;storages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;cache: &lt;/span&gt;&lt;span class="no"&gt;Shrine&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Storage&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;prefix: &lt;/span&gt;&lt;span class="s1"&gt;'cache'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;s3_options&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="ss"&gt;store: &lt;/span&gt;&lt;span class="no"&gt;Shrine&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Storage&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;s3_options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="no"&gt;Shrine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plugin&lt;/span&gt; &lt;span class="ss"&gt;:activerecord&lt;/span&gt;
&lt;span class="no"&gt;Shrine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plugin&lt;/span&gt; &lt;span class="ss"&gt;:restore_cached_data&lt;/span&gt; &lt;span class="c1"&gt;# refresh metadata when attaching the cached file&lt;/span&gt;
&lt;span class="no"&gt;Shrine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plugin&lt;/span&gt; &lt;span class="ss"&gt;:determine_mime_type&lt;/span&gt;
&lt;span class="no"&gt;Shrine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plugin&lt;/span&gt; &lt;span class="ss"&gt;:presign_endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;presign_options: &lt;/span&gt;&lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'filename'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;type&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'type'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;content_disposition: &lt;/span&gt;&lt;span class="no"&gt;ContentDisposition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# set download filename&lt;/span&gt;
    &lt;span class="ss"&gt;content_type: &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# set content type (required if using DigitalOcean Spaces)&lt;/span&gt;
    &lt;span class="ss"&gt;content_length_range: &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# limit upload size to 1 MB&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the lines&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'filename'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;type&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'type'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means that our GET request should use type as the key. If you set it to something like &lt;code&gt;type     = request.params['content']&lt;/code&gt; then the key name should be &lt;code&gt;content&lt;/code&gt;. Regardless, a valid param might look like &lt;code&gt;type=image/jpeg&lt;/code&gt;(url escaped by your REST client, of course)&lt;/p&gt;

&lt;p&gt;We actually don't need the filename param. You can include it, but if the filename param doesn't match exactly it won't send. So if you have a picture of say, &lt;em&gt;a gorgeous money sloth&lt;/em&gt; and you want to name it something like MONAY.jpg, if you send the filename as MONAY.jpg and then attach that from your rest client, you won't get it to work. This is because your rest client will attach it as &lt;code&gt;/User/me/Documents/MONAY.jpg&lt;/code&gt;, and those names do not match when you upload.&lt;/p&gt;

&lt;p&gt;Anyway.&lt;/p&gt;

&lt;p&gt;Okay, so after you send your straightforward get request (make sure to include auth headers if you're using an auth solution), you'll get back something that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "fields": {
    "key": "cache/ac48d4a7764610579df3f26c316f3947",
    "Content-Disposition": "inline",
    "Content-Type": "image/jpeg",
    "policy": "eyJleHBpcmF0aW9uIjoiMjAxOS0wMi0yMlQwOTo1MjozMloiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJ2aXNpb24td2ViLWltYWdlLWRldiJ9LHsia2V5IjoiY2FjaGUvYWM0OGQ0YTc3NjQ2MTA1NzlkZjNmMjZjMzE2ZjM5NDcifSx7IkNvbnRlbnQtRGlzcG9zaXRpb24iOiJpbmxpbmUifSx7IkNvbnRlbnQtVHlwZSI6ImltYWdlL2pwZWcifSxbImNvbnRlbnQtbGVuZ3RoLXJhbmdlIiwwLDEwNDg1NzZdLHsieC1hbXotY3JlZGVudGlhbCI6IkFLSUFKT0VSVTNMTkFaSExOUFRBLzIwMTkwMjIyL2FwLW5vcnRoZWFzdC0xL3MzL2F3czRfcmVxdWVzdCJ9LHsieC1hbXotYWxnb3JpdGhtIjoiQVdTNC1ITUFDLVNIQTI1NiJ9LHsieC1hbXotZGF0ZSI6IjIwMTkwMjIyVDA4NTIzMloifV19",
    "x-amz-credential": "********/20190222/ap-northeast-1/s3/aws4_request",
    "x-amz-algorithm": "AWS4-HMAC-SHA256",
    "x-amz-date": "20190222T085232Z",
    "x-amz-signature": "769489a916a228d142e9bff18688bf45f44c7e77eac81f4797b8c48e3b8ab756"
  },
  "headers": {},
  "method": "post",
  "url": "https://BUCKETNAME.s3.ap-northeast-1.amazonaws.com"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't panic. One by one - &lt;/p&gt;

&lt;p&gt;key - what shrine named the object in s3 for you.&lt;br&gt;
content-disposition - &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition"&gt;Irrelevant for us, but docs anyway&lt;/a&gt;. Just copy it.&lt;/p&gt;

&lt;p&gt;Content-Type - yep, this is what we said our type was.&lt;br&gt;
Policy - just copy it. This tells Amazon what is permitted to be uploaded, and how.&lt;/p&gt;

&lt;p&gt;The next four that start with x-amx-* - these four, together, are part of the Amazon V4 signature protocol. They tell Amazon that the request is legitimate. That's really it, just make sure to copy them correctly every time and you won't have issues.&lt;/p&gt;

&lt;p&gt;Headers - this is messed up. Ignore these entirely. I spent way, way too long messing with headers before I realized they were red herrings.&lt;/p&gt;

&lt;p&gt;Method - Post it.&lt;br&gt;
Url - Post it to this Url.&lt;/p&gt;

&lt;p&gt;Okay, now I'm just going to go ahead and show you what your client needs to look like.&lt;/p&gt;

&lt;p&gt;If you are using postman, copy your URL into the url bar and set it to post. Click the body tab, and set it to form-data. Now click the bulk-edit orange text in the upper-right hand corner, and past this in -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;key:YourKeyHere
x-amz-credential:YourCredentialsHere
policy:YourPolicyHere
x-amz-algorithm:AWS4-HMAC-SHA256
x-amz-date:YourDateHere
x-amz-signature:YourSigHere
Content-Disposition:inline
Content-Type:YourContentTypeHere

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just replace the values with your values, &lt;strong&gt;add the file at the bottom&lt;/strong&gt;and you're golden. Or, if you are using another rest client, use the above keys and fill in your own values a bit slower because you won't have bulk copy-paste, so you need to go line by line. then &lt;strong&gt;add the file at the bottom&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Okay. Now, hit send. If everything worked, you should get back a 204, and the image is in your bucket. If everything did NOT work, weep and look at the error list above, or post a comment and I'll do my best to troubleshoot on the roughly one day/week that I read comments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using that response to save the file
&lt;/h3&gt;

&lt;p&gt;This one is actually pretty simple. Make sure that you have the &lt;code&gt;:restore_cached_data&lt;/code&gt; plugin available (see my Shrine code, above). In your Ruby code, once you've authenticated and such, call the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ModelInQuestion.update_attributes(attachment_name: {id: "ID OF S3 OBJECT", storage: "cache"}.to_json)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For example, if your object is something like &lt;code&gt;books&lt;/code&gt; with your image uploader that you set up in the folder set to &lt;code&gt;image:&lt;/code&gt;, assuming your AWS response looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x-amz-id-2 → stuff
x-amz-request-id → stuff
Date →Sat, 23 Feb 2019 10:04:20 GMT
ETag →"daa14e86f803fca11a1baff256fa259b"
Location →https://bucket.s3.ap-northeast-1.amazonaws.com/cache%2Fdabe031bee03ae8365e2ec48b523bb33
Content-Length →0
Server →AmazonS3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You want to call this code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;YourBookModelHere.update_attributes(image: {id: "dabe031bee03ae8365e2ec48b523bb33", storage: "cache"}.to_json)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We get that image ID from the end of the location tag. The documentation actually has a regex that parses that for you - &lt;a href="//image:%20%7Bid:%20"&gt;last paragraph&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quick note - I found that if you want to pass the string in and use the regex, you're going to have to take the url string, restore it, and then remove the beginning of the line character from the regex.&lt;/p&gt;

&lt;p&gt;Or, in code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;URI.decode(params[:link])[/cache\/(.+)/, 1]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And now when you run that update attributes, you should get this cool thing back:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;ImageUploader&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;UploadedFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0x00007fbb995c8eb8&lt;/span&gt;
&lt;span class="vi"&gt;@data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;"e68f1910d4fb723d6538383dbbac5f78"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s2"&gt;"storage"&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s2"&gt;"metadata"&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"filename"&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"size"&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;92931&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"mime_type"&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;"image/jpeg"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;note that if your mime_type is nil, you need to add &lt;code&gt;Shrine.plugin :determine_mime_type&lt;/code&gt; to your plugin list.&lt;/p&gt;

&lt;p&gt;Now, if you call &lt;code&gt;yourbook.image_url&lt;/code&gt;, you get a super-cool signed url that lasts for 15 minutes!&lt;/p&gt;

&lt;p&gt;Lastly, if you want to set your expiration time for something a bit more narrow than 15 minutes (say, 5 minutes), use the default_url_options plugin -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="c1"&gt;# 90 seconds to use the upload URL, 5 minutes to use the GET url&lt;/span&gt;
  &lt;span class="no"&gt;Shrine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plugin&lt;/span&gt; &lt;span class="ss"&gt;:default_url_options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;cache: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;expires_in: &lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="ss"&gt;store: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;expires_in: &lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Huge shout out to &lt;a href="https://github.com/janko"&gt;Janko&lt;/a&gt; the gem maintainer for all of his help in the Shrine Google group. I recommend going over there if you have questions - he's very friendly!&lt;/p&gt;

</description>
      <category>shrine</category>
      <category>aws</category>
      <category>postman</category>
      <category>insomnia</category>
    </item>
    <item>
      <title>How to REALLY set up a React Native environment on Mac</title>
      <dc:creator>Rob Sherling</dc:creator>
      <pubDate>Thu, 09 Aug 2018 11:39:10 +0000</pubDate>
      <link>https://dev.to/rob117/how-to-really-set-up-a-react-native-environment-on-mac-248h</link>
      <guid>https://dev.to/rob117/how-to-really-set-up-a-react-native-environment-on-mac-248h</guid>
      <description>&lt;p&gt;This is basically taken from a private README that I use and cleaned up for public consumption. It doesn't really have the humor that I try to bring to these things, and I tried to keep it simple for Japanese speakers that I can point here when they need help. Very quick and dirty, may clean up later.&lt;/p&gt;

&lt;p&gt;This is only for Mac. If you aren't using Mac for React Native dev - do it, it's pretty great.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up a react native environment
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Software installs and file setup
&lt;/h3&gt;

&lt;p&gt;Install Xcode from the app store - Xcode is a program that runs iOS apps for you, and lets you start a simulator for your app so you can develop without needing a physical iPhone.&lt;/p&gt;

&lt;p&gt;Install a Java Development Kit - you need this to make Android apps in React Native&lt;br&gt;
&lt;a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html"&gt;http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html&lt;/a&gt;&lt;br&gt;
Accept license agreement, Mac OS X x64&lt;/p&gt;

&lt;p&gt;Install Android Studio (google this). This is how we will run android simulators so we don't need an Android phone open to check our work. Now, we need to set it up.&lt;/p&gt;

&lt;p&gt;Open Android Studio. Choose custom install. Check the boxes for&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android SDK&lt;/li&gt;
&lt;li&gt;Android SDK Platform&lt;/li&gt;
&lt;li&gt;Performance(Intel@HAXM) - this speeds up the simulator.&lt;/li&gt;
&lt;li&gt;Android Virtual Device&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Begin downloads.&lt;/p&gt;

&lt;p&gt;Install Node and Node Package Manager(NPM). If you don't know what that is, literally google - install Node on MacOS. It's very painless&lt;/p&gt;

&lt;p&gt;That will take a long time, so in your terminal, enter the following (without the $ symbol).&lt;/p&gt;

&lt;p&gt;This will install watchman, a program that watches files and updates your app when they change.&lt;br&gt;
&lt;code&gt;$brew install node watchman&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will install react native so we can do cool stuff like make apps&lt;br&gt;
&lt;code&gt;npm install -g react-native-cli&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Back to Xcode
&lt;/h3&gt;

&lt;p&gt;install the xcode command line tools. In terminal:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$xcode-select --install&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add the following line to your ~./bash_profile&lt;/p&gt;

&lt;p&gt;&lt;code&gt;alias android-studio="open -a /Applications/Android\ Studio.app/"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What this does (after restarting terminal) is let you open directories by typing&lt;/p&gt;

&lt;p&gt;&lt;code&gt;android-studio .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;in that directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Android SDK and AVD Install
&lt;/h3&gt;

&lt;p&gt;Open android studio once downloads finish, click on "configure", go to SDK manager.&lt;/p&gt;

&lt;p&gt;Click "Show package details"&lt;/p&gt;

&lt;p&gt;Enable Android 6.0 (Marshmallow), and INSIDE Marshmallow, enable&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google APIs&lt;/li&gt;
&lt;li&gt;Android SDK platform 23&lt;/li&gt;
&lt;li&gt;Intel x86 Atom_64 System Image&lt;/li&gt;
&lt;li&gt;Google APIs Intel x86 Atom_64 System Image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do the above for Android 7 and 8 as well (Not necessary, but good to have for the future)&lt;/p&gt;

&lt;p&gt;Next, on SDK tools tab, click "Show package details", look for "Android SDK Build-Tools", and make sure that 23.0.1 is selected&lt;br&gt;
click apply.&lt;/p&gt;

&lt;p&gt;append to ~/.bash_profile:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/platform-tools
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;terminal: &lt;code&gt;source $HOME/.bash_profile&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Confirm sdk location with echo $PATH&lt;/p&gt;

&lt;p&gt;We just did all that because really we have no choice. That's the work necessary to make Android apps.&lt;/p&gt;

&lt;h3&gt;
  
  
  New project
&lt;/h3&gt;

&lt;p&gt;Setup a project really quick to configure the emulators.&lt;/p&gt;

&lt;p&gt;In terminal, start a new project with&lt;br&gt;
&lt;code&gt;$npx react-native init &amp;lt;APP_NAME&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$cd &amp;lt;APP_NAME&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$npm install&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note, you can use Yarn as well (google install Yarn)&lt;/p&gt;

&lt;h4&gt;
  
  
  Running on iOS
&lt;/h4&gt;

&lt;p&gt;In a terminal, type &lt;code&gt;$react-native run-ios&lt;/code&gt; from your react native project folder&lt;/p&gt;

&lt;p&gt;Confirm that app runs.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;SIMULATOR NOT FOUND ERROR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If it tells you that a simulator isn't found, restart your computer. Common issue on using react-native init command.&lt;/p&gt;




&lt;p&gt;Press command+d&lt;/p&gt;

&lt;p&gt;Enable hot reload.&lt;/p&gt;

&lt;p&gt;Change text in app.js under ios, save, and observe instant change in simulator.&lt;/p&gt;

&lt;p&gt;Close simulator.&lt;/p&gt;

&lt;p&gt;Celebrate.&lt;/p&gt;

&lt;h4&gt;
  
  
  Running on Android
&lt;/h4&gt;

&lt;p&gt;Open the project in Android Studio. (Go to the react-native directory, go to /android, then run &lt;code&gt;android-studio .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Open Android studio, and open the Example App directory in it&lt;br&gt;
When it says "Android framework detected", configure -&amp;gt; Agree&lt;/p&gt;

&lt;p&gt;click the AVD manager icon in the upper-right hand corner (Waaaaay upper right)&lt;/p&gt;

&lt;p&gt;Grab whatever device you want to test on, then click Next&lt;br&gt;
on the x86 images tab, then look for the Marshmallow API Level 23, x86_64 API image with a Android 6.0 (Google APIs) target.&lt;/p&gt;

&lt;p&gt;Click next, then finish.&lt;/p&gt;

&lt;p&gt;Click the play button on your specific android virtual device to launch it. When the home screen appears, you're ready!&lt;/p&gt;

&lt;p&gt;terminal in project root:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;react-native run-android&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Press cmd + m&lt;/p&gt;

&lt;p&gt;Enable hot reloading&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IF YOUR SCREEN IS WHITE:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go to more settings (sidebar), go to settings, click advanced, then set the OpenGL ES renderer to a new option (randomly), then exit the settings, exit the emulator, restart the emulator, and re-run &lt;code&gt;react-native run-android&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Change text in app.js&lt;/p&gt;

&lt;p&gt;Observe change.&lt;/p&gt;

&lt;p&gt;Celebrate!&lt;/p&gt;

&lt;h3&gt;
  
  
  Editor
&lt;/h3&gt;

&lt;p&gt;I was hardcore Nuclide (Atom). Now I'm all about that visual studio code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up ESLint
&lt;/h2&gt;

&lt;p&gt;This Project uses &lt;a href="https://eslint.org/"&gt;ESLint&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Source:&lt;br&gt;
&lt;a href="https://github.com/expo/eslint-config-universe"&gt;https://github.com/expo/eslint-config-universe&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/Intellicode/eslint-plugin-react-native"&gt;https://github.com/Intellicode/eslint-plugin-react-native&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;run the following in the root directory:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;yarn add --dev eslint prettier eslint-config-universe eslint-plugin-react eslint-plugin-react-native&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Move this file to your project root &lt;a href="https://gist.github.com/Rob117/118443a2610af3abcbb3d8ddb8a213d1"&gt;https://gist.github.com/Rob117/118443a2610af3abcbb3d8ddb8a213d1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;in your package.json, add the following line under "scripts"&lt;br&gt;
&lt;code&gt;"lint": "./node_modules/.bin/eslint --fix *.js **/*.js"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then just run &lt;code&gt;npm run lint&lt;/code&gt; to lint your code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing testing tools
&lt;/h3&gt;

&lt;p&gt;Jest is already installed&lt;/p&gt;

&lt;p&gt;To run jest tests: &lt;code&gt;npm test -- __tests__&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I realize that this is very rapidly written and might be a bit hard to follow - if any part doesn't work, let me know and I'll update it. I wrote this in a time crunch as a promise to a friend.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>development</category>
    </item>
    <item>
      <title>Circle CI Nightly Builds and Github PRs with AWS Lambda Triggers</title>
      <dc:creator>Rob Sherling</dc:creator>
      <pubDate>Mon, 23 Apr 2018 14:09:18 +0000</pubDate>
      <link>https://dev.to/rob117/circle-ci-nightly-builds-and-github-prs-with-aws-lambda-triggers-3p1</link>
      <guid>https://dev.to/rob117/circle-ci-nightly-builds-and-github-prs-with-aws-lambda-triggers-3p1</guid>
      <description>&lt;p&gt;Hi! In this blog post, I'll show you in detail how to create daily/nightly builds in CircleCI with AWS Lambda, and take the results of those builds and create a Github pull request with the changes. Everything in this tutorial is 100% free.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Rob117/CircleCI-Nightly-Builds"&gt;Repository Here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this project, I am assuming that you already have your project on CircleCI and Github. If you don't use Github, the Lambda and CircleCI parts will still be useful to you, just ignore the part at the very end where we create pull requests. If you don't have CircleCI, this project unfortunately has almost nothing for you unless you want to see an example of what a Github API request looks like.&lt;/p&gt;

&lt;p&gt;CAVEAT: In the bash script, we use the line &lt;code&gt;git add apples.txt&lt;/code&gt; to add our newest files. I would recommend writing &lt;code&gt;git add &amp;lt;whatever your files are expected to be&amp;gt;&lt;/code&gt; instead of some catch all expression like &lt;code&gt;git add .&lt;/code&gt;. For example, if you ran bundle update, I would recommend running only &lt;code&gt;git add Gemfile.lock&lt;/code&gt;. This is because CircleCI can mess with your repo in crazy ways when it sets up for things. Example: Before it gets to your code, it may run something like bundle install to get all of your project dependencies. This means that you will suddenly have tons of files related to gems in vendor/bundle, and if you didn't gitignore that file, you are looking at a huge diff. It can also edit database.yml, so there's that.&lt;/p&gt;

&lt;p&gt;Along the way, I'll be explaining gotchas or odd lines of code. Let's begin.&lt;/p&gt;

&lt;p&gt;The way that nightly builds work is that first, we'll make a bash script to run all the code we want to execute on the build machine (in this case, make a file). This could be anything from &lt;code&gt;rails t&lt;/code&gt; to &lt;code&gt;bundle update&lt;/code&gt; to a bash script that checks the weather around your Singapore server (if you write that, please show me, I would be super interested). The end of that script will have us push any changes we made to Github as a pull request.&lt;/p&gt;

&lt;p&gt;Then, we'll put that script in our CircleCI File to make it activate when we trigger our builds via API. This is relatively simple, a few lines.&lt;/p&gt;

&lt;p&gt;Finally, we'll build a lambda and slap a cron job on there to make it proc our build at whatever time and frequency you please. Note: Lambda cron is limited to a rate of no greater than 1/minute &lt;a href="http://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html"&gt;(source)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, the bash script. Create a file with a name that describes what the code will do. I wrote a script called bundle_update.sh, because we're gonna be updating bundles. Don't forget to chmod +x !&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Rob117/CircleCI-Nightly-Builds/blob/master/bundle_update.sh"&gt;bundle_update.sh&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
# First check out the branch you want to work code magic on. This is our base.
git checkout 'master'
# Force our branch to be in alignment with remote.
git reset --hard origin/master
# Make sure the commit is made with the correct credentials
git config --global user.email "&amp;lt;Your email here&amp;gt;"
git config --global user.name "circle-ci"
# Check to see if our work branch exists - $? command will return 0 if branch exists
# of course, this branch name could be anything you like, it's just important that it is unique to this script.
git rev-parse --verify circle_ci/make_apples
# If we have no branch, make one. Else, switch to it.
if ! [ 0 == $? ]; then
  git checkout -b 'circle_ci/make_apples'
else
  git checkout 'circle_ci/make_apples'
fi

# Run your custom code here. We'll just make a file for ease of use.
# This code can be anything you want to do, bundle update, nginx ip configs, etc.
touch apples.txt

# If we have changes, make a PR for those changes
if [[ `git status --porcelain` ]]; then
  # Ensure that our branch is correct. The last thing you want is to force push into the wrong branch
  if [ `git rev-parse --abbrev-ref HEAD` == 'circle_ci/make_apples' ]; then
    git add 'apples.txt'
    git commit -m 'My commit message here'
    # -f Necessary to possibly overwrite any existing remote branch code and force this to be correct
    # -u sets upstream for circleci
    git push -f -u origin circle_ci/make_apples
    # Head = Code to merge, base = branch to merge into
    # $GITHUB_ACCESS_TOKEN is an environment variable we set on CircleCI, but you must set it on your local machine if you want to test there as well
    # Example Github URL: https://api.github.com/repos/Rob117/circletest/pulls?access_token=$GITHUB_ACCESS_TOKEN
    curl -H "Content-Type: application/json" -X POST -d '{"title":"Title Of Pull Request Here","body":"Body of pull request here", "head": "circle_ci/make_apples", "base":"master"}' https://api.github.com/repos/&amp;lt;Organization or User Name&amp;gt;/&amp;lt;Project Name&amp;gt;/pulls?access_token=$GITHUB_ACCESS_TOKEN
  fi
fi

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before I explain the gotchas of the above code, go onto Github and create a &lt;a href="https://github.com/settings/tokens"&gt;token&lt;/a&gt;. That token should have the repo checkbox ticked so it has &lt;code&gt;Full control of private repositories&lt;/code&gt;. &lt;strong&gt;Save that token&lt;/strong&gt;. Switch over to CircleCI, and on your project settings page under Environment Variables, create a variable with the name GITHUB_ACCESS_TOKEN and a value of whatever your token string was. &lt;/p&gt;

&lt;p&gt;Also ensure that your project has ssh permissions for Github set as well, or we can't push code from within our scripts. You can check by going to Checkout SSH Keys in the project settings and ensuring that you have a key that is permitted to ssh to your git repo there. If not (i.e., you don't have a user key there), click add user key and authorize the application to use your key. After authorizing, click on the 'create and add user key' button to get your ssh key on the machines so they can push code.&lt;/p&gt;

&lt;p&gt;If you want to test the code on your local machine, go ahead and &lt;code&gt;export GITHUB_ACCESS_TOKEN=&amp;lt;string here&amp;gt;&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Okay, now that we can actually run this code, let's break it down.&lt;/p&gt;

&lt;p&gt;Most of the comments explain the code clearly. Remember to replace your email in the git config section, and your Github API URL organziation name and project name in the last line. The gotchas are:&lt;/p&gt;

&lt;p&gt;We have to reset our base branch to whatever it is on remote with &lt;code&gt;git reset --hard origin/develop&lt;/code&gt;. The reason for this is because as a byproduct of using CircleCI, a lot of things happen to our build machine repository before we execute a single line of code, and they could taint the final results. Syncing develop with its remote counterpart ensures that we have a pristine copy, so it's just good practice anyway.&lt;/p&gt;

&lt;p&gt;These two lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git rev-parse --verify circle_ci/make_apples
if ! [ 0 == $? ]; then
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first line checks to see if the git branch exists. If it does, it will show 0 when you run the command $?, else it will show something else. This tells us if the branch exists so we know whether to make one or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if [[ `git status --porcelain` ]];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simply runs git status and outputs nothing if there is no change. If this outputs text, we want to make a pull request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if [ `git rev-parse --abbrev-ref HEAD` == 'circle_ci/make_apples' ]; then
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checks if our branch was actually created correctly. We do this so that we are sure we aren't going to force push to the wrong branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -H "Content-Type: application/json" -X POST -d '{"title":"Title Of Pull Request Here","body":"Body of pull request here", "head": "circle_ci/make_apples", "base":"master"}' https://api.github.com/repos/Rob117/circletest/pulls?access_token=$GITHUB_ACCESS_TOKEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the magic. Base is the branch we started with in the beginning, the one that we want to reflect our code changes post-merge. Head is the branch we created in this script to do all of our work. We take the changes and make a pull request using our github access token that is stored in our environment variable.&lt;/p&gt;

&lt;p&gt;Okay! We've broken down the bash script. Remember- just change the name of the base branch, created branch, and the file creation part to use the script in your own project. Running this script on your local environment - assuming you set your environment GITHUB_ACCESS_TOKEN var - should work smoothly and create a pull request on github.&lt;/p&gt;

&lt;p&gt;Next, let's edit our circle CI. It's just a few lines of code added to your normal circle.yml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Other Circle.yml code

test:
  post:
    - &amp;gt;
      if [ -n "${RUN_NIGHTLY_BUILD}" ]; then
        # If you put the script in your scripts folder, the path is ./scripts/&amp;lt;name&amp;gt;
        ./bundle_update.sh
        # As many scripts as you want here
      fi

# More circle CI code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code says 'if we get a post request that has variable called RUN_NIGHTLY_BUILD, execute the following scripts'.&lt;/p&gt;

&lt;p&gt;That's it! Push this code to the branch that you want to call it from. For example,  maybe you want to keep all of your scripts in your builds branch. Simply merge the above script and yml file into a branch called builds, and push that branch. You're all set to trigger your builds! You could also use a staging branch, develop branch, etc.&lt;/p&gt;

&lt;p&gt;SUPER IMPORTANT NOTE: If you have more than one script set to run and you only store the scripts in a single branch - say, &lt;code&gt;builds&lt;/code&gt; - and you change branches within a script, you MUST run &lt;code&gt;git checkout builds&lt;/code&gt; between script runs / at the end of each script. If you don't, Circle CI may fail to run all your scripts because you'll have changed to a branch where they don't exist!&lt;/p&gt;

&lt;p&gt;Okay, next let's set up our lambda and be done with this.&lt;/p&gt;

&lt;p&gt;First, hop on over to Circle CI, go to project settings, then go to API Permissions, then click Create Token. The scope of the token should be &lt;code&gt;All&lt;/code&gt;, and the label can be whatever you want. I chose &lt;code&gt;Lambda Execution&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Save that token, and open up your AWS Control Panel. Switch over to Lambda.&lt;/p&gt;

&lt;p&gt;Click Create Lambda Function, then click Blank Function. Next, click the empty dotted box to the left of the word Lambda and click Cloudwatch Events as the trigger. For the rule, create new rule. Rule name is &lt;code&gt;Nightly-Build&lt;/code&gt; and the schedule expression is &lt;code&gt;cron(0 0 * * ? *)&lt;/code&gt; -run at 12 UTC every day. &lt;a href="http://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html"&gt;(Source)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check Enable Trigger, then move to the next screen.&lt;/p&gt;

&lt;p&gt;Name the function 'NightlyBuild'. Skip the code for now.&lt;/p&gt;

&lt;p&gt;Set the environment variable CircleCIToken to .&lt;/p&gt;

&lt;p&gt;Set the role to a basic lambda execution role.&lt;/p&gt;

&lt;p&gt;Under advanced settings, set the timeout to 15 seconds.&lt;/p&gt;

&lt;p&gt;Finally, &lt;a href="https://github.com/Rob117/CircleCI-Nightly-Builds/blob/master/lambda.js"&gt;the lambda code&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Based on: https://github.com/godfreyhobbs/circleci-cron-serverless/blob/master/handler.js
'use strict';
var http = require("https");

exports.handler = (event, context, callback) =&amp;gt; {
    var options = {
        "method": "POST",
        "hostname": "circleci.com",
        "port": null,
        // example: "/api/v1.1/project/github/RobUserName117/secret-project/tree/builds"
        "path": "/api/v1.1/project/&amp;lt;github or bitbucket&amp;gt;/&amp;lt;organization or user name&amp;gt;/&amp;lt;project name&amp;gt;/tree/&amp;lt;branch name with scripts&amp;gt;" +
        "?circle-token=" + process.env.CircleCIToken,
        "headers": {
            "content-type": "application/json",
            "cache-control": "no-cache"
        }
    };

    // Make request, write out all of response
    var req = http.request(options, function (res) {
        var chunks = [];

        res.on("data", function (chunk) {
            chunks.push(chunk);
        });

        res.on("end", function () {
            var body = Buffer.concat(chunks);
            const response = body.toString();
            console.log(response);
            callback(null, response);
        });
    });

    req.write(JSON.stringify({
      "build_parameters": {
        "RUN_NIGHTLY_BUILD": "true"
      }
    }));
    req.end();
};


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of this code is self explanatory. The line that I would like to direct your attention to is the "path" part of your options object. According to the &lt;a href="https://circleci.com/docs/1.0/nightly-builds/"&gt;Circle CI docs&lt;/a&gt;, the URL that you post to is &lt;code&gt;/api/v1.1/project/vcs system/organization or user name/project name/tree/branch&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So if you wanted to push to the staging branch of the blogly project of the Google organization, stored in github, you would use:&lt;br&gt;
&lt;code&gt;/api/v1.1/project/github/google/blogly/tree/staging&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The second thing is that we are calling our builds by sending a JSON with the RUN_NIGHTLY_BUILD parameter set to true. You could set or send as many variables as you please - see the docs for more details.&lt;/p&gt;

&lt;p&gt;When this code runs successfully (click 'TEST'), you should get a response that says something like "Last build was blah blah blah". If you see a response that looks like CircleCI Webpage HTML, you made a configuration error somewhere.&lt;/p&gt;

&lt;p&gt;Switch over to CircleCI and watch your build happen, then switch to Github and witness your glorious pull request!&lt;/p&gt;

&lt;p&gt;Finished! Thanks for reading to the end. If you have any questions, please message me directly or leave a comment.&lt;/p&gt;

</description>
      <category>git</category>
      <category>circleci</category>
      <category>lambda</category>
    </item>
    <item>
      <title>Enhanced Active Admin - Audio and Image Previews</title>
      <dc:creator>Rob Sherling</dc:creator>
      <pubDate>Sun, 04 Jun 2017 08:37:29 +0000</pubDate>
      <link>https://dev.to/rob117/enhanced-active-admin---audio-and-image-previews</link>
      <guid>https://dev.to/rob117/enhanced-active-admin---audio-and-image-previews</guid>
      <description>

&lt;h1&gt;
  
  
  Images and Audio Preview in Active Admin
&lt;/h1&gt;

&lt;p&gt;This is a small piece of code that extends active admin to show previews of images and audio on the index, edit, and show pages. It's very straightforward and very, very easy to implement.&lt;/p&gt;

&lt;p&gt;repo: &lt;a href="https://github.com/Rob117/active-admin-uploads"&gt;https://github.com/Rob117/active-admin-uploads&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;p&gt;I was recently working on a project where I needed a portable solution for enabling image and audio previews in active admin. The admins needed to be able to click on any given piece of audio to hear it, or an image preview to see it full size. They also needed this information available in the show, index, and edit views. This is the code that I distilled to perform that function. The full walkthrough is at the bottom.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This code is not very Safari friendly, so I strongly recommend Chrome or Firefox for working with active admin (and also in general).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Module EnhancedUploader
# We grab the form, then the object from the form. We try to then show the
# content of that object
  def input_audio(f, property)
    f.input property, hint: audio_content(f.object, property)
  end

  def input_image(f, property)
    f.input property, hint: image_content(f.object, property)
  end

# We simply grab an object and check to see if our property exists on it.
# If it does, display the object
  def audio_content(object, property)
    if object.persisted? &amp;amp;&amp;amp; object.respond_to?(property)
      audio_tag object.send(property), controls: true
    else
      content_tag(:span, 'No Current Audio')
    end
  end

  def image_content(object, property)
    if object.persisted? &amp;amp;&amp;amp; object.respond_to?(property)
      image_tag object.send(property), height: 150
    else
      content_tag(:span, 'No Current Image')
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Inputs Explanation
&lt;/h3&gt;

&lt;p&gt;First, we'll start with the input form options&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  def input_audio(f, property)
    f.input property, hint: audio_content(f.object, property)
  end

  def input_image(f, property)
    f.input property, hint: image_content(f.object, property)
  end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So, in order to understand what this code does, you have to understand what a hint is in active admin. When you edit something in active admin, it allows you to give some context as to what that object might be. You typically specify that with the &lt;strong&gt;hint:&lt;/strong&gt; param. For example, you could write some text next to a field called 'credit card' on an input form that says 'application only accepts visa.', and it would show that next to the input field.&lt;/p&gt;

&lt;p&gt;Let us assume we have a user profile picture that we want to display a preview of when we edit it on a form. We also have a audio sample of the user saying 'hello' that we would like to be playable on the form. The code for the input image and audio would look something like this:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  # f is a form
  form do |f|
    extend EnhancedUploader
    input_image f, :profile_picture
    input_audio f, :hello_audio
  end 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Please check the section "The Use" for a minimal, guided, working example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audio and Image Content methods
&lt;/h2&gt;

&lt;p&gt;Next, we'll explain what the following audio and image rendering code does:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  def audio_content(object, property)
    if object.persisted? &amp;amp;&amp;amp; object.respond_to?(property)
      audio_tag object.send(property), controls: true
    else
      content_tag(:span, 'No Current Audio')
    end
  end

  def image_content(object, property)
    if object.persisted? &amp;amp;&amp;amp; object.respond_to?(property)
      image_tag object.send(property), height: 150
    else
      content_tag(:span, 'No Current Image')
    end
  end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This code is much easier to explain. In each method, we accept an object. First, we check that it is persisted (saved to the DB), because if it isn't there's nothing to show or render - we cannot render data that we do not have.&lt;/p&gt;

&lt;p&gt;Next, we check to make sure that the object can actually respond to the method that we want. It wouldn't be a good idea to try to render something that the object doesn't have! For example, before we try to display a profile_photo, we should make sure that the model actually has a profile_photo field that we can show.&lt;/p&gt;

&lt;p&gt;Lastly, we simply render an html5-compliant image link or audio player with controls. The code in the show section would look something like this:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  show do
    extend EnhancedUploader
    attributes_table do
      row :profile_photo do |row_object|
        image_content row_object, :profile_photo
      end
      row :hello_audio do |row_object|
        audio_content row_object, :hello_audio
      end
    end
  end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Walkthrough
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Laying Foundation
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;rails new demo&lt;/code&gt;&lt;br&gt;
&lt;code&gt;rails g model User name:string location:string&lt;/code&gt;&lt;br&gt;
&lt;code&gt;rails db:create db:migrate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we add active admin and devise&lt;br&gt;
In your gemfile, add the lines&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem 'activeadmin'
gem 'devise'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;bundle&lt;/code&gt;&lt;br&gt;
&lt;code&gt;rails generate devise:install&lt;/code&gt;&lt;br&gt;
&lt;code&gt;rails g active_admin:install&lt;/code&gt;&lt;br&gt;
&lt;code&gt;rails db:migrate db:seed&lt;/code&gt;&lt;br&gt;
&lt;code&gt;rails s&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;localhost:3000/admin&lt;/code&gt;, login with&lt;br&gt;
username: &lt;a href="mailto:admin@example.com"&gt;admin@example.com&lt;/a&gt;&lt;br&gt;
password: password&lt;/p&gt;

&lt;p&gt;create file at app/admin/user.rb, and paste in this content:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ActiveAdmin.register User do
  permit_params :name, :location
  # Show the essential data in the index
  index do
    selectable_column # we can select columns for batch actions
    column :id
    column :name
    column :location
    column :created_at
    column :updated_at
    actions
  end

  # When you click on the show for any individual item, this data is rendered
  show do
    attributes_table do # display the following attributes
      row :id
      row :name
      row :location
      row :created_at
      row :updated_at
    end
  end
  # When you click on edit, this form is rendered
  form do |f|
    f.semantic_errors
    f.inputs do
      f.input :name
      f.input :location
    end
    f.actions
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Go to &lt;code&gt;http://localhost:3000/admin/users&lt;/code&gt; and confirm that we can create, delete, and edit our basic users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding CarrierWave
&lt;/h3&gt;

&lt;p&gt;Time to add an image uploader and an audio uploader. First, let's include our library that will manage data display for us. Move the following file to &lt;code&gt;lib/enhanced_uploader&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;+git file+&lt;/p&gt;

&lt;p&gt;Add the following to your gemfile:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem 'carrierwave', '~&amp;gt; 1.0'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;bundle&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;make two uploaders, one for profile_photo and one for hello_audio&lt;br&gt;
&lt;code&gt;rails g uploader profile_photo&lt;/code&gt;&lt;br&gt;
&lt;code&gt;rails g uploader hello_audio&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add both uploaders to the user model&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails g migration add_profile_photo_to_users profile_photo:string&lt;/code&gt;&lt;br&gt;
&lt;code&gt;rails g migration add_hello_audio_to_users hello_audio:string&lt;/code&gt;&lt;br&gt;
&lt;code&gt;rails db:migrate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Open app/models/user.rb file and mount uploaders&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class User &amp;lt; ApplicationRecord
  mount_uploader :profile_photo, ProfilePhotoUploader
  mount_uploader :hello_audio,   HelloAudioUploader
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Replace app/admin/user.rb with the following (we aren't showing the enchanced uploader quite yet):&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ActiveAdmin.register User do
  permit_params :name, :location, :profile_photo, :hello_audio
  # Show the essential data in the index
  index do
    selectable_column
    column :id
    column :name
    column :location
    column :profile_photo
    column :hello_audio
    column :created_at
    column :updated_at
    actions
  end

  # When you click on the show for any individual item, this data is rendered
  show do
    attributes_table do
      row :id
      row :name
      row :location
      row :profile_photo
      row :hello_audio
      row :created_at
      row :updated_at
    end
  end
  # When you click on edit, this form is rendered
  form do |f|
    f.semantic_errors
    f.inputs do
      f.input :name
      f.input :location
      f.inputs :profile_photo
      f.inputs :hello_audio
    end
    f.actions
  end
end

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We just added the fields. &lt;strong&gt;Restart your server&lt;/strong&gt; and access your users page.&lt;br&gt;
Create a user if you need to.&lt;br&gt;
Notice that on index, show, and edit that the fields for profile_photo and hello_audio are blank. This is to be expected - we haven't uploaded anything yet!&lt;/p&gt;

&lt;p&gt;Upload a small image and a small audio clip.&lt;/p&gt;

&lt;p&gt;Notice that after we've uploaded it you can only view the path names and not anything &lt;em&gt;inside&lt;/em&gt; the file.&lt;/p&gt;

&lt;p&gt;To include our 'library', we only need make one small change, in config/application.rb:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require_relative 'boot'
require 'rails/all'
Bundler.require(*Rails.groups)

module Blogly
  class Application &amp;lt; Rails::Application
    config.autoload_paths += %W(#{config.root}/lib) # Add this line!
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, simply change your admin/user.rb file to this final code:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ActiveAdmin.register User do
  permit_params :name, :location, :profile_photo, :hello_audio
  # Show the essential data in the index
  index do
    extend EnhancedUploader # include uploader
    selectable_column
    column :id
    column :name
    column :location
    column :profile_photo do |row_object|
      image_content row_object, :profile_photo
    end
    column :hello_audio do |row_object|
      audio_content row_object, :hello_audio
    end
    column :created_at
    column :updated_at
    actions
  end

  # When you click on the show for any individual item, this data is rendered
  show do
    extend EnhancedUploader # include uploader
    attributes_table do
      row :id
      row :name
      row :location
      row :profile_photo do |item|
        image_content item, :profile_photo
      end
      row :hello_audio do |item|
        audio_content item, :hello_audio
      end
      row :created_at
      row :updated_at
    end
  end
  # When you click on edit, this form is rendered
  form do |f|
    extend EnhancedUploader # include uploader
    f.semantic_errors
    f.inputs do
      f.input :name
      f.input :location
      input_image f, :profile_photo
      input_audio f, :hello_audio
    end
    f.actions
  end
end

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Refresh your server, and head to the users page. Now you should see previews of the audio and image that you uploaded on each index, show, and edit page! Success!&lt;/p&gt;


</description>
      <category>rails</category>
      <category>activeadmin</category>
    </item>
    <item>
      <title>Serverless Backends with AWS Cloud: Cloudfront and WAF</title>
      <dc:creator>Rob Sherling</dc:creator>
      <pubDate>Mon, 24 Apr 2017 19:06:44 +0000</pubDate>
      <link>https://dev.to/rob117/serverless-backends-with-aws-cloud-cloudfront-and-waf</link>
      <guid>https://dev.to/rob117/serverless-backends-with-aws-cloud-cloudfront-and-waf</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a part in a series on AWS serverless architecture. The original blog post series can be found both here and on my blog &lt;a href="http://robsherling.com/jbytes/index.php/2017/01/08/serverless-backends-with-aws-cloud-intro/" rel="noopener noreferrer"&gt;J-bytes&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  CloudFronts and Firewalls
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Why Cloudfront for an API?
&lt;/h2&gt;

&lt;p&gt;I'm gonna be honest: When my boss told me to put the API on CloudFront, I thought he might have been joking. Why would you need to put an API on a distribution network? Setting it up was the hardest part of this project (no, seriously), and working with the quirks of CloudFront was a pain.&lt;/p&gt;

&lt;p&gt;Then it became super obvious why we did it once it started working.&lt;/p&gt;

&lt;p&gt;Do you remember at the beginning when I said that we were assuming the site you were using this with was a collection of static pages (although it doesn't have to be)? Well, if you put your API on CloudFront and your site in S3, they are all under the same SSL and distribution settings. This means no separate configurations for anything, you can ensure all requests are automatically HTTPS, etc., and the configurations are all in one convenient panel. Also, thanks to WAF, your site and your API are protected in the exact same way. You can never launch the site but forget to make the API available and cause user confusion.&lt;/p&gt;

&lt;p&gt;We'll be making (as usual) two API CloudFront distributions - one for each of our stages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: As of the time of this publication, it has been my experience and the experience of several others that cloudfront will randomly drop API requests for no reason. This behavior is intermittent but definitely present &lt;a href="https://forums.aws.amazon.com/thread.jspa?threadID=182765&amp;amp;tstart=0" rel="noopener noreferrer"&gt;(source)&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  S3 Static Sites
&lt;/h2&gt;

&lt;p&gt;First, however, we need to make an S3 distribution. This is because the first origin that we create in our distribution must have a Path Pattern of Default (*) and catches all routes, and we don't want our API to do that. We want our /api requests to go to our API and the rest to go to our S3. Basically, this is just a placeholder so we'll just rig something up lightning quick.&lt;/p&gt;

&lt;p&gt;Go make a new bucket in S3 called "whatever unique name you want here-site." We will now call this our site bucket. Edit the properties of this bucket, and set Static Website Hosting to &lt;strong&gt;Enable website hosting&lt;/strong&gt;, then set the Index Document to index.html. Leave Error Document blank. &lt;a href="http://docs.aws.amazon.com/AmazonS3/latest/dev/HowDoIWebsiteConfiguration.html" rel="noopener noreferrer"&gt;(source)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upload a single file into it called &lt;strong&gt;index.html&lt;/strong&gt; with some text of your choosing (I always choose the word delicious for really circuitous reasons based on a Japanese word for a bad situation). Make sure to set the permissions on this file to &lt;strong&gt;Everyone&lt;/strong&gt; - &lt;strong&gt;Open/Download&lt;/strong&gt;. If correctly done, you should be able to open just the file and see everything inside it easily. Let's put that on a distribution really fast, and then get to the good part. &lt;strong&gt;Read the following very carefully, because redeploys can take a long time so troubleshooting becomes very costly in terms of time.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Go to the CloudFront panel&lt;/li&gt;
&lt;li&gt; Click Create Distribution&lt;/li&gt;
&lt;li&gt; Under Web, click Get Started&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Origin Domain Name&lt;/strong&gt;, type the site bucket name configured as follows: &lt;code&gt;&amp;lt;bucket-name&amp;gt;.s3-website-&amp;lt;aws-region&amp;gt;.amazonaws.com&lt;/code&gt;.&lt;a href="http://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html" rel="noopener noreferrer"&gt;(source)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Leave &lt;strong&gt;Origin Path&lt;/strong&gt; blank, &lt;strong&gt;Origin ID&lt;/strong&gt; as is, and &lt;strong&gt;Origin Custom Headers&lt;/strong&gt; blank.&lt;/li&gt;
&lt;li&gt;For the &lt;strong&gt;Viewer Protocol Policy&lt;/strong&gt;, change it to "Redirect HTTP to HTTPS"&lt;/li&gt;
&lt;li&gt;For everything else in &lt;strong&gt;Default Cache Behavior Settings&lt;/strong&gt;, you can leave it as-is. If you need to confirm a lot of rapid site changes in real time on your staging environment, set your &lt;strong&gt;Object Caching&lt;/strong&gt; to Customize and all your TTL to 0.
For your &lt;strong&gt;Distribution Settings&lt;/strong&gt;, configure your &lt;strong&gt;Price Class&lt;/strong&gt; to your region. For example, I'm in Japan so we use "Only US, Canada, Europe, and Asia." You probably don't actually have to do this, but it's a great habit to get into.
We haven't made a WAF yet (we'll talk about that briefly later), so just leave that blank.&lt;/li&gt;
&lt;li&gt;Ignore everything else and scroll down to &lt;strong&gt;Enable IPv6&lt;/strong&gt;. Turn that off unless you know you need it. For example, if this is the backend for an iPhone App, their testing standards require ipv6 connectivity &lt;a href="https://developer.apple.com/support/ipv6/" rel="noopener noreferrer"&gt;(source)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Under comment, write STAGING.&lt;/li&gt;
&lt;li&gt;Create Distribution.&lt;/li&gt;
&lt;li&gt;Make sure that your &lt;strong&gt;Origin Protocol Policy&lt;/strong&gt; says "HTTP Only" under the Origins tab. I do not know why, but one of my stages defaulted to HTTPS and it broke my distribution later on. If your screen does not look like this: &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Frobsherling.com%2Fjbytes%2Fwp-content%2Fuploads%2F2017%2F02%2Forigin.jpg" alt="origin protocol policy"&gt; click on the edit button and simply click &lt;strong&gt;Yes, Edit&lt;/strong&gt; to save your changes. This should hopefully force it back to HTTP only, as it did for me.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Putting the API behind CloudFront
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Click on the distribution you we just made, then click the &lt;strong&gt;Origins&lt;/strong&gt; tab and click &lt;strong&gt;Create Origin.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Origin Domain Name&lt;/strong&gt;, type the base URL for your API. For example, if you go to the API panel and click on &lt;strong&gt;Stages&lt;/strong&gt;, then &lt;strong&gt;staging&lt;/strong&gt; you should see an invoke URL like &lt;code&gt;https://&amp;lt;letters&amp;gt;.execute-api.us-west-1.amazonaws.com/staging&lt;/code&gt;. Copy the URL, &lt;em&gt;without&lt;/em&gt; the /staging, and paste it in the Origin Domain Name box &lt;code&gt;https://&amp;lt;letters&amp;gt;.execute-api.us-west-1.amazonaws.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Origin Path&lt;/strong&gt;, write the stage name &lt;code&gt;/staging&lt;/code&gt;. This is why we didn't write staging above - we automatically append &lt;code&gt;/staging&lt;/code&gt; to all api requests that come to this domain.&lt;/li&gt;
&lt;li&gt;Leave &lt;strong&gt;Origin ID&lt;/strong&gt; and &lt;strong&gt;Origin SSL Protocols&lt;/strong&gt; as-is&lt;/li&gt;
&lt;li&gt;Change &lt;strong&gt;Origin Protocol Policy&lt;/strong&gt; to HTTPS Only. The API Gateway will only accept HTTPS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTPS Port&lt;/strong&gt; is 443 (as-is)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Origin Custom Headers&lt;/strong&gt; is as-is&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Behaviors&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create Behavior&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Path Pattern&lt;/strong&gt;: &lt;code&gt;/api*&lt;/code&gt;. This will match anything that looks like &lt;code&gt;https://&amp;lt;url.top&amp;gt;/api/endpoint&lt;/code&gt;. This is also the reason that our API Gateway is set up so all the requests are under a /api resource, because CloudFront will automatically append the path pattern as-is when it send it to the API Gateway. So, as a quick explanation, if we set the CloudFront path pattern to &lt;code&gt;/api*&lt;/code&gt; but our gateway was just /email and then tried site.com/api/email, it would never work because CloudFront forwards the /api/email as is to our API Gateway.&lt;/li&gt;
&lt;li&gt;Change &lt;strong&gt;Origin&lt;/strong&gt; to the one we just made: Custom-letters.execute-api-stuff&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Viewer Protocol Policy&lt;/strong&gt; is redirect HTTP to HTTPS, because the Gateway demands it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Allowed HTTP Methods&lt;/strong&gt; are GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE because we need to post info to the gateway.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forward Headers&lt;/strong&gt; are set to Whitelist, then type "Origin" in the box and "Add &amp;gt;&amp;gt;" it to the whitelist. This is required by gateway.&lt;/li&gt;
&lt;li&gt;For our &lt;strong&gt;Object Caching&lt;/strong&gt;, set it to customize, and then all TTL must be set to 0. &lt;strong&gt;You do not want any caching on the API&lt;/strong&gt;. This will make requests just plain not work if you try to add GET api methods later.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Forward Cookies -&amp;gt; All&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Query String Forwarding and Caching -&amp;gt; Forward All, Cached Based on All&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Everything else is no. &lt;strong&gt;Create&lt;/strong&gt;.
Now if you go back to your Cloudfront Overview Page, you should see something like this on status: &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Frobsherling.com%2Fjbytes%2Fwp-content%2Fuploads%2F2017%2F02%2FStatus-cloudfront.jpg" alt="cloudfront status"&gt;That can, and almost certainly will, take at least 20 minutes to update. While that's working, go ahead and follow all the steps above again, except this time create a production distribution (or don't, I'm not your boss) :). If you do, feel free to point the S3 part at the same bucket because it's just a demo. While we're still waiting (seriously, it takes a while) I'll explain WAF.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  WAF: Wireless Application Firewall
&lt;/h2&gt;

&lt;p&gt;You would use a WAF in your actual setup to protect your site. For example, you would configure your WAF for staging so that only your IP Address (and the IP address of your client, if they have to approve site changes before pushing to production) would have access. You can add your production site to that same WAF (for example, before release or during maintenance) and then simply remove it from the WAF when you are ready to launch / finished maintenance.&lt;/p&gt;

&lt;p&gt;Go to &lt;strong&gt;WAF &amp;amp; Shield&lt;/strong&gt; in your console.&lt;br&gt;
Click on &lt;strong&gt;Go to AWS AWF&lt;/strong&gt;, then click &lt;strong&gt;Configure web ACL&lt;/strong&gt;. Read the Concepts Overview if you want, then click &lt;strong&gt;Next&lt;/strong&gt;.You probably don't actually have to make a WAF, so unless you have a static IP address or just want to test it, feel free to simply follow along for the learning experience and then delete the result.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The ACL name should be something unique like " Firewall"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Region&lt;/strong&gt; is global (Cloudfront)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Associated Resource&lt;/strong&gt; is Production (for now).&lt;/li&gt;
&lt;li&gt;Click Next&lt;/li&gt;
&lt;li&gt;Click "IP match condition"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt; is Allow Example IP ( for example)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IP version&lt;/strong&gt; is V4&lt;/li&gt;
&lt;li&gt;Address is whatever Google tells you your IP is, followed by a /32(example: 127.0.0.1/32). If you own a range, add it with /24 (see the advice on the page). Feel free to add as many IP addresses as you want to allow. Note that unless you purchase a fixed IP address from your ISP, you cannot count on this number not changing.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Add IP address or range&lt;/strong&gt; button. If you don't, you'll create an empty condition that will do nothing at all.&lt;/li&gt;
&lt;li&gt;Click Create.&lt;/li&gt;
&lt;li&gt;Click Next.&lt;/li&gt;
&lt;li&gt;On the Create rules page, click Create rule&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: Allow Example IP (or really, whatever you want).
Under conditions, it should read: When a request 'does originate from an ip address in Allow Example IP' &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Frobsherling.com%2Fjbytes%2Fwp-content%2Fuploads%2F2017%2F02%2Fupdaterule.jpg" alt="Example of allow exapmple IP request"&gt;
&lt;strong&gt;Note&lt;/strong&gt;: If you need to add multiple IPs, do not click "Add condition" and add an IP on this screen. If you do, it will make the condition "All requests coming from IP set 1 and IP set 2 at the same time", which is impossible and invalidates this rule completely. If you created multiple IP conditions in the last page (for example, a set of IP addresses to represent your company and another set to represent your client), you need to create a separate rule for each set.&lt;/li&gt;
&lt;li&gt;Click create.&lt;/li&gt;
&lt;li&gt;Change the &lt;strong&gt;Default Action&lt;/strong&gt; to "Block all request that don't match any rules."
The page should look like this:&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Frobsherling.com%2Fjbytes%2Fwp-content%2Fuploads%2F2017%2F02%2Fupdatesnaps.jpg" alt="Example of default action page"&gt;
This tells us that our allowed IPs have been set to allow, and if it isn't on our IP list, block it.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Review and create&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Confirm that your production Cloudfront is attached at the bottom.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Confirm and Create&lt;/strong&gt;
If you want to add your staging distribution to the WAF, it's as easy as clicking &lt;strong&gt;Add association&lt;/strong&gt; on the right-hand side of the screen and selecting your staging distribution.
Continue to wait as your Cloudfront Distributions update. Watch Youtube, play a game, etc. When the status is no longer in progress, proceed to testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing the Cloudfront Distribution and Firewall
&lt;/h2&gt;

&lt;p&gt;Here comes the coolness. Go to your Cloudfront page. You should see both distributions there. Copy and paste the url in the &lt;strong&gt;Domain Name&lt;/strong&gt; section into your browser, and hit enter. Assuming that you configured everything correctly and are coming from the correct IP if you are behind a WAF, you should be seeing the contents of your index.html page. If you try to go to that same domain though a different IP (smartphone on mobile data), you should see a forbidden page. Success!&lt;/p&gt;

&lt;p&gt;Try sending some requests in postman to each API (staging and production) with &lt;code&gt;domain-name/api/emails&lt;/code&gt; (or twitter) and see what happens. Remember to leave out &lt;code&gt;/staging&lt;/code&gt; and &lt;code&gt;/production&lt;/code&gt;, as they are included in the origin. You should have the same results as before, and database records should be correctly updated.&lt;/p&gt;

&lt;p&gt;That's it for the web site! That was a crazy ride. Next, we'll see what happens when we need to get that data from Dynamodb into our local environment and save emails for clients / send tweets!&lt;/p&gt;

</description>
      <category>cloudfront</category>
      <category>s3</category>
      <category>staticsites</category>
      <category>waf</category>
    </item>
    <item>
      <title>Serverless Backends With AWS Cloud: Twitter Sessions</title>
      <dc:creator>Rob Sherling</dc:creator>
      <pubDate>Mon, 24 Apr 2017 19:06:44 +0000</pubDate>
      <link>https://dev.to/rob117/serverless-backends-with-aws-cloud-twitter-sessions</link>
      <guid>https://dev.to/rob117/serverless-backends-with-aws-cloud-twitter-sessions</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a part in a series on AWS serverless architecture. The original blog post series can be found both here and on my blog &lt;a href="http://robsherling.com/jbytes/index.php/2017/01/08/serverless-backends-with-aws-cloud-intro/" rel="noopener noreferrer"&gt;J-bytes&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How to make a session in DynamoDB
&lt;/h1&gt;

&lt;p&gt;In this section, we're just going to save some browsing information in a session (held in DynamoDB) and redirect the user to Twitter. Once we have a callback in place, we'll use that session data to have our user follow us. We can also use that data to message that user later (we actually have the user DM themselves, explained in the next section) with some promotional news.&lt;/p&gt;

&lt;p&gt;More specifically, we're going to save their request token in a table in DynamoDB along with some other stuff, then when they confirm our app, use their oAuth token to go get the data attached to the request token and complete the chain.&lt;/p&gt;

&lt;p&gt;This is fairly straightforward so let's just jump right into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 0: Make a Twitter App
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://apps.twitter.com/" rel="noopener noreferrer"&gt;Setup your Twitter app here&lt;/a&gt;. It's fast, free, and easy. You will need this to do anything cool like message users and create friendships (on Twitter, this technology is not guaranteed to create friendships in any other way), so making it now makes sense. When you set this app up, it is &lt;strong&gt;super hyper critical imperative&lt;/strong&gt; that you go to the permissions tab and select read, write, and access direct messages. You do this because we need to have them DM themselves later on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: DynamoDB Tables
&lt;/h2&gt;

&lt;p&gt;You should know the drill from the last time we touched tables, so let's just rig up the rest of our tables right now. We're going to need an additional 4 tables total. We'll need staging and production tables for the session we'll create to hold our user's data while they log in to their Twitter accounts to (hopefully) authorize us, and we'll need staging and production tables to hold their data once they come back from that authorization and hit our callback.&lt;/p&gt;

&lt;p&gt;Open the DynamoDB table and make the following tables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: staging_session -&amp;gt; primary key: request_token (string)
name: production_session -&amp;gt; primary key: request_token (string)

name: staging_twitter -&amp;gt; primary key: uid(Number)
name: production_twitter -&amp;gt; primary key: uid(Number)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quick note on the uid in the Twitter tables: The uid actually will be treated as a string in our lambdas and automatically converted on storage. This is because Javascript sometimes has a problem with numbers and uids&lt;a href="https://dev.twitter.com/overview/api/twitter-ids-json-and-snowflake" rel="noopener noreferrer"&gt;(source)&lt;/a&gt;, but DynamoDB does not care at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: env-config.json
&lt;/h2&gt;

&lt;p&gt;Open up - or download from your S3 - your env-config.json file (you should have two, one for each environment we are creating). We'll be filling in the rest of the values, leaving only the twitter_api_callback blank for now (we'll do that in the next section). You can get your consumer_key and consumer_secret values from your Twitter app that you set up in step zero. You can find it in Keys and Access Tokens tab on your app settings.&lt;/p&gt;

&lt;p&gt;The twitter_table_name should be &lt;code&gt;&amp;lt;stage&amp;gt;_twitter&lt;/code&gt;, and the twitter_session_table_name is &lt;code&gt;&amp;lt;stage&amp;gt;_session&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the follow uid, you can get it from the same Keys and Access Tokens tab labelled as Owner Id. If it is &lt;em&gt;not&lt;/em&gt; your own account use &lt;a href="https://tweeterid.com/" rel="noopener noreferrer"&gt;this link&lt;/a&gt; and put in the account that you want to follow.&lt;/p&gt;

&lt;p&gt;Save your JSON, and re-upload to the appropriate S3 buckets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Constructing the Twitter Lambda
&lt;/h2&gt;

&lt;p&gt;Make a session_lambda folder on your local disk, and cd into it.&lt;/p&gt;

&lt;p&gt;We're going to download libraries like we did before. This time, we'll need the node-twitter-api library. Observe the spacing on this command, it's a little tricky (careful when you copy):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install –prefix=./ node-twitter-api&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add the loader.js that we made before using either a hard system link or copying it into the folder, depending on your expertise. If you're copying the loader.js from the github repo for the project, remember to change the S3 bucket on line 61 to our actual bucket.&lt;/p&gt;

&lt;p&gt;Add the &lt;a href="https://github.com/Rob117/serverless-twitter-email/blob/master/session_lambda/index.js" rel="noopener noreferrer"&gt;index.js&lt;/a&gt; file.&lt;br&gt;
Change the line on line 6 to your appropriate db region.&lt;/p&gt;

&lt;p&gt;Read the index file for the notes, but it should be fairly straightforward. We're just going to take a POST request that will tell us if the user chose to follow us or not, hit the Twitter API to get some request tokens, save that data all together, and then redirect to the Twitter site so they can complete the authorization. If you don't need users to follow an account or track any other data in the session, feel free to make it a get request later on.&lt;/p&gt;

&lt;p&gt;Zip the folder like we did when we made the email lambda (zip the contents of the folder, not the folder itself) and head on over to the lambda console.&lt;/p&gt;

&lt;p&gt;Create a lambda function. Select &lt;strong&gt;Blank Function&lt;/strong&gt; for the blueprint.&lt;br&gt;
Click Next on the Configure Triggers section that pops up to move to the next screen.&lt;br&gt;
For the name of the function, use &lt;strong&gt;generate_twitter_session&lt;/strong&gt;.&lt;br&gt;
Change the Code entry type drop-down box to "upload a zip file."&lt;br&gt;
Upload the zip we just made.&lt;br&gt;
Under Lambda function handler and role, use &lt;strong&gt;master_lambda&lt;/strong&gt; in the Existing role dropdown box.&lt;br&gt;
Set the Timeout to 15s&lt;br&gt;
Click Next, then Create Function.&lt;br&gt;
From the Actions drop-down, configure the test event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
 "body-json": "follow=true"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click Save.&lt;br&gt;
Click Actions and create two aliases. One 'staging', the other 'production'. Both should point to Version: $LATEST (you can make a version 1 if you'd like).&lt;br&gt;
Click the button to the left of test (could start with either Alias or say Qualifiers) and click staging under the aliases drop-down tabs. Then click test.&lt;br&gt;
If you get an error message in your logs on a line with JSON.parse that says &lt;strong&gt;SyntaxError: Unexpected token u&lt;/strong&gt; or something similar, check your test event again.&lt;/p&gt;

&lt;p&gt;You should get an error message that says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "errorMessage": "Twitter.MovedPermanently : Redirecting.",
  "errorType": "https://twitter.com/oauth/authenticate?oauth_token=&amp;lt;SOME TOKEN STUFF HERE&amp;gt;"
If you do, you are in good shape and ready to move on to hooking up our API endpoint.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Making our Gateway
&lt;/h2&gt;

&lt;p&gt;We're just going to hook up an API endpoint to our Twitter. This is basically a carbon-copy of the email API we made, so if you need a refresher please go read that again now.&lt;/p&gt;

&lt;p&gt;Open the API Gateway console and click on our services-api that we made. Click on /api, and then click the Actions drop-down and select &lt;strong&gt;Create Resource&lt;/strong&gt;. Name that resource twitter-session, and click Create Resource.&lt;/p&gt;

&lt;p&gt;This resource is going to mimic our email resource nearly identically. Remember to have your AWS CLI ready to approve our stage variable controlled lambdas.&lt;/p&gt;

&lt;p&gt;Click on the twitter-session resource, and click &lt;strong&gt;create method&lt;/strong&gt;.  Change that method to post, and click the check mark.&lt;/p&gt;

&lt;p&gt;Change the lambda region to your region, then type &lt;code&gt;generate_twitter_session:${stageVariables.alias}&lt;/code&gt;. Save, and when you see that giant wall of text, put it into the AWS CLI and replace &lt;code&gt;${stageVariables.alias}&lt;/code&gt;with staging. Enter, then replace it again with production. Enter again. Confirm non-error text.&lt;/p&gt;

&lt;p&gt;Back in your lambda console, click okay. Then click on Method Response. Delete the 200, add a 301, and then edit it to include the 'location' header.&lt;/p&gt;

&lt;p&gt;Go to the integration response. Delete the default response with a status of 200. Click &lt;strong&gt;add integration response&lt;/strong&gt;, change the status to 301, and make the error regex, &lt;code&gt;^Twitter.MovedPermanently.*&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Edit our newly created integration response and set the value of the location header mapping to &lt;strong&gt;integration.response.body.errorType&lt;/strong&gt;. Click the checkmark.&lt;/p&gt;

&lt;p&gt;Lastly, go back to our Integration Request from the twitter-session post option, and add a body mapping template.  The type is &lt;strong&gt;application/x-www-form-urlencoded&lt;/strong&gt;. Set the general template to Method Request passthrough, and the Request body passthrough to When there are no templates defined. Save it all.&lt;/p&gt;

&lt;p&gt;Deploy to staging and production. Export. Save.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Postman
&lt;/h2&gt;

&lt;p&gt;Click on staging under stages, then click on &lt;strong&gt;/api/twitter-session&lt;/strong&gt;. Copy the invoke URL and paste it into Postman. Set the header to &lt;code&gt;Content-Type: application/x-www-form-urlencoded&lt;/code&gt;. Set the body to &lt;code&gt;x-www-form-urlencoded&lt;/code&gt;, and the data key-value to &lt;code&gt;follow : true&lt;/code&gt;. Ensure that the method type is POST, and hit send. Postman should say loading for a short bit (if, for example, you are doing this from near Tokyo when your server is in California, it may be a long bit), and then come at you with something like this (you will have to click "pretty" to make it pretty):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Frobsherling.com%2Fjbytes%2Fwp-content%2Fuploads%2F2017%2F01%2Fapi-session.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Frobsherling.com%2Fjbytes%2Fwp-content%2Fuploads%2F2017%2F01%2Fapi-session.png" alt="Postman Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It works!&lt;/p&gt;

&lt;p&gt;There is no need to go any farther than this for now. If you check your staging_session database table, you should have some data in it. That marks the completion of this section.&lt;/p&gt;

&lt;p&gt;In the next section, we'll send confirmation tweets, actually follow an account, etc.&lt;/p&gt;

</description>
      <category>apigateway</category>
      <category>s3</category>
      <category>lambda</category>
      <category>dynamodb</category>
    </item>
  </channel>
</rss>
