Today, I cam upon an interesting research article: “Income and emotional well-being: A conflict resolved.” The article presents the results of a new study regarding the dependence of income and well-being, often used, at least by laymen such as myself, as a proxy for happiness.
The findings are interesting as they seem to fit better with many peoples intuition, more money makes more happy, sending the article to reddits ‘not the onion’ subreddit. The subreddit collects articles that seem satirical based on their title – everyone knows nobody reads the content.
Anyways, the findings discuss the previously found leveling-off of well-being improvements after a certain point, i.e., $75.000 per year, by Kahneman and Deaton. This new study shows their data suggests this is only the case for the unhappiest 20% of high earners, while otherwise the log-linear relationship holds: More money makes more happy.
These “discussions” on reddit usually go a certain way, e.g., Empathetic_Orch says:
I make under 30k a year so this is pretty obvious to me. If I could make 60k a year I’d be happy.
This is just an example of a popular kind of comment, I see quite often. I was curious what the results actually said and how they are presented. The article focuses on the change around the point of $100k household income and uses this as its only new visualization. Note though, that this shows the log of the income.
The authors provide their data easily – Thank You! – so it is simple for everyone to create new visualizations. So i threw the data in a few visualizations tools to make myself happy.
First I wanted an overview of the distributions, to get a feeling for the data. Seaborn has a nice and simple way to plot violin plots. The quantiles of the distribution, shown as dashed lines within the violines, seem to indicate a fairly clear upwards trend over the brackets.
It is important to note, that the brackets organized in this way, still are mostly logarithmic, as they get larger and larger. To alleviate this, I computed the 10th and 90th percentile in addition to the quartiles.
Income Bracket
P10
Q1
Median
Q3
P90
$10k-$20k
45.9867
53.14500
61.1750
68.94900
77.1774
$20k-$30k
47.0060
53.60100
61.8785
70.25600
78.6860
$30k-$40k
47.4220
55.34900
62.1260
70.18400
77.6935
$40k-$50k
48.2610
54.91400
62.2000
70.54600
78.2786
$50k-$60k
47.7432
55.17000
62.8250
70.68100
78.8980
$60k-$70k
48.6820
55.39100
62.9490
71.11300
78.8512
$70k-$80k
48.9280
55.27100
63.0960
71.45600
79.0130
$80k-$90k
49.1064
56.00800
63.3040
70.97600
79.2354
$90k-$100k
49.3025
56.25700
63.4340
71.54675
79.2570
$100k-$125k
49.9322
56.44700
63.5450
71.40300
79.2282
$125k-$150k
49.7290
56.61400
63.7900
72.06900
79.4690
$150k-$200k
49.8530
56.86500
64.1910
71.93700
79.9730
$200k-$300k
50.6540
57.70700
65.0000
73.41700
81.0800
$300k-$500k
50.9915
58.09625
65.6220
73.89550
81.2555
$500k-$750k
49.6628
57.27675
64.7130
73.28625
81.8000
10th percentile, first quartile, median, thrid quartile and 90th percentile of the well-being indicator for each income bracket that had data.
Based on this information, I created a log-regression for a new visualization.
The authors of the original article note: There is not enough data to make any meaningful conclusions for the >$500k bracket, so lets ignore the seeming drop for the richest respondents to the survey.
For me, the more important thing to draw from this, is more related to the reddit comment I showed as an example. If you are unhappy at $30k, would you be happy at $60k? Who knows, you are an individual not a statistic.
But, for a large population, the answer is who knows… While someone earning ~$400k unhappily (10th percentile) is still unhappier than 75% of people earning ~$15k, a person moving up in earning from $15k to $400k, might become happier. That’s not in the data.
It is important to realize though, that well-being is a wide spectrum within any earning bracket. There are many happy low-earners, as there are many unhappy high-earners.
So, best of luck /r/Empathetic_Orch, I hope you can make it to $60k quickly, and that it actually makes you happy. 🙂
ps: This is a random blogpost and I am not a professional in the relevant field. I just do this for fun, if you base any policy on a blogpost by and idiot like me, you are an idiot as well.
His bare foot touched the warm, but dark water of the sea. The wet feeling was welcome after this long walk. Standing still in this location was the payoff for a, surprisingly tough, journey from the closest village. It used to be easy to get here! Was it because it was night? No – he remembered well coming here at night before. Was it because the path deteriorated? The townsfolk must have neglected it. Surely, they have no use for the beauty of this spot, so maintaining the path was not worth it to them. Nonetheless it was a treasure for him.
A wave of unusually cold water washed over his feet. He backed off from the sea – he felt betrayed. Just a few steps away, he realized the ridiculousness of that feeling and sat down. Was this not what he should expect from the sea? Was this not even the reason he came here? The sea did not betray him – he betrayed his own expectations.
Slowly he sat down, his gaze drifts from one oncoming wave to the next, until it reaches the horizon. He noticed the lights of a far away ship, competing with the stars above his head and the dim lights of the village behind him. None could really claim the title of brightest, and not only because the moon was already holding that. He laid down on his back, taking in the full, yellowish glowing circle of the brightest.
A refreshing cool wind let him shudder for a moment. When they were here together, this never was a problem – for obvious reasons. They would just cuddle closer for those short moments and enjoy the otherwise cozy temperatures. He could barely remember coming here alone at night anymore. Did he bring a jacket before? He didn’t today at least. It shouldn’t be much of a hassle to just wait it out! A few moments of freezing or returning early? An easy choice.
A loud caw of a probably colorful bird caught his attention. It must have been close. The moon did not plan on making it easy for him to spot it. Another one, slightly further away – was the bird leaving? Or was a second bird approaching him? He slowly turned around, using his hands to keep himself steady. His eyes needed some time to adapt, too, after staring at the bright moon. Only a few seconds. It was barely enough to catch a glimpse of the bird flying through the trees he himself emerged from not that long ago.
Now that he focused on the trees, he notices some activity. A few smaller birds were happily chirping, while taking turns fishing for bugs in the air. A flying squirrel sailing through the night – a sight he hadn’t even noticed by day! How could he have missed all of this when wandering by? Was he too focused on his goal? His own expectation of arriving? The short distraction made him lose sight of the squirrel, something he instantly started to regret.
Regret. A word which can create a powerful downwards spiral of thoughts in many heads. He came here to for the experience of the past, but somehow it turned out to be so different. Was it tainted by the time they spent here together? Or was the, nearly magical, power of the experience before just unattainable? Coming back, just for the sake of going back.
When they came here the first time, he wanted to share the mystical nature of his favorite spot. The view far above the sea. The reflection of the sun, the stars, the moon. No matter the time they would come here, it was always beautiful. But today it felt like he didn’t belong here, even the road tried to stop him. He should go back after all, for the sake of accepting fate as it was. He got up.
He stopped. Had he given up? Yes. Had he not accepted his fate all the time? Was it him putting in the effort? No; he did not want to give up. There was so much to do, so much to say to each other, so much beauty and warmth to experience together!
Some splashes of warm water from the waves hit his feet. The lukewarm wind slightly pushed him to the road home. He looked forward to the path taking him there.
It’s no secret that we learn best by doing something: we remember vocabulary by repeating them, or better use them in sentences. We study math by solving problems. We hone our writing skills by writing. More often than not, those don’t have a well figured out point. Sometimes, though, we create a dockerized fizzbuzz web API.
Fizzbuzz?
Fizzbuzz is a surprisingly infamous children’s game: one after another the children count by saying out the number aloud. But if the number is a multiple of three, they have to say “fizz” instead. For multiples of five, it is “buzz.” If the number is a multiple of five and three, the child has to say “fizzbuzz.”
The game gained infamy with computer scientist and programmer applicants though! How so? As a simple challenge, i.e., write a loop that prints out the numbers up to 20 but print it with the rules of fizzbuzz, it is used as a screening for job interviews. The insight it provides is: has the applicant lied about their basic programming knowledge?
Thanks to this popularity fizzbuzz is often used as a starting problem on programming challenge platforms. Or as a starting point, similar to hello-world. But it is inefficient and boring to copy paste or rewrite solutions to fizzbuzz in all languages we know to farm points on such a platofrm. So we’ll just write it once and call it. Abstracting it away! (Writing external REST API calls is so much more fun!)
Let’s start with a simple fizzbuzz function for a single number in PHP. Why PHP? Because I happen to have a webhoster that natively supports it, making testing and iterating on it fast and simple. Here is the fizzbuzz.php:
Simple and straight forward, as we would expect from a topclass fizzbuzz. Don’t use it in production just yet, though, it’s not battle tested yet.
A First PhP Implementation
Building on this function, we would like to offer two API endpoints:
getting the fizzbuzz value for a single element,
getting an array of all fizzbuzz values up to a given value.
As we are providing an API, we should stick to a common format for data. Our desired API endpoints have no complex data, so we stick with JSON, which is well supported for PHP.
Let’s take a look at exact.php the file we will use to realize the first API endpoint:
<?php header('Content-Type: application/json'); include 'fizzbuzz.php';
A few points of interest, starting from the top: we add the expected content type header, to let our recipients know they receive JSON formated data. Setting headers needs to be done before any output. To ensure this condition, we defer includes after the header statements, as included files might output. We can’t trust the author of fizzbuzz.php after all.
We read the get parameter “fb” so, for now, we have to call this file using exact.php?fb=<number> to get the API response. We will fix this later, so we can call our API in a PHP-agnostic way.
Lastly, we check the read value, as we do not trust the author of our fizzbuzz function to do the right thing and return the JSON encoded response from the function. A simple call to exact.php?fb?=15 will now return the string “FizzBuzz” and our browser recognizes it as JSONdata.
We can do the same for our range endpoint, using a file called to.php. We use the same parameter name, headers and checks, but resulting in the much more interesting result of a JSON array when calling to.php?fb=15.
<?php header('Content-Type: application/json'); include 'fizzbuzz.php';
Unfortunately, we are currently restricted to PHP files that are called with parameters. This is unpleasant to document and use, and terrible to migrate to a new platform: we might need to switch to a high-performance fizzbuzz solution once our fizzbuzz service takes off.
Our current solution, hosting it on a PHP based provider, can do that: it is running apache with an enabled rewrite engine. This allows us to specify rewrite rules in a .htaccessfile in our folder:
First, we have to instruct the apache http server to activate the engine. Afterwards, we can specify rewrite rules. As htaccess files can contain many declarations, a rewrite rule is initiated with the string “RewriteRule”. A regular expression defines which requests we want to capture, followed by the destination we want to rewrite to. Lastly, we have further attributes.
The rules will be applied top to bottom, once a match is found, the attributes in brackets determine if further rules are applied: L specifies no further matching after applying this rule. The other used attribute, NC, explicitly tells apache to ignore case.
Within the regular expression, we can capture information: using brackets we tell the regular expression, that we want to preserve this part of the match and inject it in the position of “$1”.
As a final touch on the htaccess file, we want to rewrite any other request to a custom 404 reaction. We add a rewrite condition, which limits the next line of the configuration, to only apply if no matching file exists. This is necessary to prevent rewriting of our filenames to.php and exact.php.
Using this file, requests to /to/15 will be forwarded correctly to our previous implementation, as well as /10232 to our exact.php file.
Deployment
After finishing the productive part of our endeavour, it is time to think of deployment and providing the thirsty masses with easy access to our open source fizzbuzz solution (until we find a way to monetize a fizzbuzz SaaS of course).
You might think one of the reasons to chose PHP was simple deployment. But simple is in the eye of the beholder. If you are not already subscribed to such a service, you will need a PHP installation, an apache webserver, and maybe even a Linux! If someone deploys our software on an Nginx, it will not work, too. So the answer is obvious: docker.
To provide a docker version of our software, we require a Dockerfile. A simple textbased file specifying our requirements and actions. We can also choose a base image to use for our software. Fortunately, PHP provides apache based docker images.
FROM php:7.4-apache RUN a2enmod rewrite COPY src/ /var/www/html/ EXPOSE 80/tcp
We need to activate Apaches rewrite mod, which can simply be done using the run command. While run would allow us to install arbitrary software, we do not need anything else. Copy instructs docker do use our source folder at a specific place inside our docker container. Expose tells it that we require port 80 for TCP.
We can build a container image from our dockerfile using ‘docker build -t fizzbuzz .’ and run it using ‘docker run fizzbuzz -p 8080:80’, which will allow us to access the fizzbuzz API on ‘http://localhost:8080’.
Finally, we can share the generated image with all our clients or even distribute it via docker hub.
All sources can be found on GitHub. The actual docker container is also available on docker hub and running on fizzbuzz.ketzu.net.
Like many devs, I started a few projects. And like many devs, I never really finished them. My self made website CMS? There’s no admin panel. Once the front was done, I just started editing the tables using phpMyAdmin. My shitty idle game? It was stuck on version 0.11 with 7 half finished, or not even started, features. Or the insanely terrible 3D weekend game challenge.
But that 3D project gave me an idea. The basic capsule shape with the weird texture looked like a cactus to me — with enough fantasy at least. How about honoring that cactus, and make it into an actual game?
The 3D version didn’t work well, so how about a 2D platformer? Climbing up and up, evading deadly enemies, swinging on ropes! I instantly started with some character sketches.
It had to be a cactus. I already wondered how many people would question the jump abilities of a cactus though. Quickly I set up a unity project and started working.
The inital cactus design looked terrible in unity, quite a disappointment. So I created a smaller one, but tried to keep at least the “facial expression”. But I really wanted to keep the big design for something.
When I came across the 2D Animation Humble Bundle, I knew what I had to do. It was so obvious: A game needs videos! So without thinking, I bought it. It wasn’t as useful as I hoped, and probably a waste of money, as there are open source, or at least free, animation solutions out there. But it resulted in a nice, according to my standards, intro video.
When I finished the video after hours and hours of work, I felt like I was missing something. The game for the video! After setting up the unity project and creating a smaller character, I had done nothing. No gameplay, no menu — just emptiness.
Art and Features: Not Easily Seperatable
I decided to scrap some features I had imagined. Just getting the base gameplay down. Jumping and platforms. I started with the jumping.
The GDC talk on jumps made me create my own jumping physics. I even redid all the math, because I needed it in my own notation.
By now I believe, I should have stuck with unity mechanics, but I thought I had to do it manually. Implementing the jump and movement created a lot of problems later on, without much of a payoff: I couldn’t use many unity provided helpers, but had to solve most of the problems (e.g., getting stuck in platforms, not correctly using normals and more). But in the end, it worked somewhat as I expected: I could set jump height and length, or duration, and have a jump with those properties, which came in useful much later on platform generation.
Creating platforms took quite a lot of trial and error, until I found some that didn’t look completely terrible.
Originally I wanted to scale the platforms during the level. This turned out to be much harder than I expected. Getting the tiles correctly was the easy part, but the level generation was tricky.
At first I just created 4 platforms on each plane with random distances from each other. They mostly clipped into each other. I created an array of distance ratios of the game width, which summed up to 1 when including the width of the platforms. While that fixed the clipping, the level was extremly boring. Each layer was at roughly the maximum jump strength from the last and everything looked very uniform.
I needed a better level generator. So I wrote down all the constraints I had.
Most of them based on the jump properties, but also the width and height of the platform. I made many many miscalculations, forgot as many details as I remembered, but in the end it… kinda worked. Let’s say it was better than the previous one, and actually playable. I looked upon the game, and felt a little proud, but also that it was terrible.
I had two friends play the game (shoutout to Lazitus and Gariot, your suffering won’t be forgotten).
The worst bug was: Getting stuck in clouds, helplessly moving around. Unless you let go of the controls, then it would magically move you upwards! At least it wasn’t gamebreaking. I tried a lot of things. I came across Platform Effector 2D and noticed: unity had what i needed. Platform effectors modify the behaviour of collisions with platforms, e.g., allows a character to jump through from one side!
Remember when I said it was a mistake to implement the mnovement myself? Those don’t work if you do this. I tried implementing them myself, and it mostly worked. And by that, I mean: I could do as much as before, but still had the bug if the angle of collision was too low. So I scrapped all the complicated code, and used my simple version again, but put in more margin of safety and it mostly worked as well. Finally a finished game!
Visual Only User Interface
Unless you count having a UI instead of just an endless level. Then it was unpolished and unsueable! As I wanted to do everything myself, I created some UI sketches, which I then made into UI elements.
I had to build my own ring indicator and combined upgrade elements, but I didn’t have upgrades yet anyways, so I didn’t put too much thought into it. Maybe I should have.
One of my design goals was being able to use it without any language, so everyone that would like to play it, could do so. Mostly because I didn’t think there were more than 1 interested players if I restricted it to any language — I did call it ‘Shitty Cactus’ after all.
I made up some rough ranges for upgrade ideas and tested them. Jumping too high, would be detrimental, making it much harder. The same for many others. After some hours of playtesting, I came up with some values, split them and made up some costs. I linked everything in the UI and felt I was done. But the game felt open ended and unsatisfactory.
I decided that the game needed an outro video. It was easily created, if you disregard 10 hours of getting back into the animator software and failing to create anything in the way I imagined it. But how and when to play the video?
I tested some more, and felt 1200 was a good height to unlock it. But unlocking it, and switching to the play scene, would kill the progress. There’s a good and an easy solution to that! The good one, storing the state and being able to reload it. That would be useful in many other cases, too. Obviously I went with the easy one: Unlocking it, and you have to watch it in the main menu (or simply in the folder if you have the offline version).
Finally, I felt, I had a full game. But now I wanted to feel like a real game dev, so I decided to publish the game on steam for fun. It was quite the interesting experience. The requirements are easy: Pay 100$, fill out some tax forms, create lots of game art, have the shop page in “coming soon” mode for at least two weeks, and you get to release the game!
What steam doesn’t tell you: Once the shop page is online, you will get indie-game-marketing spam. It would have been nice, if they felt less than fully automated emails with a small placeholder for the game name. But that’s a lot to ask for such a small and terrible game. Though, I didn’t take this too seriously, so I didn’t respond.
Instead, I gave my friends each a free key and one told me: “It would be cool to have leaderboards.” That was the day I realised: There are leaderboards on steam.
Steam Leaderboards and Achievements
There is a nice implementation of the Steamworks steam SDK for C#, and therefore unity. It was especially easy to get into. Adding some statistics and leaderboards was covered by the example, so they could be added with little code. It was already time for my first patch!
As they say: Never play on patch day — and I enforced that! I never set up the steam pipeline, instead I uploadzip archives of the game folder. Those get preprocessed by Steam and are then published to players. This time, I zipped the folder. Not the contents. This made the game unplayable, as steam was configured to search “shitty cactus.exe” only in the root folder. Quickly I created a new patch and uploaded it, hoping none of my 3 players would notice — so I could tell them instead personally.
I worked so well, I started to look into steam achievements, the culmination of steam! It’s quite easy, if you base them on existing statistics. When you do that, they get awarded automatically, once a statistic above the threshold is submitted. Otherwise, you manually have to set the achievement from code. I opted to include only easy achievements for now, and created seven of them: Reach some height or reach a set amount of coins. One achievement for height was masked as a “play at least once” achievement, by setting the required game to height. I included a “don’t forget to jump!” in the description. Each achievement needs two pieces of art: Unlocked and not unlocked. Turns out, greyed out achievements are only a recommendation for not yet unlocked achievements.
After setting them up and publishing the changes, they were live instantly. It turned out, I only manged to get 3 out of 7, while a friend of mine and a reviewer from japan created highscores that felt insane to me.
Lastly, I wanted to try a feature of steam I didn’t know existed: Curator connect. You can send up to 5 keys to up to 100 curators and reviewers. To be honest, I just randomly selected reviewers at first and wrote “don’t play it, I just wanted to try the feature”.
In the end, 10 people bought the game, and one actually played it. The best thing about all of this, was the feeling when that one guy, a person I don’t know personally, reviewed the game without even being asked to: “It’s aight”.
After retracting the keys from the curators, I wroter a nicer message this time, something like “Seems like the game is not as bad as I thought, it would be nice to get a review, thanks.” I guess in the end, if you want someone to play your game, you have to tell people. And people don’t like bad self degrading humor in advertisements and even less in call outs to reviewers. Maybe I should stop prefixing my game names with ‘Shitty’.
That’s it. I continue to work on the game sometimes, currently I plan to add a leaderboard for shortest time to 1200, I want to try the steam sale feature, too. But I won’t do anything big with it.
Once I lose interest, I will put the whole project on github (probably january ’21 or later), but for now the repo is locked. It’s not a great game, but it’s not terrible either.
Don’t make the mistakes I made, believe in your game if you want it to be a success — whatever that means to you. But at least I can say: I shipped a game (and lost some money while doing it), which is a success in itself.