<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Caleb Meredith</title>
    <description>The latest articles on DEV Community by Caleb Meredith (@calebmer).</description>
    <link>https://dev.to/calebmer</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1101%2F20d77305-05be-41b4-8192-3cad3a7e77c3.jpg</url>
      <title>DEV Community: Caleb Meredith</title>
      <link>https://dev.to/calebmer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/calebmer"/>
    <language>en</language>
    <item>
      <title>How to survive (and thrive!) in software engineering interviews</title>
      <dc:creator>Caleb Meredith</dc:creator>
      <pubDate>Sat, 11 Jul 2020 22:20:04 +0000</pubDate>
      <link>https://dev.to/calebmer/how-to-survive-and-thrive-in-software-engineering-interviews-39oo</link>
      <guid>https://dev.to/calebmer/how-to-survive-and-thrive-in-software-engineering-interviews-39oo</guid>
      <description>&lt;p&gt;I’m an engineer who's beginning to interview candidates for coding work. I’m loving meeting new people, and I’m also benefitting a lot from the incredibly interesting conversations that spark in the interview room. However, while it’s exciting for me to see the process from the other side, I know full well how daunting it is to be in the interview chair. I wrote this article hoping to assuage some fears by removing some of the mysteries around interviewing for software engineering positions.&lt;/p&gt;

&lt;p&gt;Right now, my understanding of the gap between being an interviewee and an interviewer is developing. As I learn more about the process from the interviewer side, from colleagues who’ve been interviewing for far longer than I have, I can see clearly (with hindsight) some of the more egregious errors I made in the interviewee chair. I could tell stories about the things that I’ve done…&lt;/p&gt;

&lt;p&gt;Ok, just a few. Purely for illustrative purposes. And maybe some amusement. Let’s call these—uhh—Story Charmander, Story Squirtle and Story Bulbasaur. Because why not?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Story Charmander&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The worst interview I ever had ended early. Why? I was way too forthright with my opinions, and immovable on my stance. Things I’m still working on today. And while I am a huge proponent of confidence (see below), my nerves had pushed me right through confidence and into arrogance. Not a good interviewing look! More on this later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Story Squirtle&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My second story is about a time when I couldn’t come up with a simple answer, so instead grasped at the most esoteric, niche data structures I could muster (&lt;a href="http://lampwww.epfl.ch/papers/idealhashtrees.pdf"&gt;Bagwell’s ideal hash trees&lt;/a&gt; with a branching factor of 32, since you asked) to solve…wait for it…a problem asking me to do date math skipping weekends. The interviewer was, to their eternal credit, extremely patient, and once I’d stopped grasping at straws, gently queried whether that would really be the most efficient, cost effective solution for a client. That brought me back down to earth pretty quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Story Bulbasaur&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The third story is about the time I helped build an app and coded in right / left swiping with &lt;a href="https://redux-saga.js.org/"&gt;redux-saga&lt;/a&gt; that almost blew my own mind with its elegant beauty. Yes, it was that good. I wanted to explain all the awesome details of the code to my employer. And my employer &lt;del&gt;was so fascinated that he paid me double to write a book about it&lt;/del&gt; didn’t care. Not one single bit.&lt;/p&gt;

&lt;p&gt;I still think fondly about that code, from time to time.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, you’re preparing for a software interview? Welcome!
&lt;/h2&gt;

&lt;p&gt;Now that I’m in the other chair, I find that I have empathy with both sides. One of the really interesting things I didn’t appreciate before is that the interviewing process really is all about communication. By which I definitely mean two-sided communication. This train of thought got me mulling on all the things that I wish someone had told me before I started interviewing. So here, I’m going to explain some of the things that we look for in candidates. My intention is to make the process less intimidating, if possible.&lt;/p&gt;

&lt;p&gt;There are a lot of myths around; stories that seem designed to worry candidates. I was certainly anxious, particularly given my oddly shaped background. And this needless worrying did me no favours at all. This article is intended to be more transparent, dispel some of those myths, and explain the process a little better.&lt;/p&gt;

&lt;p&gt;I also want to spend a little time exploring how personal behaviors that we put on for one reason can very create different impressions on those around us (please refer back to Story Charmander). I hope that the following points will remove some of the mystery surrounding interview rooms, and maybe even allow you to enjoy the experience of meeting people who, most likely, share some of your passions with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interview terrors: taming the beast
&lt;/h2&gt;

&lt;p&gt;Lots of people get these. Arguably most people. We all feel worried, agitated, like our stomachs are full of &lt;del&gt;butterflies&lt;/del&gt; raging, fanged netherbeings.&lt;/p&gt;

&lt;p&gt;It doesn’t have to be this way! Having some nerves before important events is a good thing, causing adrenaline to flow, which in turn will help your natural charisma to shine in the room. However, unchanneled fear is more harmful than not, in several ways. Here, I’m going to share with you a few strategies I’ve learned to face some common pitfalls within engineering interviews.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rejections! Fresh rejections! Get ‘em while they’re hot!
&lt;/h2&gt;

&lt;p&gt;Some people hamstring themselves, being so worried about failing the interview that they fail to even apply for the job. This is a huge shame. Really. I almost want to shake some of my intelligent, awesome friends when I think about the jobs that they’ve settled for, instead of applying for the jobs they deserve, all because of a lack of confidence. Their inner voice made the decision that they weren’t going to get the job, and they then made sure of that by never applying.&lt;/p&gt;

&lt;p&gt;Look, truthfully, for most people, the fact is that you will apply for more jobs than you land, i.e. you will face some rejections. This is ok! Please, don’t let fear of rejection put you off applying in the first place. If you don’t give yourself a chance, why would someone else?&lt;/p&gt;

&lt;p&gt;I think we’re all familiar with &lt;a href="https://www.entrepreneur.com/article/311319"&gt;rejection-to-success stories&lt;/a&gt;; everyone has at least one and you can fall down a plethora of internet wormholes reading them. So I won’t repeat those stories here. However, recently, I‘ve been finding it more helpful to train myself to look forward to the rejections — to consider each rejection as one stepping stone closer to a YES. I’m really enjoying &lt;a href="https://www.rejectiontherapy.com/about-jia"&gt;Jia Jiang's rejection therapy&lt;/a&gt; talks as a way of understanding this process.&lt;/p&gt;

&lt;p&gt;I like to imagine the process as collecting a bunch of rejections that I can then trade in for a YES at a swap meet. You may have a different visualization technique.&lt;/p&gt;

&lt;h2&gt;
  
  
  The interview itself: Shall I compare thee to a band-aid?
&lt;/h2&gt;

&lt;p&gt;Ah, the best bit. Are you a ripper-offer, or a slow peeler?&lt;/p&gt;

&lt;p&gt;In theory, a perfect interview would be you demonstrating your smart, cool, funny qualities so well that when you leave, the interviewer(s) can’t imagine being on a team without you. Perhaps you’d have a conversation ignited by glowing sparks about developments and solutions in a field you’re both interested in. (Hopefully. If the interests aren’t shared, there may be bigger problems to fix 😉).&lt;/p&gt;

&lt;p&gt;However, in practice, know this: the interviewer is looking for indications of your skills and behaviors. Essentially, they want to know three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Can you do the job as advertised?&lt;/li&gt;
&lt;li&gt;Can you learn fast?&lt;/li&gt;
&lt;li&gt;Are you a person they want to work with for the next three—five years?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And don’t forget, crucially, the interviewer should also want to show &lt;em&gt;you&lt;/em&gt; how cool the company is to work for.&lt;/p&gt;

&lt;p&gt;Anything else is just icing on the cake. Flowing conversation would be amazing, but honestly, one interviewer may be trying to remember to assess you and not just have a fun conversation, another may be worried about ensuring you’re having a good time; meanwhile you are trying to remember how html works. No one single interviewer gets a final say in these things. What I'm trying to say is that it’s tough, and there are a multitude of moving parts to interviews.&lt;/p&gt;

&lt;p&gt;And recently, I’ve actually been thinking, instead of sugar coating this process, maybe &lt;em&gt;the truth&lt;/em&gt; is really the best that can be said about this. An interview isn’t intended to be a walk in the park. Hey, 👁👄👁. Just acknowledging that fact will allow you to get to grips with the nature of the beast.&lt;/p&gt;

&lt;p&gt;So yes, you &lt;em&gt;are&lt;/em&gt; being evaluated while you are in the room. But please don’t forget, you should be doing some evaluating of your own while you’re in the room! Do you want to work with your interviewers? Do you get a good vibe as you walk through the offices? Interviews are not one-sided lectures—you should actively participate in making your own judgments about the company. Understand that the interview is a necessary part of this process. It might not be pleasant, but facing it with strength allows you to have some power over the situation.&lt;/p&gt;

&lt;p&gt;Also please note, if you’re more of a slow band-aid peeler, sorry—I don’t know of other, more useful advice for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The interview itself - some answers are more right than others
&lt;/h2&gt;

&lt;p&gt;Let’s get into the details. The list of three things above is a summary, and there is a bunch of information out there on &lt;a href="https://www.indeed.com/career-advice/interviewing/interview-question-tell-me-about-yourself"&gt;learn how to talk about yourself, your achievements and your abilities&lt;/a&gt;. I have faith in you—you’ve got this part.&lt;/p&gt;

&lt;p&gt;But that stuff? That’s the basic stuff. Here’s where you’re really going to make an impression. Try to remember at all times that you are being considered not just for the job as described, but as an individual who’s going to be able to grow and develop alongside the rest of the people in the company. Your interviewers want to see that you have that potential. How do we look for it?&lt;/p&gt;

&lt;p&gt;Well, there are a few indications, and one really interesting one I want to talk about relates to Story Bulbasaur (see above).&lt;/p&gt;

&lt;p&gt;The moral of that cautionary tale is that yes, code can be beautiful, and complex, and imaginative. Is this always what a client is paying you to do? No. Is it ever? Unlikely. Your clients probably won’t care about the intricate, clever solution you came up with to fix their issue. They just want to know it’s fixed.&lt;/p&gt;

&lt;p&gt;But wait! There's more ... On the other hand, your co-workers will care &lt;em&gt;very much&lt;/em&gt; what solutions you are using, as they’ll be the ones helping to maintain and develop your code in the future. They will also be the audience you want to woo with well-designed code.&lt;/p&gt;

&lt;p&gt;So long story short, in the interview room, when we are looking for potential, we are almost certainly looking for your ability to take a practical approach when it comes to work. The trick to this is to try to achieve a balance between demonstrating your knowledge, and being pragmatic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The interviewers: just…some other people?
&lt;/h2&gt;

&lt;p&gt;A point so important, so vital, so often-forgotten: we’re just people. Moreover, we are people who want to stop interviewing other people so we can get back to work, so that we can go home on time. This incentivizes us to be on your side — truly, we want you to be ✨The One✨ so that we can end the interview early!&lt;/p&gt;

&lt;h2&gt;
  
  
  Techniques for Improvement
&lt;/h2&gt;

&lt;p&gt;So, now you have some of the common pitfalls and experiences that many of us go through on this journey. Here, if you’re interested, are some of my thoughts on how to change your approach to software interviews from now on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Confidence is Key
&lt;/h2&gt;

&lt;p&gt;Work on your confidence before getting into the room. Really work on it. Use affirmations or whatever is necessary. You need to be able to talk with assurance about what you’ve achieved, and use your skills to solve problems while in the room. If you don’t believe in yourself, it’s going to be harder for you to do these things. The interview is about proving to us in person that you have the skills your resume said you had.&lt;/p&gt;

&lt;p&gt;Always try to aim for balance. At this point, please refer back to my personal ‘Story Charmander’. For some people (guilty), confidence under pressure has a habit of mutating into something that seems like arrogance. Work on your communication skills before the interview with friends and family members. Remember, we can’t read your mind, so something that may seem obvious to you will need to be explained to people who don’t live inside your head. Think of it like this: remember how for school math tests, you couldn’t get high marks unless you showed your work? Show us your work! We want to know how you’re arriving at your conclusions.&lt;/p&gt;

&lt;p&gt;And finally, take the time to understand that in this area, just like everything else in life, there are very few cut-and-dry answers. Almost everything will have grey areas which can be debated and played with. Part of any interviewer’s job will be to test your boundaries and see how well you work in a team. As long as you can’t be malleable and accept other points of view, you’ll be telling your own ‘Story Charmander’ to people for a while.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practice may not make perfect, but it sure builds muscle memory
&lt;/h2&gt;

&lt;p&gt;I wholeheartedly recommend that you practice interviewing in preparation for an interview. Find a friend who is familiar with interviewing and set up some Zoom time with them. Or join an interview practice group - these do exist, and you just have to find them. You’re not practising to get perfect, because you won’t. What you will do is improve and build your personal tool-set. Work on spotting patterns rather than aiming to do every problem under the sun. We’re interested in the solutions you offer, sure, but also your routes to solutions, the way you think, and the tools you have at your disposal and choose to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Programming languages and problem solving
&lt;/h2&gt;

&lt;p&gt;Try to be comfortable in at least one programming language, but don’t get hung up on your usage speed. Remember, we’re not looking at how fast you can type, or how many languages you can list. We are looking at how you use the tools at your disposal to effectively solve practical problems. Often, a candidate who is very familiar with only one language but has spent time practically using a language will outperform a candidate who is familiar with three—four languages but spent no time practically using those languages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Will I have to use a whiteboard like on TV?
&lt;/h2&gt;

&lt;p&gt;Most likely yes, this will probably come up. You may need to show your work on a whiteboard. Seems like it’s easy as pie to simultaneously think, talk, write on a board and explain your thinking when the people on TV do it, right?&lt;/p&gt;

&lt;p&gt;Yeah, it’s not.&lt;/p&gt;

&lt;p&gt;It requires some serious hand-eye co-ordination, the ability to organize your thoughts, and simultaneously present. It’s further complicated in current, social distancing times with the necessity to ensure that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Whatever program you’re using for the interview will allow you to present; and&lt;/li&gt;
&lt;li&gt; You have enabled the necessary permissions to be able to present.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My advice?&lt;/p&gt;

&lt;p&gt;Practise presentation skills with a friend who enjoys being talked at. Use &lt;a href="https://www.google.com/docs/about/"&gt;Google Docs&lt;/a&gt; and &lt;a href="https://miro.com/"&gt;Miro&lt;/a&gt;. Check your settings several times before any interviews begin. Then practise presenting again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The thing I most want you to take away from this is the fact that we are all just people. If you and we are in a room together, it means the recruiting team believes you can pass based on your resumé. Whether your resume is full or not, you’re in the room, so try to have fun talking about the thing you enjoy doing! And know this:&lt;/p&gt;

&lt;p&gt;We, as interviewers, want you to succeed so that we can go write some more cool stuff. We want you to succeed so that we can have an extra person on the team to do even more cool stuff with. The interview is simply an opportunity for you to wow us in person.&lt;/p&gt;

&lt;p&gt;Now, go forth and interview.&lt;/p&gt;

&lt;p&gt;And let me know if you have any questions.&lt;/p&gt;

&lt;p&gt;Because I’m interested.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>career</category>
      <category>interview</category>
    </item>
    <item>
      <title>Tired: Golf, Wired: Boardgames</title>
      <dc:creator>Caleb Meredith</dc:creator>
      <pubDate>Mon, 15 Jul 2019 19:00:00 +0000</pubDate>
      <link>https://dev.to/calebmer/tired-golf-wired-boardgames-1i14</link>
      <guid>https://dev.to/calebmer/tired-golf-wired-boardgames-1i14</guid>
      <description>&lt;p&gt;My mom is an accountant and a lot of people in her office enjoy playing golf. However, my mom doesn’t play golf so that means to join recreational business outings that involve golf she’s either aimlessly wandering the playing field or not participating at all.&lt;/p&gt;

&lt;p&gt;This got me thinking, what is the future of business recreation? Will it continue to be dominated by golf, or is golf as business recreation a generational thing?&lt;/p&gt;

&lt;p&gt;I predict that the future of business recreation in the next 20–50 years will be boardgames! Boardgames are great, they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cheap:&lt;/strong&gt; The most expensive games max out around $60. That’s quite reasonable when you have 5–8 players.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inclusive:&lt;/strong&gt; Anyone can play! Generally, everyone will be around the same experience level. These games are also designed to be fun for newcomers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaborative:&lt;/strong&gt; A good game will also serve as a team-bonding exercise. You can get to know your co-workers better by playing a co-operative game or by playing against each other in a hidden information game.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Short:&lt;/strong&gt; You can pick a game that fits into the time you have. Games with quick 30 minute rounds allows parents to play while still getting home to their families.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible:&lt;/strong&gt; All you need is a table, people, and the game. You don’t need a full golf course or equipment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m not talking about classic boardgames like Monopoly or Risk. I’m talking about the &lt;em&gt;huge&lt;/em&gt; wave of indie boardgames.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcalebmer.com%2Fassets%2Fimages%2Ftired-golf-wired-boardgames%2Fboardgames.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcalebmer.com%2Fassets%2Fimages%2Ftired-golf-wired-boardgames%2Fboardgames.jpg" alt="Box art of various boardgames"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If I’m right, and boardgames become a mainstream part of business recreation, then the ability to run a boardgame night and introduce new players to the activity will be pretty valuable.&lt;/p&gt;

&lt;p&gt;In this post I’ll share some of my boardgame recommendations, specifically ones I think would work well in the workplace. I haven’t played all of these…yet. If you’re in the Bay Area and you’re interested in the future of “business recreation” we can give one of these a spin.&lt;/p&gt;

&lt;h3&gt;
  
  
  One Night Ultimate Werewolf
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Time:&lt;/strong&gt; 7 minutes, &lt;strong&gt;Difficulty:&lt;/strong&gt; easy, but can become more challenging as you add roles&lt;/p&gt;

&lt;p&gt;My first, and strongest, recommendation is &lt;a href="https://www.amazon.com/dp/B00HS7GG5G/ref=cm_sw_em_r_mt_dp_U_uNohDb2T9JTWE" rel="noopener noreferrer"&gt;One Night Ultimate Werewolf&lt;/a&gt;. The name is a bit of a mouthful, but all the words actually mean something. I’ll call it “Werewolf” from here on out.&lt;/p&gt;

&lt;p&gt;In Werewolf you have three to eight players and you give everyone a role. Two or so players will get the “werewolf” role and everyone else will be human villagers. The humans have five minutes to correctly identify the werewolves. If the humans discover the werewolves, humans win. Otherwise the werewolves win. So the werewolves must lie and pretend they are villagers to not get caught. The game also gives some human roles “powers” like the power to see the role of one other person or the power to swap two roles. &lt;a href="https://youtu.be/bJ4Hrp8gQ-E" rel="noopener noreferrer"&gt;You can watch some game play here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Werewolf is in the hidden information genre and is actually a very common format for tabletop games. Growing up, I knew this format as “&lt;a href="https://en.wikipedia.org/wiki/Mafia_(party_game)" rel="noopener noreferrer"&gt;Mafia&lt;/a&gt;” which is a game you play with a standard deck of 52 playing cards.&lt;/p&gt;

&lt;p&gt;However, Werewolf makes a couple big changes which streamlines the format and makes it much more fun.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An entire game of Werewolf fits into a single round. Hence why “One Night” is in the title. Normally, in a Mafia-style game you have multiple rounds where players are progressively eliminated. In a one night format players don’t get eliminated so no one has to stop playing!&lt;/li&gt;
&lt;li&gt;Furthermore, you don’t need a game master! Normally, Mafia requires one person to run the game to make sure no one is cheating. Werewolf instead comes with an app which will run the game for you. That way no one has to sit out during play.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These two changes mean everyone in a business recreation setting can play and can keep playing for multiple rounds. A Werewolf round is also really short which allows for quick games.&lt;/p&gt;

&lt;p&gt;Werewolf is a very collaborative game that’s great for team bonding. You really need to know the people around you at the table. To know who your allies are and to know when someone is bluffing. I strongly recommend Werewolf for business recreation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sheriff of Nottingham
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Time:&lt;/strong&gt; 1 hour, &lt;strong&gt;Difficulty:&lt;/strong&gt; medium&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://www.amazon.com/dp/B007EZMABG/ref=cm_sw_em_r_mt_dp_U_OkphDbWQ2YF59" rel="noopener noreferrer"&gt;Sheriff of Nottingham&lt;/a&gt;every player is a merchant trying to stock their shop with goods. One player is also the sheriff which rotates to someone else every round. In a round, players will put some goods into a pouch. For example, three apples. However, players may also smuggle contraband, like beer, into their pouch! Each player gives their pouch to the current sheriff and they declare what’s in the pouch. The sheriff may choose to either believe the player or inspect the player’s pouch. If there is no contraband in the pouch, the sheriff is fined. If there is contraband in the pouch, the player who tried to smuggle is fined. Of course, you can also bribe the sheriff to not inspect your pouch.&lt;/p&gt;

&lt;p&gt;If you’ve every played the game &lt;a href="https://en.wikipedia.org/wiki/Cheat_(game)" rel="noopener noreferrer"&gt;Cheat (aka BS)&lt;/a&gt; with a standard deck of 52 playing cards, then you get the basic idea. You want to smuggle contraband past the sheriff since contraband is valuable, but you also don’t want to get caught.&lt;/p&gt;

&lt;p&gt;It can take a second to understand all the rules. Make sure one person reads the rule book ahead of time if you’re in a group of new players. &lt;a href="https://youtu.be/Gli9C3HtF44" rel="noopener noreferrer"&gt;You can watch some game play here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The physical elements of the game are very engaging. Whether you’re putting cards into a pouch and sliding it over to the sheriff, tossing coins over in a bribe, or popping open the button on a pouch looking for contraband gives an authentic smuggling experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Captain Sonar
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Time:&lt;/strong&gt; 1 hour, &lt;strong&gt;Difficulty:&lt;/strong&gt; medium&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: I haven’t played this game.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://www.amazon.com/dp/B01EZUCHOC/ref=cm_sw_em_r_mt_dp_U_wwphDb18EETTX" rel="noopener noreferrer"&gt;Captain Sonar&lt;/a&gt; you have two teams made of two to four players with each team piloting a submarine. Players have roles like navigator, engineer, and sonar operator to position their submarine against the opponent. The navigator calls out the direction the submarine is moving on a grid. The enemy sonar operator is responsible for listening to the opposing captain to record enemy movements. Once one team believes they have the location of another team they may fire a torpedo.&lt;/p&gt;

&lt;p&gt;So this game is a lot like Battleship except each team only has one submarine and that submarine is piloted by multiple players.&lt;/p&gt;

&lt;p&gt;This game is all about teamwork and communication. With good communication you can strategically manuever your submarine, with bad communication your opponent will know exactly what you’re up to. The game can get hectic with a lot of people talking at once, but that’s also part of the thrill.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dominion
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Time:&lt;/strong&gt; 30 minutes, &lt;strong&gt;Difficulty:&lt;/strong&gt; hard&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.amazon.com/dp/B01LYLIS2U/ref=cm_sw_em_r_mt_dp_U_OcqhDbAG7WN2S" rel="noopener noreferrer"&gt;Dominion&lt;/a&gt; is a deck building game for two to four players. You start with a couple cards and you slowly buy more, building up your deck. Dominion is a lot like Magic the Gathering, in fact, it’s frequently marketed with: “Want to play Magic the Gathering but don’t have the time or money to invest in Magic? Play Dominion instead!” Which is perfect for me. I love deck building games, but the Magic investment always intimidated me.&lt;/p&gt;

&lt;p&gt;Dominion comes with a bunch of different kinds of cards. You play each game with a different set of those cards. That means you can have multiple games of Dominion with &lt;em&gt;wildly&lt;/em&gt; different feels depending on the cards you play with.&lt;/p&gt;

&lt;p&gt;The game is pretty easy to learn, but there’s a lot of depth, complexity, and strategy to the game. Especially when you add in expansions. A player can easily pull ahead of their competitors by employing strategy. This game might be a bit less inclusive than the others because of that. At some point, you need to start thinking strategically or you’ll get left behind.&lt;/p&gt;

&lt;p&gt;In a workplace, I’d recommend playing Dominion in a tournament format since the maximum number of players is four.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tabletop RPGs
&lt;/h2&gt;

&lt;p&gt;Tabletop RPGs are also a compelling category for business recreation. The most popular Tabletop RPG is Dungeons &amp;amp; Dragons, but that’s a massive game which can sprawl over multiple four hour long sessions for years. I think D&amp;amp;D can be great for building teams in a business setting, but you need commitment.&lt;/p&gt;

&lt;p&gt;D&amp;amp;D is not the only Tabletop RPG, though! I recommend watching the &lt;a href="https://youtu.be/YqD_oLkrq_8" rel="noopener noreferrer"&gt;Tablepop series&lt;/a&gt; to get an idea of what shorter form single session Tabletop RPGs look like.&lt;/p&gt;

&lt;p&gt;Here are some of my recommendations beyond D&amp;amp;D. Unfortunately, I don’t have too many recommendations for Tabletop RPGs that play out over a single session. I’d like to hear yours!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.docdroid.net/KJzmn5k/honey-heist-by-grant-howitt.pdf" rel="noopener noreferrer"&gt;Honey Heist&lt;/a&gt;: You’re a bear pulling off a heist to steal honey from Honeycon. This is a fast, fun, one-shot tabletop RPG.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.evilhat.com/home/monster-of-the-week/" rel="noopener noreferrer"&gt;Monster of the Week&lt;/a&gt;: You’re a monster hunter and every week there’s a new threat to fight. Thematically similar to Buffy the Vampire Slayer and other Monster of the Week TV shows. Plays out over multiple sessions.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Vampire:_The_Masquerade" rel="noopener noreferrer"&gt;Vampire: The Masquerade&lt;/a&gt;: Players are vampires struggling against their bestial natures. Plays out over multiple sessions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also think single session Tabletop RPGs could be a fun addition to a tech conference. You get some well known speakers on stage and run a session. If you’re a conference organizer interested in exploring this idea more, let me know.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If I’m right and boardgames become a mainstream business recreation activity, then being able to run a boardgame night and introduce new players could be a valuable skill in a work environment.&lt;/p&gt;

&lt;p&gt;So I’m investing into building this skill. I’ll keep you updated on whether or not it works out for me.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>career</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>My Adventures Writing a Cross-Platform Virtualized List</title>
      <dc:creator>Caleb Meredith</dc:creator>
      <pubDate>Tue, 09 Jul 2019 19:00:00 +0000</pubDate>
      <link>https://dev.to/calebmer/my-adventures-writing-a-cross-platform-virtualized-list-4l90</link>
      <guid>https://dev.to/calebmer/my-adventures-writing-a-cross-platform-virtualized-list-4l90</guid>
      <description>&lt;p&gt;I wrote a virtualized list! It was quite the adventure.&lt;/p&gt;

&lt;p&gt;I was working on a cross-platform React Native app that also rus on the web with &lt;a href="https://github.com/necolas/react-native-web"&gt;React Native Web&lt;/a&gt;. None of the existing virtualized lists were suitable for the product I wanted to build. Not &lt;a href="http://facebook.github.io/react-native/docs/0.59/flatlist"&gt;&lt;code&gt;FlatList&lt;/code&gt;&lt;/a&gt;, not &lt;a href="https://react-window.now.sh"&gt;&lt;code&gt;react-window&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, as one does, I wrote my own virtualized list. Forking React Native in the process. You can see the final code in a &lt;a href="https://gist.github.com/calebmer/2a3bf40baa929115e7f985f876effb6f"&gt;public gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’m going to describe my entire adventure in this post. Through my experience I hope to inspire you to take control of your code. If writing a virtualized list, or anything else, would make your user’s life better, you should do it! You need not be bound to existing libraries. You have the power to fork and modify dependencies as you see fit. Fear not the unfamiliar, if someone out there wrote a virtualized list then there’s no reason you can’t!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/12vJgj7zMN3jPy/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/12vJgj7zMN3jPy/giphy.gif" alt="You can do it GIF"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a story divided into four parts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Part 1: The Product&lt;/li&gt;
&lt;li&gt;Part 2: When I realized existing virtualized lists wouldn’t work…&lt;/li&gt;
&lt;li&gt;Part 3: How it works&lt;/li&gt;
&lt;li&gt;Part 4: Forking React Native&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: The Product
&lt;/h2&gt;

&lt;p&gt;I was building a React Native Web/iOS/Android app which was, basically, a forum. A forum has posts and then people could leave comments on that post.&lt;/p&gt;

&lt;p&gt;If you were reading the post for the first time, you’d want to read the first comments and scroll &lt;em&gt;down&lt;/em&gt;. If you were catching up on the discussion after replying, you’d want to read the latest comments and scroll &lt;em&gt;up&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So I needed a virtualized list that would support scrolling from either direction. I came up with, what I believe, is a new UI pattern: the Skim List! A sister of the Infinite List.&lt;/p&gt;

&lt;p&gt;In a Skim List we pre-allocate space for all the items in the list. When the user scrolls to a position in the list, we load the items at that position. So if I scroll 50% through the list, I’ll load items halfway through the list. If I scroll to the end of the list, I’ll load items at the end of the list.&lt;/p&gt;

&lt;p&gt;Here’s the Skim List in action on web. It works the same way on mobile.&lt;/p&gt;

&lt;p&gt;These GIFs are slowed down and I added network throttling when recording so you can really see the progressive loading behavior. It’s really fast and slick when you get your hands on it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://calebmer.com/assets/images/my-adventures-writing-a-virtualized-list/scroll-down.gif"&gt;&lt;strong&gt;Scrolling from the top to the bottom&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://calebmer.com/assets/images/my-adventures-writing-a-virtualized-list/scroll-up.gif"&gt;&lt;strong&gt;Scrolling from the bottom to the top&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you might be able to imagine, this list also lets you scroll to a random place in the list and move around.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: When I realized existing virtualized lists wouldn’t work…
&lt;/h2&gt;

&lt;p&gt;I first tried using React Native’s &lt;a href="http://facebook.github.io/react-native/docs/0.59/flatlist"&gt;&lt;code&gt;FlatList&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That was working fine, I was able to implement a list where you were able to scroll down and the comments below you loaded. That’s what &lt;code&gt;FlatList&lt;/code&gt; is optimized for. However, I also needed the ability to jump to the end and load comments while scrolling &lt;em&gt;up&lt;/em&gt;! &lt;code&gt;FlatList&lt;/code&gt; just wasn’t built for this.&lt;/p&gt;

&lt;p&gt;Next I explored &lt;a href="http://react-window.now.sh"&gt;&lt;code&gt;react-window&lt;/code&gt;&lt;/a&gt;. At first glance, the library obviously wouldn’t work. You need to know the heights of all your items ahead of time for &lt;code&gt;react-window&lt;/code&gt;. Since I was working with comments on a post, I had know way of knowing the item heights!&lt;/p&gt;

&lt;p&gt;There’s a PR open to &lt;a href="https://github.com/bvaughn/react-window/issues/6"&gt;add a dynamically sized virtualized list for &lt;code&gt;react-window&lt;/code&gt;&lt;/a&gt;, but it hadn’t been merged yet.&lt;/p&gt;

&lt;p&gt;I needed to incrementally load items in the list when they scrolled into view and while the items were loading I needed shimmer placeholders. I couldn’t do this with &lt;code&gt;FlatList&lt;/code&gt; but I could with the unmerged &lt;code&gt;react-window&lt;/code&gt; PR! However, I needed a solution that would also work on React Native iOS and Android. &lt;code&gt;react-window&lt;/code&gt; is web only.&lt;/p&gt;

&lt;p&gt;Well, that meant I needed to write my own virtualized list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3: How it works
&lt;/h2&gt;

&lt;p&gt;The way my virtualized list works is it takes the total number of items (in this case comments) on a post and it takes an array of all the comments. I represent the array as a &lt;em&gt;sparse array&lt;/em&gt;. That means any positions in the array without a loaded comment will be &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;commentCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReadonlyArray&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CommentID&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For all the comments which are not loaded I render a placeholder component called &lt;code&gt;&amp;lt;CommentShimmer&amp;gt;&lt;/code&gt;. A comment shimmer renders grey boxes which are meant to look like a conversation. Different comment shimmers have different heights. I measure the total height of the scroll view with code that roughly looks like &lt;code&gt;commentShimmerHeight * commentCount&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I use a pretty standard virtualized list technique. The same one &lt;code&gt;react-window&lt;/code&gt; uses: absolute positioning. I add a &lt;a href="https://gist.github.com/calebmer/2a3bf40baa929115e7f985f876effb6f#file-postvirtualizedcomments-tsx-L239"&gt;scroll event listener&lt;/a&gt; which calculates the onscreen comments. Then I use &lt;a href="https://gist.github.com/calebmer/2a3bf40baa929115e7f985f876effb6f#file-postvirtualizedcomments-tsx-L772-L773"&gt;absolute positioning&lt;/a&gt; to make sure the comments are rendered at the right position in the virtualized list.&lt;/p&gt;

&lt;p&gt;So whenever a user scrolls I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Figure out which comments to render.&lt;/li&gt;
&lt;li&gt;Render &lt;em&gt;only&lt;/em&gt; those comments, unmounting any offscreen comments.&lt;/li&gt;
&lt;li&gt;Position the rendered comments in the list with absolute positioning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This only works if I know the size of all comments in the list. I know the height of unloaded comments since they are just &lt;code&gt;&amp;lt;CommentShimmer&amp;gt;&lt;/code&gt;s. However, when a comment loads it might have a completely different height!&lt;/p&gt;

&lt;p&gt;When a comment loads I need to measure it. Since I’m using React Native, I must measure asynchronously. So when the comment is loaded but not measured I render the &lt;code&gt;&amp;lt;CommentShimmer&amp;gt;&lt;/code&gt; and the &lt;code&gt;&amp;lt;Comment&amp;gt;&lt;/code&gt; next to each other. Hiding the&lt;code&gt;&amp;lt;Comment&amp;gt;&lt;/code&gt; with &lt;code&gt;opacity: 0&lt;/code&gt;. Once we’ve measured the &lt;code&gt;&amp;lt;Comment&amp;gt;&lt;/code&gt; we can get rid of the &lt;code&gt;&amp;lt;CommentShimmer&amp;gt;&lt;/code&gt; and update the height of the list.&lt;/p&gt;

&lt;p&gt;So there are three states any comment could be in:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// State 1: Unloaded Comment&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CommentShimmer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// State 2: Loaded but Unmeasured Comment&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CommentShimmer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hidden&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onLayout=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleCommentLayout&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Comment&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// State 3: Loaded and Measured Comment&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Comment&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can see this &lt;a href="https://gist.github.com/calebmer/2a3bf40baa929115e7f985f876effb6f#file-postvirtualizedcomments-tsx-L767-L800"&gt;in the &lt;code&gt;renderItem()&lt;/code&gt; function&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 4: Forking React Native
&lt;/h2&gt;

&lt;p&gt;Ok, at this point the list was working and it was working pretty well. However, there were a couple bugs I just couldn’t fix. I didn’t just want a &lt;em&gt;good&lt;/em&gt; experience, I wanted a &lt;em&gt;flawless&lt;/em&gt; experience. This led me to fork React Native so I could add a feature to &lt;code&gt;&amp;lt;ScrollView&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, let me describe the bug.&lt;/p&gt;

&lt;p&gt;When the content of a scroll view resizes, the platform (Web or iOS in this case) needs to determine where the new scroll position should be. Usually, the scroll position is measured as the number of pixels that have been scrolled from the top of the scroll view. So when content resizes, that number is usually kept constant. See the below image for an example.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JPW1ryaV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://calebmer.com/assets/images/my-adventures-writing-a-virtualized-list/pin-window-to-top.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JPW1ryaV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://calebmer.com/assets/images/my-adventures-writing-a-virtualized-list/pin-window-to-top.png" alt="Behavior of a resized scroll view when we pin the scrolled window to top"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We change the size of the scroll content, but the scroll window (the red box) stays the same distance from the top of the scroll view.&lt;/p&gt;

&lt;p&gt;This works well in most cases, but it doesn’t work well when the user is scrolling from bottom to top. That’s because when we load a chunk of comments, the virtualized list size changes. We add content “above” what the user was reading which either pushes or pulls the content the user was reading out of the viewport.&lt;/p&gt;

&lt;p&gt;Instead what we want is to pin the scroll window to the &lt;em&gt;bottom&lt;/em&gt; of the scroll view. So when we add new content the distance of the scroll window to the bottom of the scroll view stays constant. See the below image for an illustration of the difference.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5mWgHe96--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://calebmer.com/assets/images/my-adventures-writing-a-virtualized-list/pin-window-to-bottom.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5mWgHe96--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://calebmer.com/assets/images/my-adventures-writing-a-virtualized-list/pin-window-to-bottom.png" alt="Behavior of a resized scroll view when we pin the scrolled window to bottom"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I forked React Native and added the &lt;code&gt;pinWindowTo&lt;/code&gt; prop. When set to &lt;code&gt;pinWindowTo="top"&lt;/code&gt; we use the default behavior. When set to &lt;code&gt;pinWindowTo="bottom"&lt;/code&gt; it uses the behavior depicted in the previous image.&lt;/p&gt;

&lt;p&gt;This is the important part &lt;a href="https://github.com/calebmer/react-native/commit/8874509405acda979d61504c53cfad4545cae458"&gt;of the commit&lt;/a&gt; in the Objective-C code for the &lt;code&gt;ScrollView&lt;/code&gt; component on iOS.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;       // offset falls outside of bounds, scroll back to end of list
       newOffset.y = MAX(0, newContentSize.height - viewportSize.height);
     }
   }

+  if (![self.pinWindowTo isEqualToString:@"bottom"]) {
&lt;span class="gi"&gt;+    CGFloat oldOffsetBottom = oldContentSize.height - (oldOffset.y + viewportSize.height);
+    newOffset.y = newContentSize.height - viewportSize.height - oldOffsetBottom;
+  }
&lt;/span&gt;
   BOOL fitsinViewportX = oldContentSize.width &amp;lt;= viewportSize.width &amp;amp;&amp;amp; newContentSize.width &amp;lt;= viewportSize.width;
   if (newContentSize.width &amp;lt; oldContentSize.width &amp;amp;&amp;amp; !fitsinViewportX) {
     CGFloat offsetHeight = oldOffset.x + viewportSize.width;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I don’t currently have an Android implementation which is why I haven’t contributed this back to React Native. In the meantime, this works great for me!&lt;/p&gt;

&lt;p&gt;I also implemented this feature on my &lt;a href="https://github.com/calebmer/react-native-web/commits/master"&gt;React Native Web fork&lt;/a&gt;.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;_pinWindowToBottom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getScrollableNode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastScrollTop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_lastScrollTop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastScrollHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_lastScrollHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_lastScrollHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrollHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastClientHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_lastClientHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_lastClientHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastScrollBottom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastScrollHeight&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastScrollTop&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;lastClientHeight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextScrollTop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrollHeight&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientHeight&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;lastScrollBottom&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrollTop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nextScrollTop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_lastScrollTop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nextScrollTop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Other changes I’ve made in my &lt;a href="https://github.com/calebmer/react-native/commits/0.59-stable"&gt;React Native fork&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fixed &lt;a href="https://github.com/facebook/react/issues/15732"&gt;React bug&lt;/a&gt; until React and React Native publish a new version.&lt;/li&gt;
&lt;li&gt;Send &lt;a href="https://developer.apple.com/documentation/uikit/uiscrollview/2902259-adjustedcontentinset?language=objc"&gt;iOS &lt;code&gt;adjustedContentInset&lt;/code&gt;&lt;/a&gt; in scroll events since it’s important for accurate measurements involving “unsafe areas” on iPhone X.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other changes I‘ve made in my &lt;a href="https://github.com/calebmer/react-native-web/commits/master"&gt;React Native Web&lt;/a&gt; fork:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fire &lt;code&gt;onLayout&lt;/code&gt; in a microtask instead of &lt;code&gt;setTimeout()&lt;/code&gt; so it fires before the next browser paint. This is very important for my virtualized list double rendering strategy!&lt;/li&gt;
&lt;li&gt;Remove unsafe life-cycle methods like &lt;code&gt;componentWillReceiveProps&lt;/code&gt; so that I can enable React Concurrent mode in my app.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  In defense of forking
&lt;/h3&gt;

&lt;p&gt;Forking your dependencies is frequently maligned, and for good reason. Without adequate upkeep your forks will fall behind the latest version of your dependencies. You’ll miss out on critical bug fixes and security patches!&lt;/p&gt;

&lt;p&gt;When I fork I’m very careful to make sure there’s a clear upgrade path in the future.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I only make small changes. The change should only touch a few files and should be very well documented.&lt;/li&gt;
&lt;li&gt;I only make changes which I’d reasonably expect to get merged upstream some day. That way there’s a path to getting off the fork.&lt;/li&gt;
&lt;li&gt;I’ll only make changes I wouldn’t expect to get merged on projects that aren’t actively maintained.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once I’m comfortable that the change won’t make upgrading too hard in the future, I fork. Then I have criteria for proposing my forked changes upstream.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the change tested?&lt;/li&gt;
&lt;li&gt;Is the change documented?&lt;/li&gt;
&lt;li&gt;Can I show the change working in a production app?&lt;/li&gt;
&lt;li&gt;Can I justify the change to contributors?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a lot of work and slows down shipping. To me, it‘s more valuable to live on a fork for a few months and fix bugs for users &lt;em&gt;immediately&lt;/em&gt; than to make users wait a few months for a proper open source release with the change.&lt;/p&gt;

&lt;p&gt;The best part of open source is that it’s, well, open. You have the power to modify your dependencies. It’s a dangerous power, but if you use it wisely you can ship brilliant user experiences no one else is capable of.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As developers, we have so many tools to ship brilliant user experiences. Don’t be afraid to think out of the box when you encounter a particularly sticky problem. For me, writing my own virtualized list was the best way to build the experience I wanted.&lt;/p&gt;

&lt;p&gt;Also don’t be afraid of forking your dependencies. Yes it’s dangerous, yes it will make your life harder if you’re not careful, but it’s also an incredibly powerful tool. Recognize the risks and use it where appropriate.&lt;/p&gt;

&lt;p&gt;I put the code for my &lt;a href="https://gist.github.com/calebmer/2a3bf40baa929115e7f985f876effb6f"&gt;virtualized list in a gist&lt;/a&gt;. I don’t currently plan to turn it into a reusable open source component. That wasn’t my goal. Shipping a unique experience for my users was my goal.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Writing Good Compiler Error Messages</title>
      <dc:creator>Caleb Meredith</dc:creator>
      <pubDate>Mon, 01 Jul 2019 19:00:00 +0000</pubDate>
      <link>https://dev.to/calebmer/writing-good-compiler-error-messages-khc</link>
      <guid>https://dev.to/calebmer/writing-good-compiler-error-messages-khc</guid>
      <description>&lt;p&gt;It’s never fun when you see an error message while trying to ship some code. It means you’re one step further from working software! It doesn’t help that a lot of error messages are completely inscrutable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcalebmer.com%2Fassets%2Fimages%2Fwriting-good-compiler-error-messages%2Ftypescript-error.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcalebmer.com%2Fassets%2Fimages%2Fwriting-good-compiler-error-messages%2Ftypescript-error.png" alt="A scary TypeScript error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After spending a lot of time &lt;a href="https://medium.com/flow-type/better-flow-error-messages-for-the-javascript-ecosystem-73b6da948ae2" rel="noopener noreferrer"&gt;redesigning Flow’s error messages&lt;/a&gt; I’ve developed a personal style guide for writing helpful compiler error messages. Before jumping into the style guide, I’ll share my philosophy around error messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Philosophy
&lt;/h2&gt;

&lt;p&gt;Roughly, you can sort a developer’s reaction to an error message into two&lt;br&gt;
categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;80%&lt;/strong&gt; of the time, the developer will immediately know what the fix is. The error will be related to code they’re actively working on. The developer may even know how to fix it &lt;em&gt;just&lt;/em&gt; by seeing where the red squiggly in their IDE is. No need to read the error message.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;20%&lt;/strong&gt; of the time, the developer won’t immediately know why the compiler says their code is incorrect. The compiler might have a complex rule that’s non-intuitive but important to the safety of the program. In this case, an error message should provide enough information to enable the developer to take a deep dive into their program.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;strong&gt;80%&lt;/strong&gt; case a developer is either quickly iterating through their code and a long error message would be a &lt;em&gt;disservice&lt;/em&gt; to their productivity. They only need a glance at the message to know what to fix.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;20%&lt;/strong&gt; case it will be really difficult to pack enough context into a single error message to explain the problem. The error message’s fix might be somewhere far away from the reported location since the compiler can’t determine a human’s intent. The error might be caused by a really nuanced rule that can’t easily be explained in an error message format.&lt;/p&gt;

&lt;p&gt;A great example of a rough error messages in the 20% case is anything reported by the Rust borrow checker or the Elm infinite type error message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I am inferring a weird self-referential type for x:

11| f x = x x
      ^
Here is my best effort at writing down the type. You will see ∞ for parts of
the type that repeat something already printed out infinitely.

    ∞ -&amp;gt; a

Staring at this type is usually not so helpful, so I recommend reading the
hints at &amp;lt;https://elm-lang.org/0.19.0/infinite-type&amp;gt; to get unstuck!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Elm even acknowledges that “staring at this…is usually not helpful”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;It’s also important to understand the context of &lt;em&gt;where&lt;/em&gt; the developer will see an error message. For a programming language, ideally you have good editor integration so the user is going to see your error message in an editor like VSCode.&lt;/p&gt;

&lt;p&gt;The IDE context favors short error messages that are one to two sentences long. When you hover over an error the popup doesn’t give you much space!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcalebmer.com%2Fassets%2Fimages%2Fwriting-good-compiler-error-messages%2Ferror-popup.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcalebmer.com%2Fassets%2Fimages%2Fwriting-good-compiler-error-messages%2Ferror-popup.png" alt="VSCode Error Popup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many IDEs, like VSCode, also have some kind of panel where they show you all the error messages at once. The design of this space is also best suited to short one to two sentence long error messages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcalebmer.com%2Fassets%2Fimages%2Fwriting-good-compiler-error-messages%2Fproblems-pane.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcalebmer.com%2Fassets%2Fimages%2Fwriting-good-compiler-error-messages%2Fproblems-pane.png" alt="VSCode Problems Pane"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thinking about the context where an error message is displayed influences my style guide &lt;em&gt;a lot&lt;/em&gt;. Usually, most compiler developers are designing their error messages in the command line (CLI). Which is why you get colored multiline messages that print out code.&lt;/p&gt;

&lt;p&gt;I design error messages &lt;em&gt;IDE first&lt;/em&gt;, not &lt;em&gt;CLI first&lt;/em&gt;. Like the way you’d design a website to be mobile first. The IDE is much more constrained than the CLI. If you design a good IDE message you can easily adapt it to the CLI. It’s much harder to adapt a message designed for the CLI to an IDE since you didn’t think of an IDE’s constraints when designing your message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Style Guide
&lt;/h2&gt;

&lt;p&gt;Now that you know my philosophy and the context I design for, let’s get into my error message style guide!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Keep error messages short. Preferably a single, clear, sentence. This format works best in an IDE context.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The error location is so important since that’s where the red squiggly goes in an IDE. Pick the smallest possible location at the operation which triggered the error. If the user is writing a new operation the error will point to where they are working. If the user is refactoring the error will point to all the operations which need to change.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t print out information a developer could easily find in their code. Instead print a reference to that information which is linked in an IDE. TypeScript likes to print out huge types in error messages, this makes it hard to read the message.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use correct English grammar. This is probably obvious, but it can be hard to make a program which produces correct English grammar. It’s easy to stitch together arbitrary sentence fragments. Put some rules on the grammatical structure of your sentence fragments. It’s also worth going the extra mile to add grammatical decoration like articles: “a &lt;code&gt;String&lt;/code&gt; is not an &lt;code&gt;Int&lt;/code&gt;” vs “&lt;code&gt;String&lt;/code&gt; is not &lt;code&gt;Int&lt;/code&gt;”. Just be careful when using developer-defined names.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write messages in first person plural. That is, use “we”. For example “we see an error”. This personifies the compiler as a &lt;em&gt;team&lt;/em&gt; of people looking for bugs in the developer’s code. By personifying our type checker error messages feel like a dialogue. Elm’s error messages are famous for using first person: “I see an error”. First person feels a bit uncomfortable to me. A compiler is certainly not a single person, nor is it built by a single person. I prefer “we” as a compromise.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use present tense instead of past tense. Instead of “we found” say “we see”. When an error is displayed to a user, the code is currently in a bad state. From the compiler author’s perspective, the compiler runs at discrete points in time and “finds” errors at those points. From the developer’s perspective an error in their IDE reflects the current state of the program, not a discrete compiler run. Prefer the developer’s IDE context, use present tense.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reduce the grade reading level as much as possible. I use the &lt;a href="http://www.hemingwayapp.com/" rel="noopener noreferrer"&gt;Hemingway Editor&lt;/a&gt; for this. I’ll paste in an error message and the editor tells me the grade reading level (for example, 6th grade). I then try to reduce the grade level as much as possible without sacrificing clarity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use language the developer will understand, not compiler-speak. Words like “identifier”, “token”, and “expression” are compiler-speak. Prefer the names a developer would use in conversation with their peers. Also consider the context of your error message. If you expect a variable name, say that instead of saying “expected identifier”.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use Markdown for formatting error messages. If you want to include a code snippet put it between backticks (`) which are used in Markdown to indicate inline code. The code editor should format your message appropriately.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you use quotes, make sure they are the proper curly quote characters. For example: “phrase” instead of "phrase". See the difference? It’s subtle. I’ve gotten into the habit of typing these characters after taking a typography course. &lt;a href="https://graphemica.com/%E2%80%9C" rel="noopener noreferrer"&gt;U+201C (“)&lt;/a&gt;, &lt;a href="https://graphemica.com/%E2%80%9D" rel="noopener noreferrer"&gt;U+201D (”)&lt;/a&gt;, &lt;a href="https://graphemica.com/%E2%80%98" rel="noopener noreferrer"&gt;U+2018 (‘)&lt;/a&gt;, and &lt;a href="https://graphemica.com/%E2%80%99" rel="noopener noreferrer"&gt;U+2019 (’)&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Following this guide will produce error messages with a consistent tone, voice, and style.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Short, simple, and clear error messages are &lt;em&gt;much&lt;/em&gt; better than long and detailed error messages. They fit the developer’s IDE context better and they don’t distract the developer when they are trying to debug a particularly unintuitive error.&lt;/p&gt;

&lt;p&gt;Good error messages will make developers more efficient. They’ll spend less time staring at error message text and more time building products their users will love.&lt;/p&gt;

&lt;h2&gt;
  
  
  IDE Wishlist
&lt;/h2&gt;

&lt;p&gt;There are two features I want from the IDEs rendering my error messages written with my style guide. Specifically, I want these features in the&lt;br&gt;
&lt;a href="https://microsoft.github.io/language-server-protocol/specification" rel="noopener noreferrer"&gt;Language Server Protocol (LSP) Specification&lt;/a&gt; which is supported by VSCode, Atom, and other code editors.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I want my error messages to be rendered with markdown. Currently, at least in VSCode, error messages are rendered with a monospace font. My messages are designed to be proper English sentences with inline code snippets, not code.&lt;/li&gt;
&lt;li&gt;I want to link to code in error messages. Often, I’ll have an error that reads “&lt;code&gt;Foo&lt;/code&gt; is not &lt;code&gt;Bar&lt;/code&gt;”. I want “&lt;code&gt;Foo&lt;/code&gt;” to be a hyperlink to where the compiler found the &lt;code&gt;Foo&lt;/code&gt; type! Same for &lt;code&gt;Bar&lt;/code&gt;. I can hack around this with the &lt;a href="https://microsoft.github.io/language-server-protocol/specification#diagnostic" rel="noopener noreferrer"&gt;LSP’s &lt;code&gt;relatedInformation&lt;/code&gt; field&lt;/a&gt; but it’s not the same as being able to write a hyperlink inline.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;My announcement for &lt;a href="https://medium.com/flow-type/better-flow-error-messages-for-the-javascript-ecosystem-73b6da948ae2" rel="noopener noreferrer"&gt;Flow’s error message redesign&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Elm’s &lt;a href="https://elm-lang.org/blog/compiler-errors-for-humans" rel="noopener noreferrer"&gt;compiler errors for humans&lt;/a&gt; post.&lt;/li&gt;
&lt;li&gt;Reason has also given a &lt;a href="https://reasonml.github.io/blog/2017/08/25/way-nicer-error-messages.html" rel="noopener noreferrer"&gt;lot of thought&lt;/a&gt; towards their error messages.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Taking Control of Compilation</title>
      <dc:creator>Caleb Meredith</dc:creator>
      <pubDate>Tue, 18 Jun 2019 03:00:00 +0000</pubDate>
      <link>https://dev.to/calebmer/taking-control-of-compilation-5866</link>
      <guid>https://dev.to/calebmer/taking-control-of-compilation-5866</guid>
      <description>&lt;p&gt;The more work we can do at compile time, the better! That’s less work our code has to do at runtime, but it’s not easy to move work to compile time. In this post I propose a new way of executing code, focused on JavaScript applications, that makes &lt;em&gt;moving work to compile time as simple as moving a variable to global scope&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let’s first think about our code’s compilation and execution in two phases, &lt;strong&gt;buildtime&lt;/strong&gt; and &lt;strong&gt;runtime&lt;/strong&gt; respectively.&lt;/p&gt;

&lt;p&gt;Buildtime code executes on the developer’s machine before they deploy their application. Runtime code executes on a user’s machine when they run the application.&lt;/p&gt;

&lt;p&gt;Buildtime tasks include Webpack bundling many JavaScript files into one big file or Babel compiling ES6 features down to ES5. &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt; does a lot of work at buildtime to create a fast application at runtime.&lt;/p&gt;

&lt;p&gt;When we developers write JavaScript, or other product languages like Swift and Kotlin, we expect that all our code will be executed at runtime. If we want to execute something at buildtime we write a script or a compiler plugin.&lt;/p&gt;

&lt;p&gt;There are a lot of tasks in product development which would make sense to run at buildtime, but we often run these tasks at runtime instead since it’s convenient. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parsing &lt;a href="https://github.com/apollographql/graphql-tag"&gt;Apollo GraphQL&lt;/a&gt;queries.&lt;/li&gt;
&lt;li&gt;Parsing &lt;a href="https://www.styled-components.com/"&gt;Styled Components&lt;/a&gt; CSS.&lt;/li&gt;
&lt;li&gt;Choosing a translation based on the locale.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also a lot of tasks which we do run at buildtime but require lots of configuration &lt;em&gt;outside&lt;/em&gt; of our source code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bundle splitting.&lt;/li&gt;
&lt;li&gt;Optimizing image formats like SVG.&lt;/li&gt;
&lt;li&gt;Extracting CSS to a static file.&lt;/li&gt;
&lt;li&gt;Generating HTML files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We have many opportunities to optimize our applications at buildtime. However, we miss a lot of those opportunities because configuring Webpack or Babel or_insert buildtime tool here_ is hard.&lt;/p&gt;

&lt;p&gt;We also have very few ways to innovate when it to buildtime work. There’s&lt;a href="https://svelte.dev"&gt;Svelte&lt;/a&gt; which had to build its own compiler to innovate at buildtime. There’s&lt;a href="https://github.com/kentcdodds/babel-plugin-macros"&gt;&lt;code&gt;babel-plugin-macros&lt;/code&gt;&lt;/a&gt; which requires macro authors to write a Babel AST transform where it’s easy to miss corner cases.&lt;/p&gt;

&lt;p&gt;Today, I will propose a vision for a new way to execute programs that makes writing buildtime code &lt;em&gt;free&lt;/em&gt;. No Webpack plugins. No Babel transforms. No custom compilers.&lt;/p&gt;

&lt;p&gt;By making buildtime code dead simple to write, we can empower every developer to make the next big compiler optimization for our products.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vision: Modules execute at Buildtime, not Runtime
&lt;/h2&gt;

&lt;p&gt;Today a JavaScript module that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./utils/fibonacci&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 144&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Will print “144” to the console of every end user of the application. This module executes at &lt;em&gt;runtime&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Instead, let’s execute it at buildtime and add a hook for executing code at runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./utils/fibonacci&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createBundle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-bundle.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We now execute this module at buildtime. We compute &lt;code&gt;fibonacci(12)&lt;/code&gt; once on the developer’s machine instead of thousands of times on the machines of their users.&lt;/p&gt;

&lt;p&gt;Then, we call &lt;code&gt;Build.createBundle()&lt;/code&gt; which creates a new JS bundle named&lt;code&gt;my-bundle.js&lt;/code&gt;. Just like adding a new entry to your Webpack config. After running this code at buildtime you’ll get a bundle that looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;144&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We don’t have to include our &lt;code&gt;fibonacci()&lt;/code&gt; function in the bundle and we can directly inline the constant result of calling &lt;code&gt;fibonacci(12)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s consider a more advanced example, translations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;TranslationContext&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./TranslationContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localeNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;importDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./translations/locales&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localeName&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;localeNames&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;importFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`./translations/locales/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;localeName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.json`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createBundle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`app.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;localeName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.js`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TranslationContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;TranslationContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let’s say you have a directory &lt;code&gt;./translations/locales&lt;/code&gt; with three files that include translations for your app: &lt;code&gt;en-US.json&lt;/code&gt;, &lt;code&gt;es-MX.json&lt;/code&gt;, and &lt;code&gt;zh-CN.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this example, we declare that our app depends on all the files in our translations directory using &lt;code&gt;Build.importDirectory()&lt;/code&gt; and &lt;code&gt;Build.importFile()&lt;/code&gt;. A good buildtime framework can also then watch these JSON files and rebuild the bundles when they change.&lt;/p&gt;

&lt;p&gt;We then create a new bundle for every locale where we render a React app! Since the arrow function captures the &lt;code&gt;locale&lt;/code&gt; JSON data, that data will be included in the final bundle. Along with any other constant data we capture.&lt;/p&gt;

&lt;p&gt;If you have a page that doesn’t require any data from the user, you may also compile it statically at buildtime. Like &lt;a href="https://www.gatsbyjs.org/"&gt;Gatsby&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;It‘s not just our top level application files that run at buildtime. &lt;em&gt;Every one of our files would run at buildtime.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;TodoItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`
  fragment todo on TodoItem {
    id
    name
    completed
    # ...
  }
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="s2"&gt;`
  .item {
    border: solid 2px red;
  }
  /* ... */
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this example, we have two variables in our module scope: &lt;code&gt;query&lt;/code&gt; and&lt;code&gt;styles&lt;/code&gt;. Both of these variables would be computed at buildtime! We’d parse the corresponding GraphQL and CSS, run any transformations, and output JSON objects to the resulting bundle.&lt;/p&gt;

&lt;p&gt;The only difference is we’d do it at buildtime instead of runtime.&lt;/p&gt;

&lt;p&gt;To use a React component defined like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;TodoItem&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./TodoItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Nope! We don’t render in the module scope.&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// ❌ React.render(todos.map(todo =&amp;gt; &amp;lt;TodoItem todo={todo} /&amp;gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Instead we render in a bundle we create at buildtime.&lt;/span&gt;
&lt;span class="nx"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createBundle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TodoItem&lt;/span&gt; &lt;span class="na"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Interested?
&lt;/h2&gt;

&lt;p&gt;Does this model of execution interest you? Let me know! Twitter:&lt;a href="https://twitter.com/calebmer"&gt;@calebmer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There’s a lot to figure out to make this work in JavaScript. I imagine we could create an AST transform that adds an environment record of the variables captured a function. So the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createBundle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-bundle.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Would be transformed by wrapping all functions in some &lt;code&gt;addCapturedVariables()&lt;/code&gt;function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createBundle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-bundle.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;addCapturedVariables&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That way buildtime code could serialize captured variables out to a runtime bundle.&lt;/p&gt;

&lt;p&gt;Making this process fast is another question entirely. There are likely ways to intelligently determine if buildtime or runtime code was changed. If only runtime code changed, then you don’t need to re-run your buildtime logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/facebook/prepack"&gt;Prepack&lt;/a&gt; kinda does something like this. The big difference is that Prepack tries to optimize code you already have with a custom JavaScript engine. This proposal would reuse existing JavaScript engines and add functions for exploiting the power of buildtime evaluation like &lt;code&gt;Build.createBundle()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The idea of compile-time function execution already exists in Lisp macros, in C++ as &lt;a href="https://en.cppreference.com/w/cpp/language/constexpr"&gt;&lt;code&gt;constexpr&lt;/code&gt;&lt;/a&gt;, and in Rust as&lt;a href="https://doc.rust-lang.org/unstable-book/language-features/const-fn.html"&gt;&lt;code&gt;const fn&lt;/code&gt;&lt;/a&gt;. These systems allow you to execute pure functions with static inputs, but nothing I’ve seen has the ability to customize your build like&lt;code&gt;Build.createBundle()&lt;/code&gt; would.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://anydsl.github.io/"&gt;AnyDSL&lt;/a&gt; is a cool project that does deep partial evaluation like Prepack. It comes with a new programming language and an interesting graph-based CPS intermediate representation called&lt;a href="https://anydsl.github.io/Thorin.html"&gt;Thorin&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
