{
    "version": "https://jsonfeed.org/version/1",
    "title": "Daan Debie",
    "home_page_url": "https://www.daan.fyi/",
    "feed_url": "https://www.daan.fyi/feeds/feed.json",
    "description": "This is a feed of all posts on the website of Daan Debie",
    "icon": "https://www.daan.fyi/images/banner.png",
    "author": {
        "name": "Daan Debie",
        "url": "https://www.daan.fyi"
    },
    "items": [
        {
            "id": "https://www.daan.fyi/writings/mental-health",
            "content_html": "<p class=\"chakra-text css-ju3ovf\">Yesterday was the first day of my much-needed and much-deserved (if I may say so myself) 2-week vacation. We’re not\ngoing anywhere. Instead, this will be a staycation in which I allow myself to indulge in all of my hobbies outside\nof work, ranging from going on trips with my wife and dog, reading books, playing video games, working on <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://github.com/DonDebonair/slack-machine\">side-projects</a> and generally taking life as it comes. And these\nstaycations are usually a great opportunity to pay my social debts as well by seeing friends and family I haven’t\nseen for way too long.</p> <p class=\"chakra-text css-ju3ovf\">The first day of a typical staycation for me starts with sleeping in - preferably an outrageous amount - after which\nI will slowly get into some of the aforementioned activities. Yesterday started in such a way, but a couple of hours\nafter I got up, I was sitting on the couch bawling my eyes out, surrounded by my wife and dog who were trying to\nconsole me.</p> <p class=\"chakra-text css-ju3ovf\">This is what happened.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"keeping-up-with-current-events\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#keeping-up-with-current-events\"><span class=\"icon icon-link\"></span></a>Keeping up with Current Events</h2> <p class=\"chakra-text css-ju3ovf\">One of the first things I used to do after waking up, is to open the Apollo app to see what’s happening on Reddit.\nFor better of for worse, through <em>/r/news</em> and <em>/r/worldnews</em>, I tried to keep myself up-to-date on what is\nhappening in the world. After the <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://en.wikipedia.org/wiki/2023_Reddit_API_controversy\">2023 Reddit API</a> I\nrefuse to use Reddit anymore, so I looked for other outlets to consume news and being curious about local news as\nwell, I ended up frequenting <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.nu.nl/\">nu.nl</a>, a Dutch news outlet.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"comment-sections-are-the-worst\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#comment-sections-are-the-worst\"><span class=\"icon icon-link\"></span></a>Comment Sections Are the Worst</h2> <p class=\"chakra-text css-ju3ovf\">Everybody who’s been on the modern internet for more than 2 seconds knows this: comment sections on websites are the\nworst. And social media are basically just giant comment sections without useful content (which is why I don’t have\nFacebook/Instagram/Twitter accounts anymore). For some reason, I thought it would be a good idea to create an\naccount on nu.nl to have friendly discussions with my fellow citizens on the news of the day.</p> <p class=\"chakra-text css-ju3ovf\"><strong>I was dumb</strong></p> <p class=\"chakra-text css-ju3ovf\">Each day I got confronted more and more by how excruciatingly unempathetic, selfish, unreasonable and unkind people\nhave become. You used to be able to explain this by virtue of <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://knowyourmeme.com/memes/greater-internet-fuckwad-theory\">The Greater Internet Fuckwad Theory</a>, which states:</p> <blockquote class=\"css-p56y4k\"> <p class=\"chakra-text css-ju3ovf\">Normal Person + Anonymity + Audience = Total Fuckwad</p>\n</blockquote> <p class=\"chakra-text css-ju3ovf\"><em>- John Gabriel (2004)</em></p> <p class=\"chakra-text css-ju3ovf\">But a bunch of things have changed to make this even worse:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">Politicians have become more brazen and empowered to spread un-truths, ignore science and generally walk back on\nhard-won freedoms and improvements to the fabric of society</li><li class=\"css-0\">People, feeling unhappy about their lot in life and feeling empowered by those politicians, don’t even care about\nanonimity anymore. People are openly being dicks wherever you look</li></ul> <aside class=\"css-1t0hvt8\"> <div class=\"chakra-stack css-1igwmid\"> <svg stroke=\"currentColor\" fill=\"currentColor\" stroke-width=\"0\" viewBox=\"0 0 24 24\" focusable=\"false\" class=\"chakra-icon css-uzw9g2\" height=\"1em\" width=\"1em\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"></path><path d=\"M11 7h2v2h-2V7zm0 4h2v6h-2v-6zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z\"></path></svg> <h2 class=\"chakra-heading css-13djpho\">Dutch comment sections are even worse because of the 'polite form'</h2></div> <p class=\"chakra-text css-ju3ovf\">I have a personal pet peeve with Dutch comments on the internet. The Dutch language has 2 different pronouns to address\nthe person you’re speaking to. \"Je\" is the common form and \"U\" is the polite form.</p><p class=\"chakra-text css-ju3ovf\">The polite form is getting less and less use these days. But what I often see happening in Dutch comments on websites,\nis that people use \"U\" as some form of veneer to make their comment seem \"normal\" while trying to hide the uglyness of\nwhat they’re actually saying.</p><p class=\"chakra-text css-ju3ovf\">It will usually happen in reponse to someone being <em>actually</em> nice and trying to address some injustice, where\nthe person responding will then \"politely\" tell them that other people (or science) are not important.</p></aside> <h2 class=\"chakra-heading css-r5akja\" id=\"what-triggered-me\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#what-triggered-me\"><span class=\"icon icon-link\"></span></a>What Triggered Me</h2> <p class=\"chakra-text css-ju3ovf\">Yesterday, I read 2 news articles that in particular triggered emotional distress with me - and especially the\ncomments underneath the reporting on nu.nl on those topics:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\"> <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.theguardian.com/world/2023/jul/22/malaysia-festival-halted-matty-healy-1975-criticises-anti-lgbtq-laws\">Malaysia bans the 1975 after Matty Healy defies anti-LGBTQ+ laws with stage kiss</a>\n(<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.nu.nl/muziek/6273484/maleisie-breekt-festival-af-na-zoen-tussen-frontman-en-bassist-the-1975.html\">article on nu.nl</a>)</li><li class=\"css-0\"><a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://edition.cnn.com/2023/07/21/europe/italy-lesbian-couples-birth-certificates-scli-intl/index.html\">Italy starts removing lesbian mothers’ names from children’s birth certificates</a>\n(<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.nu.nl/buitenland/6273432/italie-schrapt-namen-niet-biologische-moeders-met-lhbtiq-relatie-uit-geboorteakten.html\">article on nu.nl</a>)</li></ul> <p class=\"chakra-text css-ju3ovf\">I care deeply about LGBTQI+ issues, not in the least because my father is gay, I have a transgender niece and I have\nmany people in my social circles that identify as LGBTQI+. And what makes me so sad is that - despite years of\nfighting for LGBTQI+ rights - I’m noticing a clear movement <em>backwards</em> on these topics. People seem to have this\nidea that the fight for equality, equity, diversity and inclusion is over now and they’re using this to argue we should\nsweep any expression of \"otherness\" under the rug.</p> <blockquote class=\"css-p56y4k\"> <p class=\"chakra-text css-ju3ovf\">I’m not against gay people, but why do you have to kiss in public?</p>\n</blockquote> <p class=\"chakra-text css-ju3ovf\"><em>- Paraphrased from a comment under an <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.nu.nl/pride/6273006/amsterdamse-pride-dit-jaar-dubbel-gevierd-dit-moet-je-erover-weten.html\">article about the Amsterdam Pride event</a></em></p> <p class=\"chakra-text css-ju3ovf\"><strong>If you cannot accept self-expression of other people different than you, you are effectively <em>against</em> those\npeople being different</strong></p> <h2 class=\"chakra-heading css-r5akja\" id=\"the-cult-of-i\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#the-cult-of-i\"><span class=\"icon icon-link\"></span></a>The Cult of I</h2> <p class=\"chakra-text css-ju3ovf\">The sentiment of people towards issues I consider to be <em>wrong</em> in the world - and that I naively believed were\n<em>generally</em> considered to be wrong - can be summed up by <strong>me, me me</strong>. This sentiment pervades both on personal and\nsocietal level:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">People increasingly care about only themselves, and want others - including the government - to optimize for\n<em>their</em> happiness and any cost to the happiness of others is considered acceptable. The most notable example is\nclimate change: even if people are willing to concede it’s real, a large group of people seem to be <em>completely</em>\nunwilling to accept even the smallest changes to their life-style for the greater good and the future of humanity\n(which includes their own children, grand-children etc.)</li><li class=\"css-0\">The previously common attitude in modern society to <em>live and let live</em> has been turned on its head. Instead of\nletting people that are \"different\" live their lives in a way they want, we’re seeing an increasing acceptance of\nletting bad actors suppress people that are \"different\". In a way, <em>live and let live</em> applies only to the\noppressors now. We <em>let</em> them get on with it.</li></ul> <span class=\"chakra-text css-1872at\">I use quotes with \"different\" because I happen to think that <em>everybody</em> is different in some way, including\nmyself</span> <p class=\"chakra-text css-ju3ovf\">The first point is not only prevalent on places like Twitter, Facebook, Reddit and the comment sections of the\naverage news outlet. Even LinkedIn - a professional networking website - is rife with people that love to\n\"challenge\" ideas to improve the global optimum just so they can optimize for their own local happiness. I lament the\npassing of the days when LinkedIn was about professionals discussing professional things professionally with each\nother.</p> <span class=\"chakra-text css-1872at\">But I’m happy to contribute to the downfall of professionalism on LinkedIn by posting this opinion piece once\nI’m done writing it</span> <p class=\"chakra-text css-ju3ovf\">It’s the second point that makes my blood truly boil, especially because the acceptance of oppression is done under\nthe guise of <em>reasonableness</em>. In the comment section on the article of The 1975 being banned from Malaysia, a\ncommon sentiment could be summed up as: <em>you go to their country, you follow their laws</em>. This completely ignores\nthat there is such a thing as <strong>Universal Human Rights</strong>.</p> <p class=\"chakra-text css-ju3ovf\">When you accept oppression - even under the guise of \"law\" - you let society slide downwards on a slippery slope and it\nwill not end well. I truly don’t think I’m being hyperbolic when I say this kind of acceptance is pretty much\n<em>exactly</em> what happened in Europe by the end of the 1930ies.</p> <p class=\"chakra-text css-ju3ovf\"><strong>We should <em>always</em> keep fighting for the rights of our fellow citizens and <em>borders</em> do not matter in that regard</strong></p> <h2 class=\"chakra-heading css-r5akja\" id=\"how-does-this-affect-my-mental-health\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#how-does-this-affect-my-mental-health\"><span class=\"icon icon-link\"></span></a>How Does This Affect My Mental Health</h2> <p class=\"chakra-text css-ju3ovf\">Society turning \"harder\" and \"colder\" by the day, causes depression in me. Reading how unreasonable and intolerant\nmy fellow citizens are, makes me immensely sad. It also makes me feel <strong>lonely</strong>, because it sometimes feels I’m the\nonly one who still cares about their fellow citizens that are not friends or family.</p> <p class=\"chakra-text css-ju3ovf\">To be honest, I had some pretty dark thoughts yesterday.</p> <blockquote class=\"css-p56y4k\"> <p class=\"chakra-text css-ju3ovf\">If only the whole of humanity would just die, it would be better for everyone, especially the rest of the species\nwe share our planet with</p>\n</blockquote> <p class=\"chakra-text css-ju3ovf\"><em>- Me, after reading one inane comment too many</em></p> <p class=\"chakra-text css-ju3ovf\">I feel a strong juxtaposition of the happiness induced by my wife, my pets, my friends and <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://source.ag/\">my job</a>\nand my increasing unhappiness with the world I live in. I’m sure other people have this as well, and part of me\nhopes that by writing this blog post, I’ll encounter people saying \"Hey, I feel this too!\" which would make me feel\nless lonely. But it is honestly increasinly hard to deal with.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"what-will-i-do-about-it\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#what-will-i-do-about-it\"><span class=\"icon icon-link\"></span></a>What Will I Do about It?</h2> <p class=\"chakra-text css-ju3ovf\">I resolve to talk more about these feelings I have with others. Maybe we can form a counter-movement. Maybe we can\nrebel against the tide of \"not caring\".</p> <p class=\"chakra-text css-ju3ovf\">I considered not reading these comment sections anymore. I’m not sure if I should or shouldn’t, because I also think\nthat if I can turn only one mind towards positivity and caring about others, I will have \"won\" a little. And not\nspeaking up is exactly what I’m trying to rebel against here.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"what-should-we-do-about-it\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#what-should-we-do-about-it\"><span class=\"icon icon-link\"></span></a>What Should We Do about It?</h2> <p class=\"chakra-text css-ju3ovf\">It is <em>really simple</em>. We (Society) should strive to <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://knowyourmeme.com/memes/wheatons-law\"><strong>not be a dick</strong></a>.\nYou should care about your fellow citizens. We should agree to uphold\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.un.org/en/about-us/universal-declaration-of-human-rights\">Universal Human Rights</a>.</p> <p class=\"chakra-text css-ju3ovf\">Here is one of its most simple tennets and it is to me the <em>core</em> of what each person is entitled to:</p> <blockquote class=\"css-p56y4k\"> <p class=\"chakra-text css-ju3ovf\">Everyone is entitled to all the rights and freedoms set forth in this Declaration, without distinction of any kind,\nsuch as race, colour, sex, language, religion, political or other opinion, national or social origin, property,\nbirth or other status. Furthermore, no distinction shall be made on the basis of the political, jurisdictional or\ninternational status of the country or territory to which a person belongs, whether it be independent, trust,\nnon-self-governing or under any other limitation of sovereignty.</p>\n</blockquote> <p class=\"chakra-text css-ju3ovf\"><em>- Article 2 of the Universal Declaration of Human Rights</em></p> <p class=\"chakra-text css-ju3ovf\">One important thing to note here, is that this only works if freedom of one group is not abused to limit the\nfreedoms of another group. This means for example that <strong>you cannot limit the rights of LGBTQI+ people because you\nwant to express your own religion</strong>.</p> <p class=\"chakra-text css-ju3ovf\">Furthermore, I think that the time of being accepting of <em>all opinions</em> should come to an end. Any opinion that\ninfringes on universal human rights, should not be tolerated. <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://en.wikipedia.org/wiki/Paradox_of_tolerance\">If we tolerate <em>everything</em>, we tolerate <strong>nothing</strong></a>.</p> <p class=\"chakra-text css-ju3ovf\">It is time that news outlets and social media - such as nu.nl - take responsibility and limit the ability of people\nto express thoughts that lead to oppression. It is for example <strong>not ok</strong> to express your \"opinion\" that same-sex\ncouples kissing is \"icky\" and should not be done in public. And news outlets and social media should not let you\nexpress such opinions in public.</p> <p class=\"chakra-text css-ju3ovf\">I personally would even go so far to state that scientifically proven facts should not be allowed to be contradicted\nwithout proper evidence to the contrary. Everyone should be able to challenge the status quo, but there is the <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://en.wikipedia.org/wiki/Scientific_method\">scientific method</a> you can follow to do this in a rigorous and\nfair way.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"ps-im-back\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#ps-im-back\"><span class=\"icon icon-link\"></span></a>PS: I’m Back?</h2> <p class=\"chakra-text css-ju3ovf\">When I started the new version of my blog, I promised that I would write more. That hasn’t really materialized and I\ndon’t know if it will. I felt so strongly about the topic of this blog post, that I wanted to write down my thoughts.\nLet’s see if that will happen more often.</p> <p class=\"chakra-text css-ju3ovf\">Peace!</p><span></span><span id=\"__chakra_env\" hidden=\"\"></span>",
            "url": "https://www.daan.fyi/writings/mental-health",
            "title": "How the State of the World Affects My Mental Health",
            "summary": "I sometimes have a hard time coping with the ugliness of people's opinions on the internet and in the world at large.",
            "date_modified": "2023-07-23T00:00:00.000Z"
        },
        {
            "id": "https://www.daan.fyi/writings/iam",
            "content_html": "<p class=\"chakra-text css-ju3ovf\">All access management in AWS is done through <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://aws.amazon.com/iam/\"><strong>AWS Identity and Access Management</strong></a>\n(or <em>IAM</em> in short). IAM provides a way to configure <em>who</em> can do <em>what</em> in an AWS account.\nThe \"who\" in this case can be humans, machines/software or other AWS services.</p> <p class=\"chakra-text css-ju3ovf\">IAM is quite complex and there are several concepts you need to understand in order to know how to\ngive people, software and machines the right access to the right resources in your AWS Accounts.\nThis can become complicated quite fast if you’re managing multiple AWS Accounts with many different\nresources and services, as explained in the <a class=\"chakra-link css-3u9hqk\" href=\"https://www.daan.fyi/aws-multi-account\">previous post in this series</a>.</p> <p class=\"chakra-text css-ju3ovf\">In this blog post I’m going to attempt to explain the terminology in a clear and concise way. Over\nthe past months, we worked hard at <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://source.ag/\">Source.ag</a> to create a good setup for our\nAWS-hosted infrastructure. I feel that this gave me a solid understanding of how IAM works\n(among other things). This blog post will help me personally as a kind of <em>cheat sheet</em> for later\nrecall and hopefully be of use to others to whom these concepts are still new.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"accounts-and-resources\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#accounts-and-resources\"><span class=\"icon icon-link\"></span></a>Accounts and Resources</h2> <p class=\"chakra-text css-ju3ovf\">A <strong>Resource</strong> in AWS is basically any piece of infrastructure or any AWS service you can pay for\nand use. This also represents the things you want to control access to. Some examples of this: <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://aws.amazon.com/ec2/\"><strong>EC2</strong></a> servers and <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://aws.amazon.com/s3/\"><strong>S3</strong></a> buckets.</p> <p class=\"chakra-text css-ju3ovf\">For all these resources, you can control who or what can access them and to what extent.</p> <p class=\"chakra-text css-ju3ovf\">An <strong>Account</strong> in AWS is a container for resources. So it’s <strong><em>not</em> a representation of a human</strong>\nusing AWS services. In that sense, it’s quite different from the typical definition of an account\nin online services like Twitter or Facebook, where accounts are digital extensions of human beings.</p> <p class=\"chakra-text css-ju3ovf\">An AWS Account is used to <strong>create, manage and pay for resources</strong>. It can be similar to an\n<em>environment</em> or <em>project</em>, with servers, databases, S3 buckets etc.</p> <p class=\"chakra-text css-ju3ovf\">Even though an account does not represent a user, it still has — confusingly — a unique email\naddress attached to it and a password to log in. This login represents the <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html\"><em>AWS account root user</em></a> of\nan AWS account.</p> <aside class=\"css-xo30cl\"> <div class=\"chakra-stack css-1igwmid\"> <svg stroke=\"currentColor\" fill=\"currentColor\" stroke-width=\"0\" viewBox=\"0 0 24 24\" focusable=\"false\" class=\"chakra-icon css-4dqk3f\" height=\"1em\" width=\"1em\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" d=\"M0 0h24v24H0z\"></path><path d=\"M12 12.9l-2.13 2.09c-.56.56-.87 1.29-.87 2.07C9 18.68 10.35 20 12 20s3-1.32 3-2.94c0-.78-.31-1.52-.87-2.07L12 12.9z\"></path><path d=\"M16 6l-.44.55C14.38 8.02 12 7.19 12 5.3V2S4 6 4 13c0 2.92 1.56 5.47 3.89 6.86-.56-.79-.89-1.76-.89-2.8 0-1.32.52-2.56 1.47-3.5L12 10.1l3.53 3.47c.95.93 1.47 2.17 1.47 3.5 0 1.02-.31 1.96-.85 2.75 1.89-1.15 3.29-3.06 3.71-5.3.66-3.55-1.07-6.9-3.86-8.52z\"></path></svg> <h2 class=\"chakra-heading css-13djpho\">AWS Account root users should not be regularly used!</h2></div> <p class=\"chakra-text css-ju3ovf\">You could use the AWS Account root user to do <em>anything</em> you want in an AWS Account. It is a bad\nhabit to do so. This <strong>root</strong> user is basically the keys to the kingdom and as such, should be\nlocked away securely and not be used for everyday tasks.</p><p class=\"chakra-text css-ju3ovf\">Instead, you should create separate IAM and/or AWS SSO users for normal tasks, even for\nadministrator tasks.</p></aside> <h2 class=\"chakra-heading css-r5akja\" id=\"identities-in-aws\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#identities-in-aws\"><span class=\"icon icon-link\"></span></a>Identities in AWS</h2> <p class=\"chakra-text css-ju3ovf\">So if <em>Accounts</em> in AWS do not represent human users, how is <strong>identity</strong> established so that\naccess can be granted to resources in AWS Accounts?</p> <p class=\"chakra-text css-ju3ovf\">This is done through <strong>Users, Roles and Groups</strong>. All three are a form of <strong>Identity</strong> in AWS.\nAn Identity is something that can be granted access to an AWS service or resource.</p> <h3 class=\"chakra-heading css-10qrs2m\" id=\"iam-users\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#iam-users\"><span class=\"icon icon-link\"></span></a>IAM Users</h3> <p class=\"chakra-text css-ju3ovf\">An <strong>IAM User</strong> represents a human that can log into AWS and/or leverage the AWS API to use\nAWS services and access resources on AWS. An IAM User has 2 sets of credentials:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\"><strong>Username/Password</strong>: used to log into the web-based <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://aws.amazon.com/console/\"><em>AWS Management Console</em></a></li><li class=\"css-0\"><strong>Access Key/Access Key Secret</strong>: used to access AWS programmatically through the API and/or command line</li></ul> <p class=\"chakra-text css-ju3ovf\">Two key things to understand about IAM users:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">a regular IAM User does <strong>not</strong> have an email address attached to it</li><li class=\"css-0\">IAM Users are created <em>within a single AWS Account</em> and (usually) only have access to resources\nwithin that account</li></ul> <p class=\"chakra-text css-ju3ovf\">As we’ll see later, there are special kinds of users you can create that <em>do have an email address</em>\nand can access resources in multiple AWS Accounts. These are created through AWS SSO.</p> <p class=\"chakra-text css-ju3ovf\">IAM Users can have permissions (policies, see below) that dictate what they can and cannot do on\nAWS. These permissions are used to allow/deny access to AWS services and resources.</p> <p class=\"chakra-text css-ju3ovf\">Users usually represent humans but can also represent software and machines <em>outside of AWS</em> that\nyou want to give programmatic access to certain AWS services and resources through the AWS API.\nIf you want to grant software running <em>inside</em> AWS access to other AWS services and resources, you\ncan use <strong>Roles</strong>.</p> <h3 class=\"chakra-heading css-10qrs2m\" id=\"iam-roles\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#iam-roles\"><span class=\"icon icon-link\"></span></a>IAM Roles</h3> <p class=\"chakra-text css-ju3ovf\">A <strong>Role</strong> in IAM is similar to a User in that it is an Identity with permissions that determine\nwhat it can and cannot do within AWS. The difference with a User is that a Role is not tied to a\nspecific human or machine. Instead, a role can be <strong>assumed</strong> by users or AWS services to\ntemporarily gain access to certain AWS services and/or resources.</p> <p class=\"chakra-text css-ju3ovf\">Roles do not have permanent login/API credentials. Instead, a role provides temporary credentials\nwhen the role is assumed.</p> <h3 class=\"chakra-heading css-10qrs2m\" id=\"iam-groups\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#iam-groups\"><span class=\"icon icon-link\"></span></a>IAM Groups</h3> <p class=\"chakra-text css-ju3ovf\">In IAM, <strong>Groups</strong> are used to group Users together so the same permissions (<em>policies</em>, see below)\ncan be applied to multiple Users at once.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"granting-and-denying-access-policies\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#granting-and-denying-access-policies\"><span class=\"icon icon-link\"></span></a>Granting and Denying Access: Policies</h2> <p class=\"chakra-text css-ju3ovf\">Now that we have established that we have <em>Resources</em> <span class=\"css-g43xk1\"><strong>*</strong></span>\nand <em>Identities</em><span class=\"css-g43xk1\"><strong>*</strong></span> that can potentially access those\nResources, how exactly do we determine <em>who</em> can access <em>what</em>?</p> <p class=\"chakra-text css-ju3ovf\">This is done through <strong>Policies</strong>. In IAM, Policies are basically <em>permissions</em> on <em>resources</em></p> <p class=\"chakra-text css-ju3ovf\">A policy defines access (or denial) to an AWS service and/or resource. There are 2 types of policies:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\"><strong>Identity-based policy</strong>: this policy is attached to a certain <em>Identity</em> to allow/deny this identity access to one or more Resources</li><li class=\"css-0\"><strong>Resource-based policy</strong>: this policy is attached to a <em>Resource</em> to define access to that Resource</li></ul> <p class=\"chakra-text css-ju3ovf\">A policy contains the following elements:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\"><strong>Effect</strong>: should we <em>allow</em> or <em>deny</em> something?</li><li class=\"css-0\"><strong>Resource</strong>: what do we want to control access to?</li><li class=\"css-0\"><strong>Action</strong>: what action is allowed/denied?</li><li class=\"css-0\"><strong>Principal</strong>: who should be allowed/denied access?</li></ul> <p class=\"chakra-text css-ju3ovf\">The <em>Principal</em> is only specified in the case of Resource-based policies. That makes sense if you\nthink about it, because in the case of Identity-based policies, the Principal is the Identity itself\nthe policy is attached to!</p> <h3 class=\"chakra-heading css-10qrs2m\" id=\"example-identity-based-policy\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#example-identity-based-policy\"><span class=\"icon icon-link\"></span></a>Example: Identity-Based Policy</h3> <p class=\"chakra-text css-ju3ovf\">Let’s say that we want to give IAM User <em>kiara</em> access to read all files in the <code class=\"chakra-code css-lqvy6z\">confidential-data</code>\nS3 bucket. What would the Effect, Resource and Action look like for our policy? The policy would\nlook something like this:</p>\n<pre class=\"language-json\"> <code class=\"chakra-code language-json css-lqvy6z\"><span class=\"token punctuation\">{</span>\n<span class=\"token property\">\"Effect\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Allow\"</span><span class=\"token punctuation\">,</span>\n<span class=\"token property\">\"Action\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n<span class=\"token string\">\"s3:List*\"</span><span class=\"token punctuation\">,</span>\n<span class=\"token string\">\"s3:Get*\"</span>\n<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n<span class=\"token property\">\"Resource\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n<span class=\"token string\">\"arn:aws:s3:::confidential-data\"</span><span class=\"token punctuation\">,</span>\n<span class=\"token string\">\"arn:aws:s3:::confidential-data/*\"</span>\n<span class=\"token punctuation\">]</span>\n<span class=\"token punctuation\">}</span>\n</code></pre> <p class=\"chakra-text css-ju3ovf\">This policy would then be attached to the IAM User <em>kiara</em> to grant her access.</p> <h3 class=\"chakra-heading css-10qrs2m\" id=\"its-a-matter-of-principal\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#its-a-matter-of-principal\"><span class=\"icon icon-link\"></span></a>It’s a Matter of Principal</h3> <p class=\"chakra-text css-ju3ovf\">As mentioned before, for Identity-based policies, you don’t need to specify a Principal. But what\nexactly <em>is</em> a Principal? Is it the same as an <em>Identity</em>? It turns out it’s more than that:</p> <p class=\"chakra-text css-ju3ovf\">A Principal is an AWS identity <strong>or Service</strong>. To understand why services can be used as Principal,\nwe have to understand where Principals are specified, which is in 2 places:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">In a Resource-based policy, the principal determines <em>who</em> can access the resource the policy is attached to</li><li class=\"css-0\">In a Role, the principal determines who (what Identity) can assume the role</li></ul> <p class=\"chakra-text css-ju3ovf\">When specifying a Principal in a Role, we can say that instead of allowing a regular (human) User\nto assume the Role, we can allow an AWS Service (e.g. AWS Lambda) to assume the role for us. An\nexample of how this can be useful: we could allow a function run on AWS Lambda to send a message on\nan SNS topic for us whenever something important happens during its execution. To do this, we would\ncreate a special Role for this Lambda function with a Policy attached that would allow this Role\nto publish messages on an SNS topic. Then we would allow AWS Lambda to assume this Role.</p> <h3 class=\"chakra-heading css-10qrs2m\" id=\"resource-based-policies\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#resource-based-policies\"><span class=\"icon icon-link\"></span></a>Resource-Based Policies</h3> <p class=\"chakra-text css-ju3ovf\">What is perhaps counter-intuitive, is that <em>Identity-based policies</em> are more common than\n<em>Resource-based policies</em> for defining access to resources. The common way of doing things, is to\nattach policies to Identities to specify what <em>Resources</em> they have access to and in what ways.</p> <p class=\"chakra-text css-ju3ovf\">Part of the reason is that Resource-based policies are not supported by all services and\nresource-types in AWS, whereas you can use any Resource identifier in an Identity-based polity.</p> <p class=\"chakra-text css-ju3ovf\"><strong>So in what situations are Resource-based policies being used?</strong></p> <p class=\"chakra-text css-ju3ovf\">Resource-based policies are often used when you want to grant an Identity <strong>outside your AWS\naccount</strong> access to a Resource in your AWS account. To understand how this works, let’s assume the\nfollowing scenario:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">There are 2 AWS Accounts: Account A (managed by Company A) and Account B (managed by Company B)</li><li class=\"css-0\">Account A has a special Resource: S3 bucket <code class=\"chakra-code css-lqvy6z\">secret-stuff</code></li><li class=\"css-0\">Company A wants to grant Company B access to the <code class=\"chakra-code css-lqvy6z\">secret-stuff</code> bucket</li><li class=\"css-0\">Company B decides that they want to use User X to access the <code class=\"chakra-code css-lqvy6z\">secret-stuff</code> bucket that Company A\nas granted them access to</li></ul> <p class=\"chakra-text css-ju3ovf\">To make this happen you have to do 2 things:</p> <ol role=\"list\" class=\"css-bux2of\"><li class=\"css-0\"><strong>Allow access from AWS Account B to a specific Resource</strong> (the <code class=\"chakra-code css-lqvy6z\">secret-stuff</code> bucket): on the\naforementioned S3 bucket, we would create a <em>Resource-based policy</em> that has <em>AWS Account B</em> as\nprincipal</li><li class=\"css-0\"><strong>Allow access from a specific Identity in Account B to a specific Resource in Account A</strong>: on\nthe <em>IAM User X</em> that we want to grant access to, we would create an <em>Identity-based policy</em> to\ngrant access specifically to the <code class=\"chakra-code css-lqvy6z\">secret-stuff</code> bucket, which happens to live in AWS Account A.</li></ol> <p class=\"chakra-text css-ju3ovf\">What is interesting here, is that Company A would have no say in exactly what <em>Identity</em> is used\nby Company B — in AWS Account B — to access their resource. The only thing they would control, is\nthe fact that AWS Account B can access their resource in AWS Account A. It is Account B where it is\ndetermined exactly what Identity gets to access the <code class=\"chakra-code css-lqvy6z\">secret-stuff</code> bucket.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"iam-with-multiple-aws-accounts-organizations\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#iam-with-multiple-aws-accounts-organizations\"><span class=\"icon icon-link\"></span></a>IAM with Multiple AWS Accounts: Organizations</h2> <p class=\"chakra-text css-ju3ovf\">As explained in the <a class=\"chakra-link css-3u9hqk\" href=\"https://www.daan.fyi/aws-multi-account\">previous blog post</a>, you can leverage AWS Organizations to\ngroup multiple AWS Accounts together to consolidate billing but also access control.</p> <p class=\"chakra-text css-ju3ovf\">How does IAM work in the context of AWS Organizations? This happens through 2 additional concepts:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">AWS SSO Users & Groups</li><li class=\"css-0\">Permission sets</li></ul> <h3 class=\"chakra-heading css-10qrs2m\" id=\"aws-sso\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#aws-sso\"><span class=\"icon icon-link\"></span></a>AWS SSO</h3> <p class=\"chakra-text css-ju3ovf\">AWS Single Sign-on lets you define Users and Groups in a central place — usually in the\n<em>management account</em> of your AWS Organization — and control access to resources in all AWS Accounts\nin an Organization for those Users and Groups.</p> <p class=\"chakra-text css-ju3ovf\"><strong>SSO Users</strong> have a few fundamental differences compared to regular IAM users:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">SSO Users have an email address to identify them</li><li class=\"css-0\">SSO Users usually have access to resources in <em>multiple</em> AWS Accounts</li><li class=\"css-0\">SSO Users don’t have (Identity-based) policies attached directly to them</li></ul> <p class=\"chakra-text css-ju3ovf\"><strong>SSO Groups</strong> are similar to IAM Groups in that they’re used to group together Users so that the\nsame policies can be applied to all users within a group. A key difference here is that — just\nlike with SSO Users — policies are not attached to SSO Groups directly.</p> <p class=\"chakra-text css-ju3ovf\">If you cannot attach policies to SSO Users & Groups directly, how can you allow those Users & Groups\naccess to resources in the AWS Accounts in your Organization? This is done through\n<strong>Permission Sets</strong>.</p> <h3 class=\"chakra-heading css-10qrs2m\" id=\"permission-sets\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#permission-sets\"><span class=\"icon icon-link\"></span></a>Permission Sets</h3> <p class=\"chakra-text css-ju3ovf\">Permission Sets are basically the AWS SSO alternative to regular IAM Policies. They are set up in a\nvery similar way — with Effects, Actions and Resources. The big difference is that Permission Sets\nare not applied to an SSO User/Group alone, but they are applied in combination with an AWS Account.</p> <p class=\"chakra-text css-ju3ovf\"><strong>A Permission Set is applied to an SSO User/Group for a <em>specific AWS Account</em></strong></p> <p class=\"chakra-text css-ju3ovf\">This means that when you apply a Permission Set to an SSO User/Group, you choose an AWS Account so\nthat the policies defined in the Permission Set are applied to the SSO User/Group <em>for the selected\nAWS Account</em>.</p> <p class=\"chakra-text css-ju3ovf\">Example: let’s say you have created a Permission Set that allows read-only access to all resources.\nNow you can grant <code class=\"chakra-code css-lqvy6z\">kiara@examplecorp.com</code> read access to all resources in Account A in your\nOrganization by applying the aforementioned Permission Set to <code class=\"chakra-code css-lqvy6z\">kiara@examplecorp.com</code> <em>specifically</em>\nfor Account A.</p> <p class=\"chakra-text css-ju3ovf\">Permission Sets encourage reuse of similar policies across AWS Accounts and SSO Users.</p> <h3 class=\"chakra-heading css-10qrs2m\" id=\"how-aws-applies-access-control-in-sso\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#how-aws-applies-access-control-in-sso\"><span class=\"icon icon-link\"></span></a>How AWS Applies Access Control in SSO</h3> <p class=\"chakra-text css-ju3ovf\">If you apply a Permission Set to an SSO User for a specific AWS Account, how does that work\ninternally? In the end, AWS will still use IAM to do the actual access management. For each\nPermission Set you apply to a certain AWS Account — for 1 or more SSO Users/Groups — AWS will\ncreate a dedicated Role in that AWS Account. Let’s say that in the example above where we want to\ngrant <em>read-only</em> access, we called the Permission Set <code class=\"chakra-code css-lqvy6z\">ReadOnlyPermissions</code>. When we apply this\nPermission Set to Account A for <code class=\"chakra-code css-lqvy6z\">kiara@examplecorp.com</code>, AWS will do 3 things:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">It will create a Role in Account A based on the <code class=\"chakra-code css-lqvy6z\">ReadOnlyPermissions</code> Permission Set</li><li class=\"css-0\">It will attach policies to that Role according to the policies defined in the <code class=\"chakra-code css-lqvy6z\">ReadOnlyPermissions</code>\nPermission Set</li><li class=\"css-0\">It will add <code class=\"chakra-code css-lqvy6z\">kiara@examplecorp.com</code> as Principal to the created Role so she can assume that Role\nin Account A</li></ul> <p class=\"chakra-text css-ju3ovf\">Now when <code class=\"chakra-code css-lqvy6z\">kiara@examplecorp.com</code> logs into AWS using SSO, she will be presented with a choice to\nassume the <code class=\"chakra-code css-lqvy6z\">ReadOnlyPermissions</code> Role in Account A — next to all the other Roles she can assume\nin the same or other AWS Accounts in the Organization, all based on the Permission Sets applied\nto her for specific Accounts.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"conclusion\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#conclusion\"><span class=\"icon icon-link\"></span></a>Conclusion</h2> <p class=\"chakra-text css-ju3ovf\">When I started writing this post, I hoped it would be concise. I guess I failed a bit on that\naccount, which just goes to show how complex AWS IAM really is. I still hope that this gives you an\noverview that is easier to digest than reading through pages of AWS documentation.</p> <hr aria-orientation=\"horizontal\" class=\"chakra-divider css-1vt04vx\"/> <p class=\"chakra-text css-ju3ovf\"><em>Thanks to <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://twitter.com/djvdorp\">Dan</a> for proofreading this yet again! ❤️</em></p><span></span><span id=\"__chakra_env\" hidden=\"\"></span>",
            "url": "https://www.daan.fyi/writings/iam",
            "title": "Aws Iam Demystified",
            "summary": "AWS Identity and Access Management (IAM) provides a way to configure who can do what in AWS Accounts. It's powerful but also hard to understand. This post explains the basics.",
            "date_modified": "2022-03-21T00:00:00.000Z"
        },
        {
            "id": "https://www.daan.fyi/writings/aws-multi-account",
            "content_html": "<p class=\"chakra-text css-ju3ovf\">Don’t you just love the freedom of working at an early stage startup, with a relentless focus on\nproduct and a blatant disregard for any non-functional distractions? I do.</p> <p class=\"chakra-text css-ju3ovf\">When I started working at <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://source.ag\">Source</a> about 9 months ago, it was just me — the\nfirst employee — and the 2 founders. The only code written, were a couple of demos for investor\npitches which we threw away quickly. I was in the luxurious position to be able to start building\nour product <em>from scratch</em>. I deployed <em>everything</em> I built into <strong>a single AWS root account</strong>.</p> <p class=\"chakra-text css-ju3ovf\">Fast-forward to today, and we’re with more than 30 people — most of whom are software engineers\nand data scientists writing and deploying code. In December, we finished migrating all of our\ninfrastructure to a <strong>multi-account setup</strong> in AWS. In this blog post I want to explain why we\ndid this and what our multi-account setup looks like.</p>\n<img alt=\"Buy why?!\" loading=\"lazy\" width=\"729\" height=\"393\" decoding=\"async\" data-nimg=\"1\" style=\"color:transparent\" srcSet=\"/_next/image?url=%2Fimages%2Fbutwhy.gif&w=750&q=75 1x, /_next/image?url=%2Fimages%2Fbutwhy.gif&w=1920&q=75 2x\" src=\"https://www.daan.fyi/_next/image?url=%2Fimages%2Fbutwhy.gif&w=1920&q=75\"/> <h2 class=\"chakra-heading css-r5akja\" id=\"when-the-cracks-start-showing\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#when-the-cracks-start-showing\"><span class=\"icon icon-link\"></span></a>When the Cracks Start Showing</h2> <p class=\"chakra-text css-ju3ovf\">As mentioned, when we started everything was deployed into a single AWS account.\nWhen the moment came that we wanted to have separate development and production environments, I\ncreated 2 VPCs in the same account and deployed an identical setup in both, each consisting of:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">An ECS cluster for our backend services</li><li class=\"css-0\">A PostgreSQL database on RDS for persistence</li><li class=\"css-0\">Some S3 buckets for storing unstructured data</li><li class=\"css-0\">Some Lambdas for data processing.</li></ul> <p class=\"chakra-text css-ju3ovf\">It looked something like this:</p>\n<img alt=\"All AWS resources in 1 account\" loading=\"lazy\" width=\"2000\" height=\"1069\" decoding=\"async\" data-nimg=\"1\" style=\"color:transparent\" srcSet=\"/_next/image?url=%2Fimages%2Faws-single-account.png&w=2048&q=75 1x, /_next/image?url=%2Fimages%2Faws-single-account.png&w=3840&q=75 2x\" src=\"https://www.daan.fyi/_next/image?url=%2Fimages%2Faws-single-account.png&w=3840&q=75\"/> <p class=\"chakra-text css-ju3ovf\">I deployed our applications and services (except for our frontend, which is deployed on Vercel) in\ntwo identical VPCs — still living in the same AWS account — and called it a day.</p> <hr aria-orientation=\"horizontal\" class=\"chakra-divider css-1vt04vx\"/> <p class=\"chakra-text css-ju3ovf\">When we started building our team and the first software engineers and data scientists joined, I\ncreated IAM users for everyone and solved access control by defining groups with specific IAM\npolicies (permissions) attached to them and adding the IAM users to those groups. The more people\njoined the team, the more diverse the access requirements became, for example:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">A data scientist does not need access to the same things as a software engineer</li><li class=\"css-0\">A junior person does not need the same <em>level</em> of access as a senior person</li></ul> <p class=\"chakra-text css-ju3ovf\">And there are many more subtle differences in the kind of access to infrastructure people need and\nshould have.</p> <h3 class=\"chakra-heading css-10qrs2m\" id=\"single-account-problems-in-a-nutshell\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#single-account-problems-in-a-nutshell\"><span class=\"icon icon-link\"></span></a>Single-Account Problems in a Nutshell</h3> <p class=\"chakra-text css-ju3ovf\">In the end, our single-account setup made it difficult to build a secure and resilient\ninfrastructure:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\"><strong>It is less secure</strong>. If someone gains access to this one account, they have\naccess to <em>everything</em>. It’s hard to separate resources for different environments\n(e.g. production, development) and treat these resources differently security wise.</li><li class=\"css-0\"><strong>It is less safe and resilient</strong>. If something goes wrong with one environment (e.g. development),\nit’s easy to affect services in other environments (e.g. production) when they’re in the same\naccount. They get caught in the <em>blast radius</em></li><li class=\"css-0\"><strong>It’s hard to maintain</strong>. All AWS resources live in 1 account so when different users need\ndifferent levels of access, this needs to be controlled on a per-resource level, which is hard to\nconfigure and keep track of</li><li class=\"css-0\"><strong>It’s hard to control spend in this way</strong>. Once certain access is granted to create new resources,\nthere is no limit to how many resources can be created and what services can be used</li></ul> <p class=\"chakra-text css-ju3ovf\">Many of these problems <em>can</em> actually be solved — even in a single-account setup — by \"properly\"\ntagging all your AWS resources and creating elaborate IAM policies for users and resources based on\nthose tags. But such a tagging strategy will quickly become really complex and will cost a lot of\ntime to maintain. Needless to say that it’s quite error-prone as well.</p> <p class=\"chakra-text css-ju3ovf\">Aside from the security and safety implications, our setup had some other problems:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">All IAM Users were created and managed through CDK/CloudFormation, because we love <em>Infrastructure\nas Code</em>. This is problematic:\n<ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">It makes it possible for anyone with access to CloudFormation to see all Access Keys + Secrets</li><li class=\"css-0\">It’s not easy to scale, because we now need to manually deploy a CDK stack when new users need\nto be added</li><li class=\"css-0\">It’s hard to broadly define policies for different access patterns in this way</li></ul>\n</li><li class=\"css-0\">Users have to use a separate set of credentials for accessing AWS instead of using an existing\nlogin (i.e. their Google Workspace account)</li></ul> <h2 class=\"chakra-heading css-r5akja\" id=\"there-is-a-better-way\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#there-is-a-better-way\"><span class=\"icon icon-link\"></span></a>There Is a Better Way</h2> <p class=\"chakra-text css-ju3ovf\">When I was researching a way forward, I found <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://aws.amazon.com/blogs/mt/governance-risk-and-compliance-when-establishing-your-cloud-presence/\">many</a>\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.parkmycloud.com/blog/aws-multi-account-strategy/\">blog</a> <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://medium.com/@mailyashacharya/aws-account-strategy-for-every-business-22aad27b7fa1\">posts</a>\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://medium.com/cloudpegboard/aws-multi-account-management-has-come-of-age-510ddf33f9d3\">extolling the virtues</a>\nof putting your infrastructure into multiple AWS accounts. But before getting a better\nunderstanding of how this would work, I had some reservations about using multiple AWS accounts:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">Do I need to create multiple IAM users for each person, so they can log in to multiple accounts?</li><li class=\"css-0\">How do we control costs? Do I need to keep track of different bills for each account?</li><li class=\"css-0\">How can I share resources, such as reusable Docker images or shared data in an S3 bucket?</li></ul> <p class=\"chakra-text css-ju3ovf\">AWS offers a nice solution to these problems (and others) in the form of <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/core-concepts.html#aws-organizations\"><strong>AWS Organizations</strong></a></p> <p class=\"chakra-text css-ju3ovf\">According to AWS:</p> <blockquote class=\"css-p56y4k\"> <p class=\"chakra-text css-ju3ovf\">An organization is an entity that you create to consolidate a collection of accounts so that you\ncan administer them as a single unit.</p>\n</blockquote>\n<img alt=\"What does that even mean?!\" loading=\"lazy\" width=\"300\" height=\"300\" decoding=\"async\" data-nimg=\"1\" style=\"color:transparent\" srcSet=\"/_next/image?url=%2Fimages%2Fwhatdoesthatevenmean.gif&w=384&q=75 1x, /_next/image?url=%2Fimages%2Fwhatdoesthatevenmean.gif&w=640&q=75 2x\" src=\"https://www.daan.fyi/_next/image?url=%2Fimages%2Fwhatdoesthatevenmean.gif&w=640&q=75\"/> <p class=\"chakra-text css-ju3ovf\">AWS Organizations lets you organize a bunch of related AWS accounts in a hierarchical, tree-like\nstructure. It will let you manage all those accounts from one central <em>management account</em>. With\n<em>Consolidated Billing</em>, all bills from all member accounts will be aggregated to the management\naccount where you can pay them as one.</p> <p class=\"chakra-text css-ju3ovf\">Arguably the most powerful feature of AWS Organizations is that you can group the member accounts\ntogether in <em>Organizational Units</em> (OUs) and apply common security policies to those. This lets you\ndefine permissions and control access in broad strokes — and from a central place — while keeping\nthe natural separation of concerns that comes from using separate AWS accounts to organize your\ninfrastructure.</p> <h3 class=\"chakra-heading css-10qrs2m\" id=\"easy-user-management-using-aws-sso\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#easy-user-management-using-aws-sso\"><span class=\"icon icon-link\"></span></a>Easy User Management Using AWS SSO</h3> <p class=\"chakra-text css-ju3ovf\">When it comes to user management, AWS Organizations offers the convenience of letting users log in\nwith <em>one</em> user account (not to be confused with AWS account), using <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://aws.amazon.com/single-sign-on/\"><em>AWS Single Sign-on</em></a>. AWS SSO lets you create users in\nthe <em>root account</em> (also known as <em>management account</em>) of your organization and\ngive them login credentials within AWS itself or link them to an external <em>identity provider</em>\nlike Google or Active Directory. You can then give these users access to specific AWS accounts within\nyour AWS Organization. Users can be assigned specific permissions within these accounts. <span class=\"chakra-text css-1872at\">(I will explain more on how this works in a later blog post)</span></p> <p class=\"chakra-text css-ju3ovf\">This has several advantages compared to using regular IAM users:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">Users only need <em>one</em> set of credentials to log into multiple AWS Accounts</li><li class=\"css-0\">Everyone can log in using credentials they already use on a daily basis (Google Workspace\ncredentials in our case)</li><li class=\"css-0\">There is no more need to create and manage IAM users through CDK</li><li class=\"css-0\">There is no credential leakage through CloudFormation</li><li class=\"css-0\">We can potentially automate user creation by programmatically syncing AWS users and Google\nWorkspace users</li></ul> <h2 class=\"chakra-heading css-r5akja\" id=\"what-does-a-good-aws-organization-setup-look-like\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#what-does-a-good-aws-organization-setup-look-like\"><span class=\"icon icon-link\"></span></a>What Does a Good AWS Organization Setup Look like?</h2> <p class=\"chakra-text css-ju3ovf\">Well, I don’t know. But I do know what works for us <span class=\"chakra-text css-1872at\">so far</span></p> <p class=\"chakra-text css-ju3ovf\">When deciding what AWS accounts to create and how to group them, I had the following requirements:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">There must be a clear separation between Development, Staging and Production resources/infrastructure</li><li class=\"css-0\">It should be easy to control access to resources with different security and \"stability\"\nproperties without having to manually define lots of policies</li><li class=\"css-0\">We want to give <em>sandbox</em> accounts to individual engineers and data scientists to allow and\nencourage experimentation while limiting spend</li><li class=\"css-0\">Sensitive resources and data should be placed out of reach from easy access when not needed for\nnormal day-to-day activities</li><li class=\"css-0\">We want to follow the <em>Principle of least privilege</em>: give only the minimum set of permissions to\nallow access to exactly the resources a person or service needs to perform their job and not more.</li><li class=\"css-0\">We want as little overhead and bureaucracy as possible within the constraints of the previous\nrequirements</li></ul> <p class=\"chakra-text css-ju3ovf\">This was aside from solving the aforementioned problems we had with our single-account setup.</p> <p class=\"chakra-text css-ju3ovf\">This led me to create the following accounts, organized by Organizational Unit:</p>\n<img alt=\"AWS Organization design\" loading=\"lazy\" width=\"2000\" height=\"1304\" decoding=\"async\" data-nimg=\"1\" style=\"color:transparent\" srcSet=\"/_next/image?url=%2Fimages%2Faws-org-design.png&w=2048&q=75 1x, /_next/image?url=%2Fimages%2Faws-org-design.png&w=3840&q=75 2x\" src=\"https://www.daan.fyi/_next/image?url=%2Fimages%2Faws-org-design.png&w=3840&q=75\"/> <p class=\"chakra-text css-ju3ovf\">Some notes and highlights:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\"><strong>Workloads</strong>: this contains the \"meat\" of the infrastructure used for the day-to-day running of\nour products. Each of the workload accounts represents a different <em>environment</em>, like Production,\nStaging and Development. They all have a similar setup and contain basic infrastructure like:\n<ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">a VPC network with private and public subnets</li><li class=\"css-0\">a couple of ECS clusters for running services in (Docker) containers</li><li class=\"css-0\">some PostgreSQL databases on RDS</li><li class=\"css-0\">many lambdas for data processing, machine learning etc.</li></ul>\n</li><li class=\"css-0\"><strong>Shared</strong>: as the name implies, this OU houses accounts with infrastructure that is shared\nbetween workloads/services on other accounts. Some highlights:\n<ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\"><em>Access Management</em>: this contains IAM users for external machines and services that need to\naccess AWS infrastructure on our behalf. Given the sensitive and \"dangerous\" access some of these\nmachine users get, the Access Management account is tightly locked down. Example of an IAM user in\nthis account, is the <em>Github Actions</em> user that is used to deploy code to our workload accounts.\nThis user assumes roles within the workload accounts for deployments.</li><li class=\"css-0\"><em>Sensitive Data</em>: this account holds sensitive data that is not needed for day-to-day operations,\nbut is occasionally used for training ML models and building new features</li><li class=\"css-0\"><em>Infra</em>: contains shared infrastructure, such as our central Docker registry. Docker images\npushed to this registry are automatically replicated to our workload accounts for easy access</li></ul>\n</li><li class=\"css-0\"><strong>Sandbox</strong>: our employees occasionally need to experiment with AWS services so they get a\nsandbox account to do so, without messing up our operational workloads. Budget restrictions are\nplaced on these accounts</li></ul> <h2 class=\"chakra-heading css-r5akja\" id=\"conclusion\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#conclusion\"><span class=\"icon icon-link\"></span></a>Conclusion</h2> <p class=\"chakra-text css-ju3ovf\">Using AWS Organizations we have now set up our infrastructure at Source in such a way that it is\nmore secure and also more scalable and easier to maintain from a security perspective.\nOur Software Engineers and Data Scientists have easier access to the infrastructure, services and\nresources they need — using only <em>one</em> set of credentials — without exposing them to\nsensitive data and/or critical infrastructure.</p> <p class=\"chakra-text css-ju3ovf\">In future blog posts I will elaborate on the steps taken to set all of this up and share some\npractical guides on how to use a multi-account setup on a day-to-day basis.</p> <hr aria-orientation=\"horizontal\" class=\"chakra-divider css-1vt04vx\"/> <p class=\"chakra-text css-ju3ovf\"><em>Thanks to <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://twitter.com/djvdorp\">Dan</a> for proofreading this ❤️</em></p><span></span><span id=\"__chakra_env\" hidden=\"\"></span>",
            "url": "https://www.daan.fyi/writings/aws-multi-account",
            "title": "Setting up an Aws Multi-Account Strategy for Fun nor Profit",
            "summary": "Using multiple AWS accounts is not fun, nor is it profitable, but it can help you set up your infrastructure in a more secure way. It also helps with keeping your sanity as your company/team grows in size.",
            "date_modified": "2022-02-09T00:00:00.000Z"
        },
        {
            "id": "https://www.daan.fyi/writings/pyenv-hooks",
            "content_html": "<p class=\"chakra-text css-ju3ovf\">I use <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://github.com/pyenv/pyenv\">pyenv</a> to manage different Python versions on my laptop. It\nalso comes with an <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://github.com/pyenv/pyenv-virtualenv\">official plugin</a> that lets you manage\n<em>virtualenvs</em> through pyenv, which I find very convenient. Basically, virtualenvs are treated as\njust different Python versions by pyenv.</p> <p class=\"chakra-text css-ju3ovf\">One thing that bothered me is that, whenever I create a new virtualenv and use <code class=\"chakra-code css-lqvy6z\">pip</code> in it, I am\ninevitably greeted by a message telling me <code class=\"chakra-code css-lqvy6z\">pip</code> is out-of-date:</p>\n<pre> <code class=\"chakra-code css-lqvy6z\">WARNING: You are using pip version 21.2.3; however, version 21.3.1 is available.\nYou should consider upgrading via the '~/.pyenv/versions/3.10.0/envs/test/bin/python3.10 -m pip install --upgrade pip' command.\n</code></pre> <p class=\"chakra-text css-ju3ovf\">So I end up always having to upgrade pip after creating a new virtualenv. Wouldn’t it be nice if\nthis could be automated?</p> <p class=\"chakra-text css-ju3ovf\">Turns out, we actually <em>can</em> by leveraging <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://github.com/pyenv/pyenv/wiki/Authoring-plugins#pyenv-hooks\"><em>pyenv hooks</em></a>.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"pyenv-hooks\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#pyenv-hooks\"><span class=\"icon icon-link\"></span></a>Pyenv Hooks</h2> <p class=\"chakra-text css-ju3ovf\">pyenv hooks are scripts that are executed by pyenv whenever certain commands are run. These can be\nregular pyenv commands like <code class=\"chakra-code css-lqvy6z\">pyenv install</code> or <code class=\"chakra-code css-lqvy6z\">pyenv rehash</code> for example. But what is not\napparent from the pyenv documentation, is that you can also create hooks for plugins, like\n<code class=\"chakra-code css-lqvy6z\">pyenv virtualenv</code>.</p> <p class=\"chakra-text css-ju3ovf\">You can create a hook by creating a script at the following location:</p>\n<pre class=\"language-bash\"> <code class=\"chakra-code language-bash css-lqvy6z\"><span class=\"token variable\">$PYENV_ROOT</span>/pyenv.d/<span class=\"token operator\"><</span>hook-name<span class=\"token operator\">></span>/<span class=\"token operator\"><</span>whatever<span class=\"token operator\">></span>.bash\n</code></pre> <p class=\"chakra-text css-ju3ovf\"> <code class=\"chakra-code css-lqvy6z\">hook-name</code> here can be any of: <code class=\"chakra-code css-lqvy6z\">exec</code>, <code class=\"chakra-code css-lqvy6z\">rehash</code>, <code class=\"chakra-code css-lqvy6z\">which</code>, <code class=\"chakra-code css-lqvy6z\">install</code> — which are all regular pyenv\ncommands — but it can also be a plugin command, like <code class=\"chakra-code css-lqvy6z\">virtualenv</code>. The filename of the script doesn’t\nmatter, and neither does the extension. I use <code class=\"chakra-code css-lqvy6z\">.bash</code> here to make it explicit that this is a bash\nscript, but pyenv hooks can be written in any language.</p> <p class=\"chakra-text css-ju3ovf\">To create a hook that upgrades <code class=\"chakra-code css-lqvy6z\">pip</code> and some other default packages, you can create a new script\nas follows:</p>\n<pre class=\"language-bash\"> <code class=\"chakra-code language-bash css-lqvy6z\"><span class=\"token function\">mkdir</span> -p <span class=\"token variable\">$PYENV_ROOT</span>/pyenv.d/virtualenv/\n<span class=\"token variable\">$EDITOR</span> <span class=\"token variable\">$PYENV_ROOT</span>/pyenv.d/virtualenv/after.bash\n</code></pre> <p class=\"chakra-text css-ju3ovf\">Where <code class=\"chakra-code css-lqvy6z\">$EDITOR</code> is your favorite editor (like <code class=\"chakra-code css-lqvy6z\">vim</code>, <strong>RIGHT?!</strong>)</p> <p class=\"chakra-text css-ju3ovf\">Then add the following contents:</p>\n<pre class=\"language-bash\"> <code class=\"chakra-code language-bash css-lqvy6z\">after_virtualenv <span class=\"token string\">'PYENV_VERSION=\"<span class=\"token variable\">$VIRTUALENV_NAME</span>\" pyenv-exec pip install --upgrade pip setuptools wheel'</span>\n</code></pre> <p class=\"chakra-text css-ju3ovf\"> <code class=\"chakra-code css-lqvy6z\">after_virtualenv</code> is the command that tells pyenv <em>when</em> to execute the following command. In this\ncase its defined by the <code class=\"chakra-code css-lqvy6z\">pyenv virtualenv</code> plugin. First we set the pyenv version to the name\nof the virtualenv we just created. This is set by pyenv virtualenv as <code class=\"chakra-code css-lqvy6z\">$VIRTUALENV_NAME</code>. Then we\ninstall/upgrade <code class=\"chakra-code css-lqvy6z\">pip</code> itself and <code class=\"chakra-code css-lqvy6z\">setuptools</code> and <code class=\"chakra-code css-lqvy6z\">wheel</code>.</p> <p class=\"chakra-text css-ju3ovf\">That is all there is to it! Now any time you create a new virtualenv using <code class=\"chakra-code css-lqvy6z\">pyenv virtualenv</code>, the\naforementioned packages will be automatically upgraded after the virtualenv was created.</p><span></span><span id=\"__chakra_env\" hidden=\"\"></span>",
            "url": "https://www.daan.fyi/writings/pyenv-hooks",
            "title": "Customzing Pyenv Behavior with Hooks",
            "summary": "You can customize the behavior of pyenv or its plugins - like pyenv virtualenv - by using hooks. These are simple (bash) scripts that are run at specific points when pyenv commands are run.",
            "date_modified": "2021-11-28T00:00:00.000Z"
        },
        {
            "id": "https://www.daan.fyi/writings/python-protocols",
            "content_html": "<p class=\"chakra-text css-ju3ovf\">At <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://source.ag/\">Source</a>, we write most of our code in Python. It’s a language that both our\nSoftware Engineers and Data Scientists are equally at home in. It’s easy to be productive in Python,\nin part due to its dynamic nature. Not having to think too much about the types of your variables\nand functions, can make it easier to experiment, especially if you’re not entirely clear yet\non how you’re going to solve a particular problem.</p> <p class=\"chakra-text css-ju3ovf\">When moving our code to production however, we want to have more guarantees about the behaviour of\nour code. Writing (unit) tests is one way to get those guarantees, but we also make heavy use of <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.python.org/dev/peps/pep-0484/\">type hints</a> to give us more confidence in our code.\nType hints can also provide a productivity boost, because not only humans can reason better about\ntype hinted code, your editor can as well!</p> <p class=\"chakra-text css-ju3ovf\">Sometimes though, using type hints everywhere can feel like you’re losing out on a lot of the magic\nand speed that a dynamic type system brings you. One particular trait of dynamic typing that is\npretty idiomatic in Python, is <strong>duck typing</strong>.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"duck-typing\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#duck-typing\"><span class=\"icon icon-link\"></span></a>Duck Typing</h2> <p class=\"chakra-text css-ju3ovf\"> <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://en.wikipedia.org/wiki/Duck_typing\">Duck typing</a> is a philosophy in programming where you\ncare more about the behaviour and properties of an object than its stated type to determine if that\nobject is useful in a certain situation. Duck typing is inspired by the <em>duck test</em>:</p> <blockquote class=\"css-p56y4k\"> <p class=\"chakra-text css-ju3ovf\">If it walks like a duck and it quacks like a duck, then it must be a duck</p>\n</blockquote> <p class=\"chakra-text css-ju3ovf\">In practice this means that when you write a function that receives a certain input, you care only\nabout the behaviour and/or attributes of that input, not the explicit <em>type</em> of that input.</p> <p class=\"chakra-text css-ju3ovf\">One interesting question that arises is: if you don’t want to be strict about the type of the\nparameters a function receives, are there still any <em>static type guarantees</em> to be had?</p> <p class=\"chakra-text css-ju3ovf\">And the other way around is interesting as well: if you have a function with statically typed\ninputs, can you <em>loosen up</em> those parameters to make the function more universally useful, the way\nduck typing does?</p> <p class=\"chakra-text css-ju3ovf\">As it turns out, Python provides a neat way to have our cake and eat it too!</p> <h2 class=\"chakra-heading css-r5akja\" id=\"protocols-to-the-rescue\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#protocols-to-the-rescue\"><span class=\"icon icon-link\"></span></a>Protocols to the Rescue</h2> <p class=\"chakra-text css-ju3ovf\">When reviewing some code recently, I came across a function that looked roughly like this:</p>\n<pre class=\"language-python\"> <code class=\"chakra-code language-python css-lqvy6z\"><span class=\"token keyword\">def</span> <span class=\"token function\">calculate_windowed_avg</span><span class=\"token punctuation\">(</span>\nmeasurements<span class=\"token punctuation\">:</span> Union<span class=\"token punctuation\">[</span>List<span class=\"token punctuation\">[</span>TemperatureMeasurement<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> List<span class=\"token punctuation\">[</span>HumidityMeasurement<span class=\"token punctuation\">]</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\nwindow_size<span class=\"token punctuation\">:</span> timedelta<span class=\"token punctuation\">,</span>\nfield_name<span class=\"token punctuation\">:</span> <span class=\"token builtin\">str</span>\n<span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span><span class=\"token operator\">></span> Dict<span class=\"token punctuation\">[</span>datetime<span class=\"token punctuation\">,</span> <span class=\"token builtin\">float</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span>\nwindow_upper_bound <span class=\"token operator\">=</span> measurements<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>timestamp <span class=\"token operator\">+</span> window_size\ncurrent_window <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\nwindow_averages <span class=\"token operator\">=</span> OrderedDict<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">for</span> m <span class=\"token keyword\">in</span> measurements<span class=\"token punctuation\">:</span>\n<span class=\"token comment\"># various calculations happen here</span>\n<span class=\"token comment\"># based on the timestamp of each measurement</span>\n<span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span>\n<span class=\"token keyword\">return</span> window_averages\n</code></pre> <p class=\"chakra-text css-ju3ovf\">The goal of this function is to calculate the average of a certain field (identified by <code class=\"chakra-code css-lqvy6z\">field_name</code>) in a rolling window. At the time of writing this function, we were using it for\n<code class=\"chakra-code css-lqvy6z\">TemperatureMeasurement</code> and <code class=\"chakra-code css-lqvy6z\">HumidityMeasurement</code>, but it is very likely we’ll want to use it for\ndifferent types of measurements in the future.</p> <p class=\"chakra-text css-ju3ovf\">If we look closely at how the function uses the input, it turns out that the only thing we want to\nbe guaranteed of, is that the items we pass into the function have a <code class=\"chakra-code css-lqvy6z\">timestamp</code> field. So instead\nof specifying each different type that has adheres to this contract, we’d like to tell the type\nchecker that we only care about having a <code class=\"chakra-code css-lqvy6z\">timestamp</code> field to work with.</p> <p class=\"chakra-text css-ju3ovf\"> <code class=\"chakra-code css-lqvy6z\">Protocol</code> from the <code class=\"chakra-code css-lqvy6z\">typing</code> module lets us do that. Just like with duck typing, <strong>Protocols</strong> let\nyou specify the behaviour or attributes you expect, without caring about the type. Here is what\nthat looks like:</p>\n<pre class=\"language-python\"> <code class=\"chakra-code language-python{4,5,8} css-lqvy6z\"><span class=\"token keyword\">from</span> typing <span class=\"token keyword\">import</span> Protocol<span class=\"token punctuation\">,</span> List<span class=\"token punctuation\">,</span> Dict\n<span class=\"token keyword\">from</span> datetime <span class=\"token keyword\">import</span> datetime\n\n<div class=\"mdx-marker\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">MeasurementLike</span><span class=\"token punctuation\">(</span>Protocol<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n</div><div class=\"mdx-marker\">    timestamp<span class=\"token punctuation\">:</span> datetime\n</div>\n<span class=\"token keyword\">def</span> <span class=\"token function\">calculate_windowed_avg</span><span class=\"token punctuation\">(</span>\n<div class=\"mdx-marker\">        measurements<span class=\"token punctuation\">:</span> List<span class=\"token punctuation\">[</span>MeasurementLike<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n</div>        window_size<span class=\"token punctuation\">:</span> timedelta<span class=\"token punctuation\">,</span>\nfield_name<span class=\"token punctuation\">:</span> <span class=\"token builtin\">str</span>\n<span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span><span class=\"token operator\">></span> Dict<span class=\"token punctuation\">[</span>datetime<span class=\"token punctuation\">,</span> <span class=\"token builtin\">float</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span>\nwindow_upper_bound <span class=\"token operator\">=</span> measurements<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>timestamp <span class=\"token operator\">+</span> window_size\n<span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span>\n</code></pre> <p class=\"chakra-text css-ju3ovf\">Now the type checker doesn’t know <em>exactly</em> what the type is of whatever is provided as <code class=\"chakra-code css-lqvy6z\">measurements</code> but it <em>does</em> know what those items have a <code class=\"chakra-code css-lqvy6z\">timestamp</code> field because they adhere to\nthe <code class=\"chakra-code css-lqvy6z\">MeasurementLike</code> Protocol.</p> <p class=\"chakra-text css-ju3ovf\">In a sense, a Protocol acts like one side of an <em>Interface</em> as we know it from Java or Typescript.\nInstead of having to specify the behaviour and properties both on a <em>type</em> and on the functions\nthat use it, we only have to specify it on a function, without caring about the types of the objects\nthat are provided to the function.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"protocol-and-generics\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#protocol-and-generics\"><span class=\"icon icon-link\"></span></a>Protocol and Generics</h2> <p class=\"chakra-text css-ju3ovf\">You can also use Protocols together with <code class=\"chakra-code css-lqvy6z\">TypeVar</code> for even more generic functions that are still\ntype checked to some extend. One use-case that comes to mind, is when you don’t care about the\ninput type to a function, as long as it follows a protocol, but you also want to guarantee that\nthe <em>output</em> of the function is of the same type as the <em>input</em>, no matter what the exact type is.</p> <p class=\"chakra-text css-ju3ovf\">This works as follows:</p>\n<pre class=\"language-python\"> <code class=\"chakra-code language-python css-lqvy6z\"><span class=\"token keyword\">from</span> typing <span class=\"token keyword\">import</span> Protocol<span class=\"token punctuation\">,</span> TypeVar\n<span class=\"token keyword\">from</span> datetime <span class=\"token keyword\">import</span> datetime\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">MeasurementLike</span><span class=\"token punctuation\">(</span>Protocol<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\ntimestamp<span class=\"token punctuation\">:</span> datetime\n\nM <span class=\"token operator\">=</span> TypeVar<span class=\"token punctuation\">(</span><span class=\"token string\">'M'</span><span class=\"token punctuation\">,</span> bound<span class=\"token operator\">=</span>MeasurementLike<span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">measurement_as_timezone</span><span class=\"token punctuation\">(</span>measurement<span class=\"token punctuation\">:</span> M<span class=\"token punctuation\">,</span> tz<span class=\"token punctuation\">:</span> tzinfo<span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span><span class=\"token operator\">></span> M<span class=\"token punctuation\">:</span>\nmeasurement<span class=\"token punctuation\">.</span>timestamp <span class=\"token operator\">=</span> measurement<span class=\"token punctuation\">.</span>timestamp<span class=\"token punctuation\">.</span>astimezone<span class=\"token punctuation\">(</span>tz<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">return</span> measurement\n</code></pre> <p class=\"chakra-text css-ju3ovf\">Here we create a function that takes any object that has a <code class=\"chakra-code css-lqvy6z\">timestamp</code> field and guarantees that\nthe output will be of the same type as the input.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"conclusion\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#conclusion\"><span class=\"icon icon-link\"></span></a>Conclusion</h2> <p class=\"chakra-text css-ju3ovf\">Protocols in Python provide a nice way to use duck typing while still having some static type\nguarantees. You can define contracts for your functions without caring too much about the actual\ntypes of your inputs.</p> <hr aria-orientation=\"horizontal\" class=\"chakra-divider css-1vt04vx\"/> <p class=\"chakra-text css-ju3ovf\"><em>Update on 2021–11–23: There was a wrong type annotation in this article, as <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://news.ycombinator.com/item?id=29315363\">pointed out by\n<strong>ragebol</strong> on Hacker News</a>, which is now fixed</em></p><span></span><span id=\"__chakra_env\" hidden=\"\"></span>",
            "url": "https://www.daan.fyi/writings/python-protocols",
            "title": "Static Duck Typing in Python with Protocols",
            "summary": "Duck typing is considered to be one of Python's strengths. If you want to have the benefits of duck typing but also want your types statically checked, Protocols offer an excellent solution.",
            "date_modified": "2021-11-19T00:00:00.000Z"
        },
        {
            "id": "https://www.daan.fyi/writings/rss",
            "content_html": "<p class=\"chakra-text css-ju3ovf\">Today, I released a new version of my website with only one new feature: <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://en.wikipedia.org/wiki/Web_syndication\">syndication</a> through RSS, Atom and JSON Feed. Even\nthough <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://techcrunch.com/2018/04/07/rss-is-undead/\">by some accounts</a>, RSS\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://mjtsai.com/blog/2019/12/26/apple-news-no-longer-supports-rss/\">seems to be dead</a>,\nI strongly believe RSS is an important feature in the fight to keep ownership over your own content\nwhile also increasing exposure. The way I approach publishing and sharing my content, is called\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://indieweb.org/POSSE\">POSSE</a>:</p> <blockquote class=\"css-p56y4k\"> <p class=\"chakra-text css-ju3ovf\"><strong>Publish (on your) Own Site, Syndicate Elsewhere</strong>.</p>\n</blockquote> <p class=\"chakra-text css-ju3ovf\">RSS is an important part of that strategy.</p> <p class=\"chakra-text css-ju3ovf\">Luckily, I’m not the only one who values RSS. <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://news.ycombinator.com/item?id=20813021\">There</a>\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://news.ycombinator.com/item?id=23212812\">are</a> <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://news.ycombinator.com/item?id=26014344\">others</a></p> <p class=\"chakra-text css-ju3ovf\">In this article I want to share how I implemented syndication feeds in my <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://nextjs.org/\">NextJS-powered</a> website.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"options-and-requirements\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#options-and-requirements\"><span class=\"icon icon-link\"></span></a>Options and Requirements</h2> <p class=\"chakra-text css-ju3ovf\">I did some Googling to see how other NextJS users were generating RSS feeds, and there turned out\nto be many people that had solved this particular problem <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.google.com/search?q=rss+feed+nextjs\">and wrote about it</a>\nI found a couple of different approaches to generating and rendering RSS feeds in NextJS:</p> <p class=\"chakra-text css-ju3ovf\"><strong>Generating feeds</strong>:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">Hand-build the required XML using templated strings 🤢</li><li class=\"css-0\">Use a library to do it for you. The most popular library for this in the JS ecosystem seems to be <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.npmjs.com/package/feed\"><em>feed</em></a> 🤩</li></ul> <p class=\"chakra-text css-ju3ovf\"><strong>Rendering feeds</strong>:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">Use <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering\">Server-side rendering</a>\n<ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">Advantages:\n<ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">Create dynamic feeds (more on that later) that can be different for each visitor</li><li class=\"css-0\">Using NextJS pages to represent feeds feels natural in the NextJS way of doing things</li></ul>\n</li><li class=\"css-0\">Disadvantages:\n<ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">You can’t generate the website statically anymore (at least parts of it remain dynamic),\nwhich reduces performance\nAs a side note: from a development perspective, server-side rendered pages and statically generated\npages in NextJS are so similar that the difference doesn’t matter</li></ul>\n</li></ul>\n</li><li class=\"css-0\">Use <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation\">Static generation</a>\n<ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">Advantages:\n<ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">Because the feeds are generated at build time, the site remains snappy</li></ul>\n</li><li class=\"css-0\">Disadvantages\n<ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">You cannot set the <code class=\"chakra-code css-lqvy6z\">Content-Type</code> header for statically generated pages, so you can’t serve\nthose pages as <code class=\"chakra-code css-lqvy6z\">application/rss+xml</code>. I’m not how big of a problem this is and what black\nmagic <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://vercel.com/\">Vercel</a> applies when serving my NextJS site</li></ul>\n</li></ul>\n</li></ul> <h3 class=\"chakra-heading css-10qrs2m\" id=\"picking-the-requirements\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#picking-the-requirements\"><span class=\"icon icon-link\"></span></a>Picking the Requirements</h3> <p class=\"chakra-text css-ju3ovf\">After looking at the options, I decided on the following requirements for my feeds:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">I want to go for statically generated feeds, to keep my site fast and the implementation simple</li><li class=\"css-0\">Support for <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://en.wikipedia.org/wiki/RSS\">RSS</a>,\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://en.wikipedia.org/wiki/Atom_(Web_standard)\">Atom</a> and <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.jsonfeed.org/\">JSON Feed</a></li><li class=\"css-0\">I want to include the <strong>complete blog post contents</strong> in the feeds. This is an important one\nbecause I personally really hate it when my RSS reader only shows me a summary of a post and\nI have to go the the website to read all of it.\nCaveat though: my website is built using MDX, so I might include components in the future\nthat are not easily convertible to static HTML without Javascript enabled. In that case,\nreaders will have to click through to my site.</li></ul> <h2 class=\"chakra-heading css-r5akja\" id=\"implementation\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#implementation\"><span class=\"icon icon-link\"></span></a>Implementation</h2> <p class=\"chakra-text css-ju3ovf\">As per my requirements, I wanted to generate the feeds at build time. But as mentioned before,\nNextJS doesn’t support setting the <code class=\"chakra-code css-lqvy6z\">Content-Type</code> header for statically generated pages.\nThe alternative that many people use, is to have a separate script generate your feeds and\nwriting them to the public folder where all other static assets such as images are stored as well.\nThat way, the feeds would be served as static assets instead of statically generated pages — which,\nfrom the browsers perspective doesn’t make a difference!</p> <p class=\"chakra-text css-ju3ovf\">I found a <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://ashleemboyer.com/how-i-added-an-rss-feed-to-my-nextjs-site\">good explanation by Ashlee Boyer</a>\nof this technique.</p> <p class=\"chakra-text css-ju3ovf\">My plan:</p> <ol role=\"list\" class=\"css-bux2of\"><li class=\"css-0\">Write script to generate feeds, using the <em>feed</em> library from NPM</li><li class=\"css-0\">Run this script as a <code class=\"chakra-code css-lqvy6z\">postbuild</code> step so it would always be invoked after building the site\nusing <code class=\"chakra-code css-lqvy6z\">npm run build</code> (this happens not only locally, but also when Vercel deploys my site)</li></ol> <h3 class=\"chakra-heading css-10qrs2m\" id=\"problem-1-running-typescript-modules-is-hard\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#problem-1-running-typescript-modules-is-hard\"><span class=\"icon icon-link\"></span></a>Problem 1: Running Typescript Modules Is Hard</h3> <p class=\"chakra-text css-ju3ovf\">I immediately hit a snag with (1), because I couldn’t manage to use ES6/Typescript modules in a\nscript run outside of my normal website code.</p> <p class=\"chakra-text css-ju3ovf\">I’m using Typescript, and apparently <code class=\"chakra-code css-lqvy6z\">ts-node</code>, the tool to run Typescript files, doesn’t support\nmodules. Writing the script in Javascript wasn’t really an option for me because I wanted to reuse\na lot of logic that I already wrote for reading and parsing MDX files in the website itself.</p> <h4 class=\"chakra-heading css-1k9a9w9\" id=\"solution\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#solution\"><span class=\"icon icon-link\"></span></a>Solution</h4> <p class=\"chakra-text css-ju3ovf\">I decided to follow the route that Ashlee Boyer suggests in her blog post and sneak in the\nfunction to generate my feeds as a \"stowaway\" in the <code class=\"chakra-code css-lqvy6z\">getStaticProps</code> function of my index\npage. This works beautifully!</p>\n<div class=\"rehype-code-title\">pages/index.tsx</div><pre class=\"language-typescript\"> <code class=\"chakra-code language-typescript css-lqvy6z\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> getStaticProps<span class=\"token operator\">:</span> <span class=\"token function-variable function\"><span class=\"token maybe-class-name\">GetStaticProps</span></span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token arrow operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"token function\">generateMainFeeds</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> lastPosts <span class=\"token operator\">=</span> <span class=\"token function\">getAllPostsFrontMatter</span><span class=\"token punctuation\">(</span><span class=\"token string\">'blog'</span><span class=\"token punctuation\">,</span> <span class=\"token number\">3</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\nprops<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\nlastPosts<span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n</code></pre> <h3 class=\"chakra-heading css-10qrs2m\" id=\"problem-2-including-the-full-content-in-the-feeds\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#problem-2-including-the-full-content-in-the-feeds\"><span class=\"icon icon-link\"></span></a>Problem 2: Including the Full Content in the Feeds</h3> <p class=\"chakra-text css-ju3ovf\">The code of my website already supported translating MDX files into valid JSX to be rendered\nby React. But how to generate valid HTML from that content and include it in the feeds?</p> <h4 class=\"chakra-heading css-1k9a9w9\" id=\"solution-1\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#solution-1\"><span class=\"icon icon-link\"></span></a>Solution</h4> <p class=\"chakra-text css-ju3ovf\">I couldn’t find many examples of this, but did find out about <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://reactjs.org/docs/react-dom-server.html#rendertostaticmarkup\"> <code class=\"chakra-code css-lqvy6z\">ReactDOMServer.renderToStaticMarkup</code></a>.\nThis function will take a bunch of React components and render them into HTML. This is what is\nused by many React server-side rendering solutions <em>(maybe also by NextJS?)</em> and works perfectly\nhere as well.</p> <p class=\"chakra-text css-ju3ovf\">One caveat: if your content contains internal links — which are often relative links — then you\nhave to be mindful that those relative links are meaningless in the context of an RSS feed.\nThe way I solved this is by doing some regex-based replacements on the generated HTML.</p> <p class=\"chakra-text css-ju3ovf\">The complete content generation part looks like this:</p>\n<div class=\"rehype-code-title\">lib/feeds.tsx</div><pre class=\"language-typescript\"> <code class=\"chakra-code language-typescript css-lqvy6z\"><span class=\"token keyword\">const</span> url <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>baseUrl<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">/blog/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>post<span class=\"token punctuation\">.</span><span class=\"token property-access\">frontMatter</span><span class=\"token punctuation\">.</span><span class=\"token property-access\">slug</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> htmlContent <span class=\"token operator\">=</span> <span class=\"token maybe-class-name\">ReactDOMServer</span><span class=\"token punctuation\">.</span><span class=\"token method function property-access\">renderToStaticMarkup</span><span class=\"token punctuation\">(</span>\n<span class=\"token operator\"><</span><span class=\"token maybe-class-name\">ChakraProvider</span> resetCSS theme<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>theme<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n<span class=\"token operator\"><</span><span class=\"token maybe-class-name\">MDXRemote</span> <span class=\"token punctuation\">{</span><span class=\"token spread operator\">...</span>post<span class=\"token punctuation\">.</span><span class=\"token property-access\">mdxSource</span><span class=\"token punctuation\">}</span> components<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token maybe-class-name\">MDXComponents</span><span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n<span class=\"token operator\"><</span><span class=\"token operator\">/</span><span class=\"token maybe-class-name\">ChakraProvider</span><span class=\"token operator\">></span>\n<span class=\"token punctuation\">.</span><span class=\"token method function property-access\">replace</span><span class=\"token punctuation\">(</span><span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">href=\"\\/#</span><span class=\"token regex-delimiter\">/</span><span class=\"token regex-flags\">g</span></span><span class=\"token punctuation\">,</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">href=\"</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>url<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">#</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">.</span><span class=\"token method function property-access\">replace</span><span class=\"token punctuation\">(</span><span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">href=\"\\/</span><span class=\"token regex-delimiter\">/</span><span class=\"token regex-flags\">g</span></span><span class=\"token punctuation\">,</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">href=\"</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>baseUrl<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">/</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">.</span><span class=\"token method function property-access\">replace</span><span class=\"token punctuation\">(</span><span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">src=\"\\/</span><span class=\"token regex-delimiter\">/</span><span class=\"token regex-flags\">g</span></span><span class=\"token punctuation\">,</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">src=\"</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>baseUrl<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">/</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">)</span>\n</code></pre> <h3 class=\"chakra-heading css-10qrs2m\" id=\"problem-3-getting-rid-of-style-information\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#problem-3-getting-rid-of-style-information\"><span class=\"icon icon-link\"></span></a>Problem 3: Getting Rid of Style Information</h3> <p class=\"chakra-text css-ju3ovf\">My site uses <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://chakra-ui.com/\">Chakra UI</a> for theming, which uses\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://emotion.sh/\">Emotion</a> — a CSS-in-JS library — under the hood. Emotion will happily\nrender tons of <code class=\"chakra-code css-lqvy6z\"> </code> tags when statically generating HTML from your React components. For most\nuse cases where you render React on the server (statically or not), this is desirable. In the case\nof RSS/Atom feeds, this is pretty useless.</p> <h4 class=\"chakra-heading css-1k9a9w9\" id=\"solution-2\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#solution-2\"><span class=\"icon icon-link\"></span></a>Solution</h4> <p class=\"chakra-text css-ju3ovf\">The solution here is to strip all the <code class=\"chakra-code css-lqvy6z\"> </code> and <code class=\"chakra-code css-lqvy6z\"><style></code> tags from the generated HTML.\nRather than summoning\n<style data-emotion=\"css 3u9hqk\">.css-3u9hqk{transition-property:var(--chakra-transition-property-common);transition-duration:var(--chakra-transition-duration-fast);transition-timing-function:var(--chakra-transition-easing-ease-out);cursor:pointer;outline:2px solid transparent;outline-offset:2px;color:inherit;background-image:linear-gradient(to bottom, var(--chakra-colors-teal-300) 0%, var(--chakra-colors-teal-300) 100%);-webkit-background-position:0 100%;background-position:0 100%;-webkit-text-decoration:none;text-decoration:none;background-repeat:repeat-x;-webkit-background-size:2px 2px;background-size:2px 2px;-webkit-transition:background-size .2s;transition:background-size .2s;}.css-3u9hqk:focus-visible,.css-3u9hqk[data-focus-visible]{box-shadow:var(--chakra-shadows-outline);}.css-3u9hqk:hover,.css-3u9hqk[data-hover]{-webkit-text-decoration:none;text-decoration:none;-webkit-background-size:4px 50px;background-size:4px 50px;}</style><a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://stackoverflow.com/a/1732454/872397\"><em>The One whose Name cannot be expressed in the Basic Multilingual Plane</em></a>\nby trying to use regex here, I found <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.npmjs.com/package/string-strip-html\">this library</a>\nto help me with this task:</p>\n<div class=\"rehype-code-title\">lib/feeds.tsx</div><pre class=\"language-typescript\"><style data-emotion=\"css lqvy6z\">.css-lqvy6z{display:inline-block;font-family:var(--chakra-fonts-mono);font-size:var(--chakra-fontSizes-sm);-webkit-padding-start:0.2em;padding-inline-start:0.2em;-webkit-padding-end:0.2em;padding-inline-end:0.2em;border-radius:var(--chakra-radii-sm);background:var(--badge-bg);color:var(--badge-color);box-shadow:var(--badge-shadow);--badge-bg:var(--chakra-colors-gray-100);--badge-color:var(--chakra-colors-gray-800);}.chakra-ui-dark .css-lqvy6z:not([data-theme]),[data-theme=dark] .css-lqvy6z:not([data-theme]),.css-lqvy6z[data-theme=dark]{--badge-bg:rgba(226, 232, 240, 0.16);--badge-color:var(--chakra-colors-gray-200);}</style><code class=\"chakra-code language-typescript css-lqvy6z\"><span class=\"token keyword\">const</span> cleanHtmlContent <span class=\"token operator\">=</span> <span class=\"token function\">stripHtml</span><span class=\"token punctuation\">(</span>htmlContent<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n    onlyStripTags<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'script'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'style'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    stripTogetherWithTheirContents<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'script'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'style'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token property-access\">result</span><span class=\"token punctuation\">;</span>\n</code></pre>\n<style data-emotion=\"css r5akja\">.css-r5akja{font-family:var(--chakra-fonts-heading);font-weight:var(--chakra-fontWeights-bold);margin-top:var(--chakra-space-2);margin-bottom:var(--chakra-space-4);font-size:var(--chakra-fontSizes-2xl);line-height:1.33;}@media screen and (min-width: 48em){.css-r5akja{font-size:var(--chakra-fontSizes-3xl);line-height:1.2;}}.css-r5akja{scroll-margin-top:5.5rem;}.css-r5akja:hover>a{visibility:visible;}.css-r5akja a{position:absolute;margin-left:-1em;padding-right:0.5em;cursor:pointer;visibility:hidden;width:80%;max-width:800px;color:var(--chakra-colors-gray-700);}.css-r5akja a:hover{visibility:visible;-webkit-text-decoration:none;text-decoration:none;}.css-r5akja a span:after{content:\"#\";}</style><h2 class=\"chakra-heading css-r5akja\" id=\"the-end-result\"><style data-emotion=\"css auue23\">.css-auue23{transition-property:var(--chakra-transition-property-common);transition-duration:var(--chakra-transition-duration-fast);transition-timing-function:var(--chakra-transition-easing-ease-out);cursor:pointer;outline:2px solid transparent;outline-offset:2px;color:inherit;-webkit-text-decoration:none;text-decoration:none;}.css-auue23:focus-visible,.css-auue23[data-focus-visible]{box-shadow:var(--chakra-shadows-outline);}.css-auue23:hover,.css-auue23[data-hover]{-webkit-text-decoration:none;text-decoration:none;}</style><a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#the-end-result\"><span class=\"icon icon-link\"></span></a>The End Result</h2>\n<style data-emotion=\"css ju3ovf\">.css-ju3ovf{margin-bottom:var(--chakra-space-2);margin-top:var(--chakra-space-2);}</style><p class=\"chakra-text css-ju3ovf\">I now have serve <style data-emotion=\"css 3u9hqk\">.css-3u9hqk{transition-property:var(--chakra-transition-property-common);transition-duration:var(--chakra-transition-duration-fast);transition-timing-function:var(--chakra-transition-easing-ease-out);cursor:pointer;outline:2px solid transparent;outline-offset:2px;color:inherit;background-image:linear-gradient(to bottom, var(--chakra-colors-teal-300) 0%, var(--chakra-colors-teal-300) 100%);-webkit-background-position:0 100%;background-position:0 100%;-webkit-text-decoration:none;text-decoration:none;background-repeat:repeat-x;-webkit-background-size:2px 2px;background-size:2px 2px;-webkit-transition:background-size .2s;transition:background-size .2s;}.css-3u9hqk:focus-visible,.css-3u9hqk[data-focus-visible]{box-shadow:var(--chakra-shadows-outline);}.css-3u9hqk:hover,.css-3u9hqk[data-hover]{-webkit-text-decoration:none;text-decoration:none;-webkit-background-size:4px 50px;background-size:4px 50px;}</style><a class=\"chakra-link css-3u9hqk\" href=\"https://www.daan.fyi/feeds/feed.xml\">RSS</a>, <a class=\"chakra-link css-3u9hqk\" href=\"https://www.daan.fyi/feeds/atom.xml\">Atom</a> and a <a class=\"chakra-link css-3u9hqk\" href=\"https://www.daan.fyi/feeds/feed.json\">JSON Feed</a>\nfor your reading pleasure. Most of the relevant code <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://github.com/DandyDev/daan.fyi/blob/main/lib/feeds.tsx\">can be found here</a></p>\n<style data-emotion=\"css r5akja\">.css-r5akja{font-family:var(--chakra-fonts-heading);font-weight:var(--chakra-fontWeights-bold);margin-top:var(--chakra-space-2);margin-bottom:var(--chakra-space-4);font-size:var(--chakra-fontSizes-2xl);line-height:1.33;}@media screen and (min-width: 48em){.css-r5akja{font-size:var(--chakra-fontSizes-3xl);line-height:1.2;}}.css-r5akja{scroll-margin-top:5.5rem;}.css-r5akja:hover>a{visibility:visible;}.css-r5akja a{position:absolute;margin-left:-1em;padding-right:0.5em;cursor:pointer;visibility:hidden;width:80%;max-width:800px;color:var(--chakra-colors-gray-700);}.css-r5akja a:hover{visibility:visible;-webkit-text-decoration:none;text-decoration:none;}.css-r5akja a span:after{content:\"#\";}</style><h2 class=\"chakra-heading css-r5akja\" id=\"future-plans\"><style data-emotion=\"css auue23\">.css-auue23{transition-property:var(--chakra-transition-property-common);transition-duration:var(--chakra-transition-duration-fast);transition-timing-function:var(--chakra-transition-easing-ease-out);cursor:pointer;outline:2px solid transparent;outline-offset:2px;color:inherit;-webkit-text-decoration:none;text-decoration:none;}.css-auue23:focus-visible,.css-auue23[data-focus-visible]{box-shadow:var(--chakra-shadows-outline);}.css-auue23:hover,.css-auue23[data-hover]{-webkit-text-decoration:none;text-decoration:none;}</style><a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#future-plans\"><span class=\"icon icon-link\"></span></a>Future Plans</h2>\n<style data-emotion=\"css ju3ovf\">.css-ju3ovf{margin-bottom:var(--chakra-space-2);margin-top:var(--chakra-space-2);}</style><p class=\"chakra-text css-ju3ovf\">At some point I want to diversify my writing output by not only writing about tech. And\neven within the topic of tech there are many sub-topics I could write about, not all of which\nare equally interesting to every reader (all 5 of them, including my mom 👩‍👦).\nI’m planning to introduce <style data-emotion=\"css 3u9hqk\">.css-3u9hqk{transition-property:var(--chakra-transition-property-common);transition-duration:var(--chakra-transition-duration-fast);transition-timing-function:var(--chakra-transition-easing-ease-out);cursor:pointer;outline:2px solid transparent;outline-offset:2px;color:inherit;background-image:linear-gradient(to bottom, var(--chakra-colors-teal-300) 0%, var(--chakra-colors-teal-300) 100%);-webkit-background-position:0 100%;background-position:0 100%;-webkit-text-decoration:none;text-decoration:none;background-repeat:repeat-x;-webkit-background-size:2px 2px;background-size:2px 2px;-webkit-transition:background-size .2s;transition:background-size .2s;}.css-3u9hqk:focus-visible,.css-3u9hqk[data-focus-visible]{box-shadow:var(--chakra-shadows-outline);}.css-3u9hqk:hover,.css-3u9hqk[data-hover]{-webkit-text-decoration:none;text-decoration:none;-webkit-background-size:4px 50px;background-size:4px 50px;}</style><a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://github.com/DandyDev/daan.fyi/issues/3\">tags</a> to allow\nfiltering content once I have enough of it.</p>\n<style data-emotion=\"css ju3ovf\">.css-ju3ovf{margin-bottom:var(--chakra-space-2);margin-top:var(--chakra-space-2);}</style><p class=\"chakra-text css-ju3ovf\">Once I have tags, I would like to start supporting dynamic feeds so readers can subscribe only\nto the stuff they actually want to read. I imagine building an endpoint like this:</p>\n<pre><style data-emotion=\"css lqvy6z\">.css-lqvy6z{display:inline-block;font-family:var(--chakra-fonts-mono);font-size:var(--chakra-fontSizes-sm);-webkit-padding-start:0.2em;padding-inline-start:0.2em;-webkit-padding-end:0.2em;padding-inline-end:0.2em;border-radius:var(--chakra-radii-sm);background:var(--badge-bg);color:var(--badge-color);box-shadow:var(--badge-shadow);--badge-bg:var(--chakra-colors-gray-100);--badge-color:var(--chakra-colors-gray-800);}.chakra-ui-dark .css-lqvy6z:not([data-theme]),[data-theme=dark] .css-lqvy6z:not([data-theme]),.css-lqvy6z[data-theme=dark]{--badge-bg:rgba(226, 232, 240, 0.16);--badge-color:var(--chakra-colors-gray-200);}</style><code class=\"chakra-code css-lqvy6z\">/feeds/by-tags.xml?tags=tag1,tag2\n</code></pre>\n<style data-emotion=\"css ju3ovf\">.css-ju3ovf{margin-bottom:var(--chakra-space-2);margin-top:var(--chakra-space-2);}</style><p class=\"chakra-text css-ju3ovf\">I’m curious if others are doing this!</p><span></span><span id=\"__chakra_env\" hidden=\"\"></span>",
            "url": "https://www.daan.fyi/writings/rss",
            "title": "How to Add an Rss Feed to a Nextjs Blog",
            "summary": "RSS is an important feature to give your content maximum exposure while also retaining control over your content. This post shows how to add syndication feeds to a statically generated NextJS site",
            "date_modified": "2021-10-05T00:00:00.000Z"
        },
        {
            "id": "https://www.daan.fyi/writings/tools",
            "content_html": "<p class=\"chakra-text css-ju3ovf\">A couple of weeks ago someone shared <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://alexander-hansen.dev/blog/benefits-of-not-using-an-ide\">an article</a> on Hacker News that\ndiscussed the drawbacks of using an IDE for programming. Needless to say, when you touch\npeople’s tools, you can be sure to\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://news.ycombinator.com/item?id=28257116\">spark a hefty discussion</a>.</p> <span class=\"chakra-text css-1872at\"> <p class=\"chakra-text css-ju3ovf\">To be fair, the author did clarify that they’re not against IDE’s <em>in general</em> and they actually\nuse one on a daily basis.</p></span> <p class=\"chakra-text css-ju3ovf\">When reading the discussion, one of the first things I wondered is if there are places on the\ninternet where carpenters or plumbers furiously criticize each other’s choice of tools.\nBut <em>even that</em> has <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://news.ycombinator.com/item?id=28257382\">a place on Hacker News</a></p> <p class=\"chakra-text css-ju3ovf\">In this post I want to explore the fundamental problems with this type of discussion and how you\ncan embrace freedom of choice.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"its-all-about-context\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#its-all-about-context\"><span class=\"icon icon-link\"></span></a>It’s All about Context</h2> <p class=\"chakra-text css-ju3ovf\">When discussing someone else’s choice of tools — in this case the choice of editor or IDE — it’s\ngood to be mindful of what we <em>don’t know</em> about this person and their reasons for choosing certain\ntools. Aside from personal preference and/or familiarity, there can be lots of extra factors to\nconsider:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">We don’t know what kind of problems they’re working on</li><li class=\"css-0\">We don’t know the context in which they work (e.g. security requirements laid down by the company\nthey work for, available budget)</li><li class=\"css-0\">We don’t know their level of experience</li></ul> <p class=\"chakra-text css-ju3ovf\">I think it’s good form to voice an opinion only when we can see the whole picture. I also\nthink that people should be encouraged to <strong>choose the right tool for the job</strong>. And to put it\nsimply: <strong>the right tool for the job is the one that fits the problem and makes you the most\nproductive</strong>.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"its-also-about-definition\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#its-also-about-definition\"><span class=\"icon icon-link\"></span></a>It’s Also about Definition</h2> <p class=\"chakra-text css-ju3ovf\">Another issue with this kind of discussion is that everyone has a different idea of what really\nconstitutes an \"IDE\". We’re inclined to frame the choice of editor as a binary choice — \"pure text\neditor\" vs \"IDE\", almost like a false dichotomy — while it really is a spectrum. On this spectrum\nyou’ll not only find different editors, but even different configurations of the same editor with\nvarying degrees of \"smartness\" applied through plugins.</p> <p class=\"chakra-text css-ju3ovf\">So when someone says <em>\"why use an IDE when you can do everything an IDE does in VIM if you install\nthe following 20 plugins\"</em>, is this really so different from an actual IDE (that was branded as\nsuch)?</p> <h2 class=\"chakra-heading css-r5akja\" id=\"philosophies-in-tool-choices\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#philosophies-in-tool-choices\"><span class=\"icon icon-link\"></span></a>Philosophies in Tool Choices</h2> <p class=\"chakra-text css-ju3ovf\">When looking at how people setup their development environments, I basically see 2 different\napproaches:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">The <em>\"additive\"</em> approach: this basically follows the UNIX philosophy of composing many different\ntools that each do one thing well. It often involves a terminal-based editor like VIM, optionally\nwith some plugins and supported by external tools like grep, sed and awk that can help with\nrefactoring code. You basically stack tools until you have an \"integrated\" development environment</li><li class=\"css-0\">The <em>\"subtractive\"</em> approach: you take one \"big\" editor as the basis of your stack. This is often\nan editor that is branded as an IDE (e.g. Eclipse, Jetbrains editors). Then you take away/replace\n(\"subtract\") the parts that work better through dedicated tools (according to personal preference\nof course)</li></ul> <p class=\"chakra-text css-ju3ovf\">To me, both approaches have their merits and uses!</p> <h2 class=\"chakra-heading css-r5akja\" id=\"how-to-create-freedom-of-choice\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#how-to-create-freedom-of-choice\"><span class=\"icon icon-link\"></span></a>How to Create Freedom of Choice?</h2> <p class=\"chakra-text css-ju3ovf\">I think the most important question around editors is not</p> <blockquote class=\"css-p56y4k\"> <p class=\"chakra-text css-ju3ovf\"><em>How to choose the right editor?</em></p>\n</blockquote> <p class=\"chakra-text css-ju3ovf\">but rather</p> <blockquote class=\"css-p56y4k\"> <p class=\"chakra-text css-ju3ovf\"><em>How to enable each member of my team to choose the editor that makes them <strong>most productive</strong>,\nwhile enabling <strong>effective collaboration</strong>?</em></p>\n</blockquote> <p class=\"chakra-text css-ju3ovf\">Here’s my recipe to do that:</p> <p class=\"chakra-text css-ju3ovf\">My basic starting point in teams: <em>everyone can use the editor/IDE of their choice</em>. To enable\neffective collaboration, the following rules must be followed:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">Editor configuration is never checked into version control, unless it’s generic and <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://editorconfig.org/\">applicable across editors</a>. Examples of generic editor configuration\nare: line endings, tabs vs spaces, max line length etc. There is some overlap with linters here</li><li class=\"css-0\">Enforce common code style through external tools (i.e. linters, code formatters)</li><li class=\"css-0\">Everyone should be able to build and run a project, regardless of the choice of editor,\npreferably through the terminal. This means that we’ll always prefer external tools for this.\nMany languages provide tooling for this:\n<ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">Java → Maven/Gradle</li><li class=\"css-0\">JS/TS → NPM</li><li class=\"css-0\">Go → Go</li><li class=\"css-0\">Rust → Cargo</li><li class=\"css-0\">…</li></ul>\n</li><li class=\"css-0\">Additionally, building and running code can be made easier and better reproducible by using\nMakefiles and/or Docker (combined with Docker Compose)</li></ul> <p class=\"chakra-text css-ju3ovf\">I have to admit that in some ways I also limit choice within my teams: building and running\nprojects often involves shell scripts which are portable between Linux and MacOS, but not to\nWindows. This can be solved by using WSL on Windows.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"this-is-my-setup\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#this-is-my-setup\"><span class=\"icon icon-link\"></span></a>This Is My Setup</h2> <p class=\"chakra-text css-ju3ovf\">My personal setup involves quite a lot of tools.</p> <p class=\"chakra-text css-ju3ovf\">For any \"serious\" development work (i.e. long stretches of coding and big projects) I take the\naforementioned \"subtractive\" approach. My basis is one of the Jetbrains tools, depending on the\nlanguage(s) I’m working with. I find the Jetbrains tools make <em>me</em> really productive and their <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.jetbrains.com/all/\"><em>All products pack</em></a> offers great value for money, especially with\ntheir huge loyalty discounts after 1 or more years.</p> <p class=\"chakra-text css-ju3ovf\">I still use the terminal and external tools for many things in this case. I put quite some time in\nimproving and maintaining <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://github.com/DandyDev/dotfiles\">my dotfiles</a> as well.</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">I prefer to use the terminal for: building, linting, running tests, using git</li><li class=\"css-0\">I prefer to use the IDE for: writing and editing code, refactoring, searching for code,\nfind/replace through regex</li></ul> <p class=\"chakra-text css-ju3ovf\">For quick and short edits and viewing files where speed is preferred and conveniences like syntax\nhighlighting and intellisense are not important, I use Sublime Text or VIM. Example of this:\nediting my dotfiles.</p> <p class=\"chakra-text css-ju3ovf\">Sometimes, but rarely, I use VSCodium for editing or viewing files which are not part of a project\nand which I want to reformat/reindent. This doesn’t work well for me in Sublime Text. For example:\nviewing/editing minified JSON files.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"conclusion\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#conclusion\"><span class=\"icon icon-link\"></span></a>Conclusion</h2> <p class=\"chakra-text css-ju3ovf\">To wrap this post up, I just want to reiterate: use whatever tools make you productive and help you\nsolve the problems you’re trying to solve and please let others do the same.</p> <p class=\"chakra-text css-ju3ovf\">And here’s some additional closing advice: should you ever grow unhappy with the tools you’re\nusing, just write a blog post extolling the virtues of your current tools. You can be sure people\non the internet will tell you how much better their tools are, thereby providing you with potential\nalternatives to your current setup 😇</p> <hr aria-orientation=\"horizontal\" class=\"chakra-divider css-1vt04vx\"/> <p class=\"chakra-text css-ju3ovf\"><em>Thanks to <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://twitter.com/djvdorp\">Dan</a> for proofreading this</em></p><span></span><span id=\"__chakra_env\" hidden=\"\"></span>",
            "url": "https://www.daan.fyi/writings/tools",
            "title": "Use Tools That Suit You and the Problem",
            "summary": "Don't let anyone tell you what tools to use. Make sure that your builds are tool-agnostic",
            "date_modified": "2021-09-10T00:00:00.000Z"
        },
        {
            "id": "https://www.daan.fyi/writings/amplify",
            "content_html": "<p class=\"chakra-text css-ju3ovf\">Have you ever gone above and beyond to give a product a fair chance, only giving up way past your\nown sanity and patience? I did. The product was <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://aws.amazon.com/amplify/\">AWS Amplify</a></p> <h2 class=\"chakra-heading css-r5akja\" id=\"lets-build-something-with-nextjs\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#lets-build-something-with-nextjs\"><span class=\"icon icon-link\"></span></a>Let’s Build Something with NextJS</h2> <p class=\"chakra-text css-ju3ovf\">When I started developing the primary (web) UI for the product we’re building at <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https:/source.ag\">Source</a>, I quickly decided to use the <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://nextjs.org/\">NextJS</a> framework as\nthe basis for the frontend. One thing I really like about NextJS is that it does <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://nextjs.org/docs/basic-features/pages\">filesystem-based\nrouting</a>. Even though I like to diss on PHP as much\nas the next person, this particular feature of NextJS reminds me a bit of PHP <em>in a good way</em>.</p> <p class=\"chakra-text css-ju3ovf\">Another very compelling feature of NextJS, is the ability to have different rendering strategies\nfor each different page. You can decide to use:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\"> <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://nextjs.org/docs/basic-features/pages#static-generation-recommended\">Static generation</a>\nfor pages and content that rarely change. These pages get pre-rendered at build time and can be\naggressively cached on a CDN.\nThese pages can of-course still be highly dynamic by using client-side data fetching methods</li><li class=\"css-0\"><a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://nextjs.org/docs/basic-features/pages#server-side-rendering\">Server-side rendering</a> for\npages that need to return different content on each request and/or for each different user</li><li class=\"css-0\"><a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://nextjs.org/docs/basic-features/data-fetching#incremental-static-regeneration\">Incremental static regeneration</a>,\nwhich is a variation on Static generation that will cache pages for a period you specify and then\nregenerate the pages server-side when they’re considered stale</li></ul> <h2 class=\"chakra-heading css-r5akja\" id=\"deployment\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#deployment\"><span class=\"icon icon-link\"></span></a>Deployment</h2> <p class=\"chakra-text css-ju3ovf\">This particular feature requires a specific hosting setup that supports the different <em>flavours</em>\nof rendering. You basically want:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">a good CDN to cache and serve your static pages</li><li class=\"css-0\">a server-side solution to serve the server-side rendered pages and facilitate incremental static\nregeneration. This should also take care of <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://nextjs.org/docs/api-routes/introduction\">API routes</a>, should you use them</li></ul> <p class=\"chakra-text css-ju3ovf\">The NextJS documentation <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://nextjs.org/docs/deployment\">mentions a couple of options</a> for\ndeployment:</p> <ol role=\"list\" class=\"css-bux2of\"><li class=\"css-0\">Use <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://vercel.com/\">Vercel</a>. Vercel is the company behind NextJS. They offer a seamless\nexperience where you can use any rendering method, and Vercel will deploy each part of your app\nin the right way. One neat thing they do is that they’ll convert your server-side rendered pages\nand API routes into serverless functions that they’ll deploy to edge locations all over the globe.</li><li class=\"css-0\">Setup a NodeJS server somewhere for the server-side stuff and use a CDN manually to serve the\nstatic content.</li></ol> <p class=\"chakra-text css-ju3ovf\">At Source however, we’ve made a conscious decision to use AWS for all of our infrastructure needs. We’re\ntoo early in the lifecycle of both our product and company to consider a hybrid cloud setup and\nAWS offers all the features that we need for prices that are reasonable <em>for now</em>. Through one of\nour investors we also got a boat-load of AWS credits to get started, which helps.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"amplify\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#amplify\"><span class=\"icon icon-link\"></span></a>Amplify</h2> <p class=\"chakra-text css-ju3ovf\">I didn’t want to manually set up a hybrid deployment with NodeJS and CDN - which I could probably do\nusing Cloudfront and ECS - so I looked for alternatives. AWS Amplify claims to be the</p> <blockquote class=\"css-p56y4k\"> <p class=\"chakra-text css-ju3ovf\">Fastest, easiest way to build mobile and web apps that scale</p>\n</blockquote> <p class=\"chakra-text css-ju3ovf\">And they <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://docs.amplify.aws/guides/hosting/nextjs/q/platform/js/\">claim to support NextJS</a>\nas well as <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://aws.amazon.com/blogs/mobile/host-a-next-js-ssr-app-with-real-time-data-on-aws-amplify/\">server-side rendering</a>\nby virtue of <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://aws.amazon.com/lambda/edge/\">Lambda@Edge</a></p> <p class=\"chakra-text css-ju3ovf\">Sounds great! So how does that all work?</p> <h2 class=\"chakra-heading css-r5akja\" id=\"amplify---the-setup\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#amplify---the-setup\"><span class=\"icon icon-link\"></span></a>Amplify - The Setup</h2> <p class=\"chakra-text css-ju3ovf\">The idea behind Amplify is that it lets you focus on building your app without having to worry\nabout the infrastructure. This means that it will not only let you build and deploy your frontend\neasily, it will also let you hook-up backend components like <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://docs.amplify.aws/lib/auth/getting-started/q/platform/js/\">authentication</a> through\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://aws.amazon.com/cognito/\">Cognito</a>,\na <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://docs.amplify.aws/lib/graphqlapi/getting-started/q/platform/js/\">GraphQL API</a> using\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://aws.amazon.com/appsync/\">AppSync</a>\nand a <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://docs.amplify.aws/lib/datastore/getting-started/q/platform/js/\">DataStore</a>.</p> <p class=\"chakra-text css-ju3ovf\">The way Amplify manages all of this, is through the idea of \"backends\". A backend contains one or\nmore of the aforementioned components. You can setup different backend environments in Amplify and\ncouple these to different (git) branches of your frontend.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"amplify---the-developer-experience\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#amplify---the-developer-experience\"><span class=\"icon icon-link\"></span></a>Amplify - The Developer Experience</h2> <p class=\"chakra-text css-ju3ovf\">We are bringing our own database and API and wanted to use a pre-existing Cognito user pool.\nAmplify lets you import an existing Cognito user pool instead of creating one for you, and this\nworked fine… until I tried to create a second \"backend environment\" with a different Cognito\nuser pool.</p> <p class=\"chakra-text css-ju3ovf\">I want to allow different users on our development environment than our production\nenvironment. These environments correspond to the <code class=\"chakra-code css-lqvy6z\">main</code> branch in Git (production) and any other\nbranches in Git (development).</p> <h4 class=\"chakra-heading css-1k9a9w9\" id=\"how-do-i-tie-an-amplify-backend-environment-to-a-frontend-branch\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#how-do-i-tie-an-amplify-backend-environment-to-a-frontend-branch\"><span class=\"icon icon-link\"></span></a>How Do I Tie an Amplify Backend Environment to a Frontend Branch?</h4> <p class=\"chakra-text css-ju3ovf\">Interaction with Amplify is done through the web console or the <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://docs.amplify.aws/cli/\">Amplify CLI</a>. According to the documentation, we can create a new\nAmplify backend environment like this:</p>\n<pre> <code class=\"chakra-code css-lqvy6z\">amplify env add\n</code></pre> <p class=\"chakra-text css-ju3ovf\">But nowhere is it made clear how this is linked to our frontend branch. The Amplify CLI tries to\nmimic the <code class=\"chakra-code css-lqvy6z\">git</code> CLI by having <code class=\"chakra-code css-lqvy6z\">amplify push</code> and <code class=\"chakra-code css-lqvy6z\">amplify pull</code>. So I assume we need to <code class=\"chakra-code css-lqvy6z\">push</code> our\nnew environment to the cloud. Does this command depend on the git branch I’m on? I don’t know.\nI could just as easily overwrite my existing backend environment when using this command.</p> <p class=\"chakra-text css-ju3ovf\">Eventually I was able to create a <code class=\"chakra-code css-lqvy6z\">main</code> environment and a <code class=\"chakra-code css-lqvy6z\">dev</code> environment, but no matter how hard\nI tried, I could not get those environments to use different Cognito user pools.</p> <h4 class=\"chakra-heading css-1k9a9w9\" id=\"how-do-new-team-members-setup-an-existing-project\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#how-do-new-team-members-setup-an-existing-project\"><span class=\"icon icon-link\"></span></a>How Do New Team Members Setup an Existing Project?</h4> <p class=\"chakra-text css-ju3ovf\">The Amplify CLI will create some configuration files, some of which you need to commit to git, and\nsome of them you need to ignore. These files should make the build reproducible. It is unclear\nhowever, what a new developer needs to do to be able to run an existing Amplify project.\nThe documentation mentions multiple Amplify CLI commands to setup a project:</p>\n<pre> <code class=\"chakra-code css-lqvy6z\">amplify pull\n</code></pre>\n<pre> <code class=\"chakra-code css-lqvy6z\">amplify init\n</code></pre>\n<pre> <code class=\"chakra-code css-lqvy6z\">amplify configure project\n</code></pre>\n<pre> <code class=\"chakra-code css-lqvy6z\">amplify env checkout <my-env>\n</code></pre> <p class=\"chakra-text css-ju3ovf\"><em>To be run in arbitrary order?</em></p> <p class=\"chakra-text css-ju3ovf\"> <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://stackoverflow.com/questions/60365208/how-to-import-existing-aws-amplify-back-end-into-an-empty-aws-amplify-project-lo\">Three</a>\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://stackoverflow.com/questions/60951924/how-do-i-continue-working-with-amplify-on-a-new-machine\">similar</a>\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://stackoverflow.com/questions/61104135/how-to-run-an-existing-aws-amplify-project\">questions</a>\non StackOverflow give 3 different answers on this topic.</p> <p class=\"chakra-text css-ju3ovf\">When I was on-boarding new team-members, we basically tried some commands in different order until\nwe were able to run the project locally for that engineer.</p> <h4 class=\"chakra-heading css-1k9a9w9\" id=\"how-do-i-figure-out-why-my-build-failed\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#how-do-i-figure-out-why-my-build-failed\"><span class=\"icon icon-link\"></span></a>How Do I Figure Out Why My Build Failed?</h4> <p class=\"chakra-text css-ju3ovf\">In short: <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://github.com/aws-amplify/amplify-console/issues/2065\">you don’t</a>. Or you enlist\nthe help of AWS Support (which you will have to pay for). The Amplify web console doesn’t share\ndetailed build logs, so you’ll have to fix your problems by trial and error.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"amplify---the-bugs\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#amplify---the-bugs\"><span class=\"icon icon-link\"></span></a>Amplify - The Bugs</h2> <p class=\"chakra-text css-ju3ovf\">AWS Amplify seems to have quite some bugs. For example: when you use Gitlab, you\ncannot put the source code of your project <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://github.com/aws-amplify/amplify-console/issues/1941\">in a sub-group</a>. This will silently\nfail your build, with no clear error message in sight.</p> <p class=\"chakra-text css-ju3ovf\">The aforementioned problem of using multiple Cognito user pools for different\nenvironments of one Amplify frontend, I also consider a bug.</p> <p class=\"chakra-text css-ju3ovf\">Not having access to the <em>actual</em> build logs, I also consider a bug.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"amplify---no-help-included\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#amplify---no-help-included\"><span class=\"icon icon-link\"></span></a>Amplify - No Help Included</h2> <p class=\"chakra-text css-ju3ovf\">The most painful issue I have with AWS Amplify - and AWS in general - is the complete lack of\nsupport. You are paying a lot of money for their services, but that does not come with any form of\nsupport, unless you pay extra. And when you make use of that paid support, it goes something like\nthis:</p> <ol role=\"list\" class=\"css-bux2of\"><li class=\"css-0\">Contact AWS Business support through their website and try to explain your problem in a plain\ntext field that you cannot resize or use formatting in</li><li class=\"css-0\">Wait far longer than the promised 4 hours</li><li class=\"css-0\">Get a response from someone telling you they’ll forward it to \"the team\" (why not have someone\nrespond who can actually help you with your problem?)</li><li class=\"css-0\">Get a canned response with a solution akin to \"turn it off and on again\"</li><li class=\"css-0\">Tell them you have an <em>actual problem</em></li><li class=\"css-0\">Get forwarded to the next person who you have to clue in again on what your problem is</li><li class=\"css-0\">Go to 2 and repeat</li></ol> <p class=\"chakra-text css-ju3ovf\">This means that in practice, AWS Amplify is <em>not usable</em> unless you are willing to pay extra for\nsupport and have a lot of patience.</p> <p class=\"chakra-text css-ju3ovf\">As a side note, I find it really frustrating that with big corporations like Amazon in general, you\nquickly feel helpless and ignored when you have problems. Stories about Google customer support (or\nlack thereof) are rampant on Hacker News, and I think Amazon is no different. You’d think that with\nso much revenue they should be able to set up actual proper customer support 🙄</p> <h2 class=\"chakra-heading css-r5akja\" id=\"the-pattern-with-aws\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#the-pattern-with-aws\"><span class=\"icon icon-link\"></span></a>The Pattern with AWS</h2> <p class=\"chakra-text css-ju3ovf\">I think that these problems with Amplify are endemic of a larger problem with AWS: <strong>their PaaS and\nSaaS solutions suck</strong>. Aside from pricing (which is quite high compared to competitors like\nDigital Ocean), I think AWs’ infrastructure-as-a-service offerings are fine. If you want to have a\nbunch of servers (EC2), a database here and there (RDS) and some serverless functions (Lambda), AWS\nwill serve you just fine.</p> <p class=\"chakra-text css-ju3ovf\">But if you want something on top of that, like authentication (Cognito), or a PaaS solution like\nAmplify, be prepared for a sub-par offering compared to the competition. I think Amazon should\nfocus on strengthening their core offerings instead of offering everything and the kitchen sink.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"the-solution\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#the-solution\"><span class=\"icon icon-link\"></span></a>The Solution</h2> <p class=\"chakra-text css-ju3ovf\">In the end, I dropped Amplify and went with Vercel. $20/user/month is a small price to pay for\nactually being able to work on the product instead of fighting AWS services and support.</p><span></span><span id=\"__chakra_env\" hidden=\"\"></span>",
            "url": "https://www.daan.fyi/writings/amplify",
            "title": "The Pitfalls of Deploying a Nextjs Frontend on Aws Amplify",
            "summary": "Half-baked products lead to much frustration",
            "date_modified": "2021-08-23T00:00:00.000Z"
        },
        {
            "id": "https://www.daan.fyi/writings/new",
            "content_html": "<p class=\"chakra-text css-ju3ovf\">I don’t really know how to say this, but: I’m going to try and blog again! After building this site,\nI didn’t even know how to begin <em>actually writing</em> again. Looking for inspiration, I studied some\nfamous tech people’s websites but came up empty trying to find examples of \"first blog posts\" there.\nMost people like to just dig right in with some on-topic tech content it seems…</p> <p class=\"chakra-text css-ju3ovf\">But <strong>HERE IT IS!</strong></p> <p class=\"chakra-text css-ju3ovf\"><em>My first blog post on my new website.</em></p> <h2 class=\"chakra-heading css-r5akja\" id=\"previously-on\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#previously-on\"><span class=\"icon icon-link\"></span></a>Previously on…</h2> <p class=\"chakra-text css-ju3ovf\">It’s been nigh on 4 years since I last wrote something on my old crib <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://dandydev.net\">dandydev.net</a> (by the time you’re reading this, I’ll have most probably\nredirected everything from there to here). I don’t really know why I stopped blogging in the first\nplace, but it probably had something to do with life/work/… getting in the way (or me letting it\nget in the way anyways).</p> <p class=\"chakra-text css-ju3ovf\">So what has been going on?</p> <p class=\"chakra-text css-ju3ovf\">After working for KLM Royal Dutch Airlines for 4.5 years I got a dream position at <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://source.ag\">Source.ag</a>, a new startup co-founded by a friend, focusing on Agriculture & AI.\nAs VP of Engineering I help build both the tech and the team and I’m loving it to bits!</p> <p class=\"chakra-text css-ju3ovf\">Keeping with the theme of this post, it’s really exciting to start something so brand new. I’m\nactually employee #1 which gives me ample opportunity to have a major impact. There are no\npre-established rules, processes, dynamics. For the first couple of months, it was just the 2\nco-founders and me figuring out what to build, how to build it and then actually building it while\nat the same time trying to grow the company. And now, 5 months after I started, we’re 12 lifeforms strong\nand growing!</p> <p class=\"chakra-text css-ju3ovf\">And after my previous job veered more and more into organizational politics instead of tech, it\nfeels great to be building an actual product again. It’s both amazing and terrifying to code most\nof an MVP all by yourself in 5 months 😱</p> <p class=\"chakra-text css-ju3ovf\"><em>If you’re interested in bringing positive change to the food system, <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://source.ag/careers/\">you can join us</a></em></p> <h2 class=\"chakra-heading css-r5akja\" id=\"the-excitement-of-new-things\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#the-excitement-of-new-things\"><span class=\"icon icon-link\"></span></a>The Excitement of New Things</h2> <p class=\"chakra-text css-ju3ovf\">Interlude: why is it that I find starting new things so exciting? I often wonder about this.</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">I’m probably one of the few people not actually terrified of starting a new job</li><li class=\"css-0\">There are few things that give me more energy than starting a new side-project</li><li class=\"css-0\">Even as a gamer, I often spend more time <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://steamcommunity.com/id/kajel/games/\">trying out</a>\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.gog.com/u/Curois/games\">new games</a> than actually finishing them\n(don’t worry, I also have a Humble Bundle backlog and a PSN profile full of games that you don’t\nknow about yet 🙄)</li></ul> <p class=\"chakra-text css-ju3ovf\">I think it comes down to wanting to <em>learn</em> new things as much as possible and I guess I just love\nexploring the unknown.</p> <p class=\"chakra-text css-ju3ovf\">But I’m gonna be honest: the challenge is to stick with things. For each side-project I finished,\nthere are many left in the dust. They were never time badly spent, because each time I learnt\nsomething new. But I think there is value in finishing things as well.</p> <p class=\"chakra-text css-ju3ovf\">I hope that a different approach with this blog will make it easier for me to stick with it.</p> <h2 class=\"chakra-heading css-r5akja\" id=\"doing-things-differently\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#doing-things-differently\"><span class=\"icon icon-link\"></span></a>Doing Things Differently</h2> <p class=\"chakra-text css-ju3ovf\">I want to sound off this rambling first blog post by sharing how things that are (going to be)\ndifferent with this website:</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">I ditched my old domain dandydev.net for some place simpler and more elegant: <strong>daan.fyi</strong>.\nI paid a pretty penny to get a domain of only my first name and an extension that didn’t look\ntoo ridiculous and I love it. It feels a bit more mature as well</li><li class=\"css-0\">Always looking to learn new things, I chose to forego a traditional static site generator for a\nmore hand-built experience. This site was built on <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://nextjs.org/\">NextJS</a>, React and\nTypescript. And I actually designed and built the theme myself using\n<a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://chakra-ui.com/\">ChakraUI</a>. I did get a lot of inspiration from other people’s websites\n(see below)</li><li class=\"css-0\">I’m writing my posts using <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://mdxjs.com/\">MDX</a> instead of regular markdown. For this\nparticular post there is not actually any difference, but MDX will allow me to create more\ntailored and interactive experiences in the future, should I need/want it</li><li class=\"css-0\">In terms of content, I plan to have a different approach than before:\n<ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\">I’ll try to write shorter posts and consequently (hopefully) write more often</li><li class=\"css-0\">I’m allowing myself to write about other stuff than tech. This blog is meant to <em>express</em>\nmyself more than to <em>advertise</em> myself. This means I’ll probably write about non-tech topics\nlike movies & tv-shows I’ve seen, games I played and maybe even reflect on politics once in\na while 😬 Once this kind of content arrives, I’ll make sure it’s easy to see and skip it 😉</li></ul>\n</li></ul> <h2 class=\"chakra-heading css-r5akja\" id=\"acknowledgements-of-inspiration\"> <a class=\"chakra-link css-auue23\" aria-hidden=\"true\" tabindex=\"-1\" href=\"#acknowledgements-of-inspiration\"><span class=\"icon icon-link\"></span></a>Acknowledgements of Inspiration</h2> <p class=\"chakra-text css-ju3ovf\">When building this website, there were a few websites that inspired me and/or helped me with actual\nsolutions to coding problems (yay for open source!):</p> <ul role=\"list\" class=\"css-a49utw\"><li class=\"css-0\"> <a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://alyssax.com/\">Alyssa X</a></li><li class=\"css-0\"><a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://leerob.io/\">Lee Robinson</a></li><li class=\"css-0\"><a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://www.joshwcomeau.com/\">Josh W. Comeau</a></li><li class=\"css-0\"><a target=\"_blank\" rel=\"noopener\" class=\"chakra-link css-3u9hqk\" href=\"https://marcel.is/\">Marcel Krcah</a></li></ul> <hr aria-orientation=\"horizontal\" class=\"chakra-divider css-1vt04vx\"/> <p class=\"chakra-text css-ju3ovf\">See you next time!</p><span></span><span id=\"__chakra_env\" hidden=\"\"></span>",
            "url": "https://www.daan.fyi/writings/new",
            "title": "The Joy of Starting Something New",
            "summary": "The start of a new blog/job/...",
            "date_modified": "2021-08-16T00:00:00.000Z"
        }
    ]
}