Jonathan Snook's Blog, page 9

May 18, 2020

Overlapping Header with CSS Grid

I have this design.



Green header with rounded body overlapping the header

Historically, I’ve done this with negative margins. The header has a height that adds a bunch of padding to the bottom and then the body gets a margin-top: -50px or whatever the design calls for.



Since I knew I was going to be using Grid for the shell of this page, I wondered if there was an easy way to do this.



I set up the page using three columns and four rows. The centre column is where the header, body, and footer reside. The left and right columns are the gutter, which—based on this particular design—I want to collapse on small screens.



The header goes in the first row and the footer in the last. (Firefox has a great Grid visualizer, by the way.)



The design with Firefox’s grid lines on

My first instinct to getting this to work was to have the header span rows 1 and 2 and have the body span 2 and 3. The problem here is that the header content won’t push the body down if things need to reflow in the header.



You can mitigate this by adding enough padding to the header equal to the height of the overlapping row.



grid-template-rows: auto 8em 1fr auto;

.shell-header {
padding-bottom: 8em;
}


Now, that’ll definitely work just fine. However, because I had collapsing margins for this design, I wanted the padding for the header to line up with the body. I can use media queries to adjust the padding for small and large screens (as well as the media queries for collapsing the margins).



I decided to take a different approach that let me leave the padding alone. I added an element for the background colour and stretched that over the first two rows:



/* overlap */
.shell:before {
content: "";
grid-column: 1/-1;
grid-row: 1/3;
background-color: #063;
}


Because I’m using :before, it should automatically be behind everything else. If I used :after, it’d be on top and I’d have to use z-index to get it back behind everything else.



Just like that, I have an overlapping header. Check it out on CodePen.

 •  0 comments  •  flag
Share on Twitter
Published on May 18, 2020 06:37

May 5, 2020

Fancy Zoom Calls

AKA, how I set up my Sony DSLR to use as a webcam.



Unless you’ve only just woken from a months’ long coma and the first thing you decided to do was read my blog, you’re likely aware of (waves arms around) this quarantine. I’ve been home and isolated for two months now. Fun times.



As a result, I’m in a lot of Zoom calls. As a result, I’m envious of the few people with their fancy camera and mic setups. As a result, I decided to do something about it.




The lowly Mac camera
The lowly Mac camera


First, here are a list of articles of what other people have done to get this going:



Dan Mall’s setup
Jesse Gardner’s setup
Matt Stauffer’s setup

Read them? If so, you may notice as I did that every single one of them use the Elgato Camlink. It’s a hardware dongle that allows you to plug in your camera via HDMI and it’ll be recognized as a webcam.



Cool cool cool cool. Here’s the thing: everybody and their grandmother have clearly read the same articles and ordered themselves the Elgato Camlink. As such, they are sold out everywhere. If you’re in the United States, it seems some people have still been able to get their hands on them. Up here in America’s Hat (i.e. Canada), I couldn’t find them anywhere.



I had pretty much resigned myself to living with the Mac’s FaceTime camera. Is that so bad?



Well, then I came across a YouTube video that perfectly describes how to setup a Sony DSLR as a webcam using a piece of free software called CamTwist.



Awesome!




The amazing Sony camera
The amazing Sony camera


Well, kinda sorta. It’s a clunky setup that requires me to fire up my camera, then fire up Remote, then fire up CamTwist, then fire up the remote streaming tool of choice.



Except, when I opened up Zoom, it wasn’t recognizing the CamTwist webcam. (Skype seemed to work fine but everybody is using Zoom these days.) Everything I was finding on the web was telling me to downgrade to a previous version of Zoom to allow this to work.



Turns out, as Zoom tried to fix a bunch of security issues, they decided to lock out any unsigned webcams. (This is explained in this Reddit thread.) CamTwist is 10 year old software and isn’t signed. As such, it doesn’t get recognized. To solve this problem, you need unsign Zoom so that it’ll allow unsigned webcams. This feels icky but it worked and since we’re dealing with a global pandemic at the moment, unsigning an app seems like the least of my worries.



Per the instructions in the Reddit thread, you’ll need to have Xcode installed and then you’ll be able to run this line of code:



codesign --remove-signature /Applications/zoom.us.app/


Just like that, you’re in business.



Now, like I said, it’s not ideal. You can’t minimize the Remote app or the webcam doesn’t work. You can’t use Spaces or the webcam doesn’t work. You don’t want to resize the Remote app or CamTwist will show the wrong thing. Remote resets its height and width every time its opened, so best not to mess with it at all.



On the upside, CamTwist is studio software, so you can play with effects and text overlays and even cut between multiple video feeds, if you’re feeling overly ambitious.



So, while not perfect, it’ll do.

 •  0 comments  •  flag
Share on Twitter
Published on May 05, 2020 16:18

May 4, 2020

A .Button is a Button is a Link

You’re working on a project and in it you see a button. It looks like a button, it acts like a button. It is a button. It is a <button>. It is a .button.



But is every <button> a .button? Is every .button a <button>?



Let’s take a look at some very specific examples:




An square with next and previous buttons next to it and with a cancel link and a save button underneath


We essentially have three different types of buttons:




Image-only buttons (the next/previous paddles)
Text-only buttons (the cancel link)
Like, actual buttons


On most projects, I see developers choose to identify all of these as the same component: the .button.



As a result of trying to shoehorn everything under the umbrella of a single component, we run into a lot of style overrides. The default style is the actual button. And then text buttons need to strip away all those styles. And image buttons have other constraints like handling hover and active states of the images.




.button--image
.button--link
.button


Different Patterns, Different Components

Just because the HTML under the hood is the same, doesn’t mean we need to use the same class for everything. Since we have three different types of buttons, we should identify them as such.




.image-button
.link-button
.button


Or whatever name you want to come up with. (Naming things is hard.)



With each clearly defined, there is no need to override styles to add or takeaway styles applied by other button styles. This simplicity results in less complexity and possibly even less code by not having to override existing styles.

 •  0 comments  •  flag
Share on Twitter
Published on May 04, 2020 18:54

April 28, 2020

Kjolle

It’s April 2019. We’re in Lima, continuing the journey of going to the world’s 50 best restaurants. There are 3 restaurants on the list here in Lima: Astrid & Gaston, Maido, and Central.



It looked like there was availability for all three restaurants and so we booked flights and hotel and then went to reserve the restaurants.



A&G was fine. Maido was great. Central, however, turned out to be full. Turns out, the reservation site for Central shows availability for all of their restaurants and not just Central.



Well, that’s unfortunate. With everything else booked, I added my name to the waiting list. Worst case, we’ll arrive at the restaurant in hopes of any last minute cancellations.



Nothing opened up.



With an evening free, we make the 45 minute walk over enjoying the quiet evening through one neighbourhood to the next until we arrive in Barranco, just as Central is set to open, pleading for a table. No luck. But they had availability at Kjolle. We could have a drink at the bar, Mayo, while we wait for our table.



Fine.



Mayo

As we sat at the bar waiting, they prepared us a drink. The cocktail looked elaborate with a dash of spice on the top placed with precision. It was presented with a platter of inspiration, where we could see the spices used in the drink. The presentation was amazing.



The drinks take some time to prepare—I think we waited for about 15 minutes. I wondered what that place would be like on a busy evening with 100 people all waiting for their drinks.



Dinner

We hadn’t quite finished our drinks when we were escorted to our table on the second floor of the compound. And compound is probably the best way to describe the three restaurants and training facilities surrounded by a high wall. Kjolle, itself, is divided into two sections separated by a glass wall. We’re sat at a table at the back, in a room with a half-dozen tables.




The Menu
The Menu


Stunningly, as the place filled, it didn’t get louder. In fact, by the end of dinner, we noticed we couldn’t overhear a single conversation from any other table. The noise management was superb (and most welcome)!



I don’t think I’ve ever been emotionally moved by a plate of potatoes before. The tubers tart was divine. The potato flavour wasn’t too strong. It wasn’t too sweet. It was a perfect combination of taste and texture.




Tubers Tart
Tubers Tart


The bread was delicious. The crust was flavourful and tasty with the whipped butter and salsa served with it.



The last two wine pairings were fantastic.



There wasn’t a disappointing dish the whole way through, along with some exceptional ones.



I walked away with a mix of emotions. Happy to have enjoyed such a wonderful meal, sad that we weren’t able to go to Central, curious about how good Central would be, and excited to plan a return to Lima.



If you find yourself in Peru, come to Lima, and enjoy some of the world’s most amazing food at Kjolle.





 •  0 comments  •  flag
Share on Twitter
Published on April 28, 2020 05:57

February 5, 2020

Playing with CSS Grid

I’ve been working on this site, Fifty, to track a list of restaurants that I’ve been to. Each new restaurant was a list item. The list will eventually reach 50 items and a long list is long and visually uninteresting.



The first attempt was to use CSS columns. I threw on a column-width and bam. Slightly more visually interesting—at least, on larger screens. It’s still just an ordered list on smaller screens.







Lately, I’ve been wanting to play with layout that had more of a magazine feel. (I’ve also been wanting to do an actual magazine but that’s a story for another day.) I even picked up a stack of magazines from the local bookstore to get some inspiration and ideas.



One thing that I noticed is that they’ll play with grids to create visual interest or to move your eye through a more dense page.



Magazines have the advantage of a fixed size. For the web, we need to consider everything from watches to wide screens. CSS Grid seemed like a great way to play around with different options.



Repeat

Grid’s repeat function is one of my favourite tools. It’s like a built-in responsive design tool that instantly creates a flexible design. I tell it the minimum column size and then it will create the number of columns that’ll fit into the space allotted.



grid-template-columns: repeat(auto-fill, minmax(250px, 1fr))



This, in and of itself, isn’t much over what I had before. I beefed up the style with some numbers in boxes.







Spanning Columns and Rows

To make things more interesting, I wanted to have items pop out, both in size and colour. If everything popped out, it would be overwhelming and I didn’t think it’d make the list any easier to parse.



I decided to create a pattern that would work when I had a few items and would continue to work as I completed restaurants on the adventure.



The first idea I had to make certain items stand out was to have some restaurants take up two columns and two rows and include a photo.







I specified the row and column span:



grid-row: span 2;
grid-column: span 2;


A problem reared its ugly head when the page scaled down to a single column. Why is this a problem? By spanning an item over 2 columns, there will always be 2 columns, even if I only want 1.



I’d love a way to say: grid-column: span minmax(1,2). It’d take two columns if there’s two columns; otherwise, it only takes one column.



Instead, I had to define a media query for when there was a single column and adjust the spans for that.



@media (max-width: 674px) {
.restaurants li {
grid-column: span 1 !important;
}
}


(I probably should’ve done this mobile first and defined the default as span 1 and then did a min-width for anything that wasn’t mobile. But it’s a personal site and whatevs.)



I played around with what would create the best look at all viewports and with various items. I wish I could say I had a magical formula but it was really just trial and error. I’d put something together and then resize to see how it’d look. Then play around with the numbers until I had something I liked.







The next problem was to make it looks semi-random. Or provided some alternation with where the spanned items would be placed. If I just use :nth-child then weird patterns can emerge at different viewport widths.



To solve this problem, I’d use multiple :nth-child declarations with alternating offsets. This provided the best results over all viewports.



Random colours

I was okay with that but I wanted more. I decided to use the alternate colours, green and brown, on random boxes. CSS doesn’t have a random function, which would’ve been really handy here. Instead, I tried to figure out what offset would create a pleasing pattern. Again, this was a lot of trial and error figuring out offsets that worked well.



.restaurants-devoured li:nth-child(17n-16):before { … }
.restaurants-devoured li:nth-child(11n+12):before { … }


And again, I used a similar solution to how I placed the large boxes. Offsetting numbers with multiple patterns helps create the illusion of randomness.



The Result

I’m really happy with the way the grid turned out. Probably the biggest problem is that people look for meaning in patterns. “Why are these restaurants a different size or colour? Are these the ones you like best or stood out to you for some reason?” The answer is no, there’s no significance. I thought it would look nice. Unsure how I’d tweak the design to make the insignificance more obvious.



I look forward to going to more restaurants and seeing the grid continue to fill in.




 •  0 comments  •  flag
Share on Twitter
Published on February 05, 2020 19:28

January 14, 2020

Consuming to Produce

As the clock turns over an arbitrary time boundary that marks one year from the next, many reflect on their past and make promises of change for the future.



Not one to want to feel left out in such reflecting, I, too, have made promises for the year (and, really, years) ahead. Well, one in particular: be more creative.



Being more creative was purposely vague so as to leave numerous avenues in which to pursue that creativity. Web design and development is assuredly a given, as that’s well within my wheelhouse of skills. Tangentially, I’ve been working to improve my photography and photo editing skills, turning that work into one web project or another. More writing. And cooking.



Each new channel of exploration has become a new way to spend money. There’s a name for this: The Diderot Effect.




The Diderot Effect states that obtaining a new possession often creates a spiral of consumption which leads you to acquire more new things. As a result, we end up buying things that our previous selves never needed to feel happy or fulfilled.




Photography is fun. Surely, I’d have better photos with that particular camera. Or the latest iPhone. Or that new lens. Y’know, I really need a better camera strap. And a new shoulder bag. Maybe a backpack for particular trips to carry all this gear.



Cooking is fun. Let’s give sous vide a go. I need the plastic tub that is especially designed for the wand. And the wire mesh to hold the food off the bottom. And a cast iron pan would really be better than my 10 year old teflon pans. Oh, and a blow torch for post-bath Maillard reactions. (And maybe try my hand at a crème brûlée while I’m at it.)



Making coffee is fun. Yes, I must have the double boiler espresso machine. And grinder, of course. And knock box. And some lovely cups to go with it.



Oh, I’ll tell you with a straight face that I’m a modern minimalist man but I have a knack for filling up my home with all the latest gadgets in pursuit of something to fill my spare time. In my effort to produce more, I end up consuming more.



Maybe in an effort to be more creative, I should be more creative in accomplishing my goals without all the gadgets.



Right after I buy this thing I need for the kitchen.

 •  0 comments  •  flag
Share on Twitter
Published on January 14, 2020 12:56

January 4, 2020

Travelling Man

As one might expect in trying to go to numerous restaurants around the world, much travel would ensue. And sure enough, that happened.



In 2019, I travelled to:




Montreal (twice)
Toronto (twice)
Pittsburgh
Portland (thrice)
Phoenix
Austin
Atlanta
San Antonio
San Francisco (twice)
Napa Valley
London
Lima
Paris (twice)
Amsterdam, with a drive to Zwolle and Ghent, Belgium
Barcelona
Buenos Aires


Some of my favourite memories, in no particular order.



I’ve never been a fan of Formula racing but a friend of mine is. I’ve known him since I was a teenager and he was my first roommate when I moved out at the tender age of 18. We went to Montreal to watch the race. He loved it. He even ran into Mitsou.




At the track.
At the track.


Made a trip the following weekend back to Montreal with my mom to have dinner in complete darkness.



My eldest son and I were supposed to go to Tokyo but our trip got cancelled. We ended up going to Toronto to see his favourite comedian: Fluffy! And then we went for his favourite food: Ramen! I enjoyed giving him that experience.



I got sick in London. Got to chat with the chefs at The Clove Club and The Ledbury.



Drove the Dutch and Belgian countrysides in search of food. Driving down a lane flanked by rolling green fields on the way to Hof Van Cleve. It was so picturesque, we had to pull to the side to take pictures.



Found a Cuban-themed bar in Lima and enjoyed a couple good drinks before it got too loud.



Sat on the rooftop of a restaurant in Napa Valley enjoying the best dessert wine I’ve ever had: a madeira from 1920. Some things do get better with age.




Blandy’s Madeira from 1920
Blandy’s Madeira from 1920


Hanging out with friends in a large house outside of Atlanta enjoying some of the finest whisky, cigars, and food.



Hung out in Austin during SXSW, bringing back good memories from a decade ago.



Celebrated a friend’s wedding anniversary in Pittsburgh. I enjoyed getting to see a bit of the ‘burgh for the first time and hang out with friends that I don’t get to see very often.



Walking with the girlfriend to coffee shops in Portland. Chatting with the baristas at Proud Mary, learning more about their process as I continue to improve my own process.



Walking for 45 minutes through the streets of Lima on the way to Central to beg our way into a table. Only to be denied and instead enjoyed the best meal at their sister restaurant, Kjolle.



In buying a bottle of whisky in Paris, the guy told us about a whisky speakeasy that the store runs. It’s in an old underground spot that used to be a spa. I had some of the best whisky I’ve ever had.




Nikka Single Cask distilled in 1986, bottled in 2008
Nikka Single Cask distilled in 1986, bottled in 2008


Sitting in the back of an Uber in Buenos Aires, chatting with the driver on the way to a restaurant. He asked what the average salary was in Canada. We said maybe $30,000. He was stunned. Like, utterly flabbergasted. He wanted to move to Canada right away. Then we figured out he thought that was monthly, not yearly. His excitement quickly deflated.



Finishing off the year here in Ottawa, with friends that I’ve known since I was 14 in high school. Much reminiscing with stories of those times.



Adventure is out there

A couple years ago, I decided to make the shift from “things” to “experiences” and my life has been full of them. I am frequently amazed at how lucky and privileged I’ve been and continue to be and how my life is full of amazing friends. Here’s to 2020 being filled with just as much and more.

 •  0 comments  •  flag
Share on Twitter
Published on January 04, 2020 10:56

December 25, 2019

A Year of Restaurants

It’s been an interesting year, to say the least. Started a new job. Left that job. Ended a relationship. Have a newfound affinity for Islay Scotch. (Those last two things aren’t related, surprisingly.) Throughout this tumultuous year, there has been adventures to many amazing restaurants around the world.



The main goal was to continue on the quest to eat at 50 of the World’s 50 Best Restaurants before I turn 50. Last year, I managed to make it to 10 restaurants. This year, I went to 17 restaurants on the list. That means I’m over the halfway point of this crazy challenge in just under two years.



This year kicked off with a trip to London in January where I came down with a severe bout of something viral and was bedridden for a bit. Not quite fully recovered, I stupidly went to the four restaurants I had reservations at: The Clove Club, Lyle’s, The Ledbury, and Dinner by Heston Blumenthal.



In April, a trip to Peru was to include three restaurants on the list. We went to Maido and Astrid & Gaston. Sadly, we couldn’t get reservations to Central due to some confusion with the online booking site. Instead, we went to its sister restaurant, Kjolle, which ended up being amazing. Like, how is this restaurant not on the list itself?!




A potato tart from Kjolle
A potato tart from Kjolle


In May, we made a road trip out of it, driving to Zwolle, in the Netherlands to go to De Librije. After an amazing meal and stay at the attached hotel, we drove to Ghent, Belgium for a brief stay to go to Hof Van Cleve.



Midway through the year, the 2019 list came out, adding Atelier Crenn and Benu from San Francisco to the list. Benu was visited the year prior, so I took the easy win.



Side Challenge

I had a secondary goal of going to every Michelin 3-starred restaurant in the Bay Area. This included Saison, Benu, Quince, and Coi in San Francisco—all of which I had been to in 2018. There is Manresa down in Los Gatos (which I also went to in 2018), The Restaurant at Meadowood (also visited in 2018) up in Napa Valley, and the French Laundry that is also up in Napa Valley. In 2019, Michelin added SingleThread and Atelier Crenn to the ranks of 3-star restaurants.



That means, I had three restaurants to go to to complete the side quest. It also meant adding one more to the 50 list. In July, I went to Atelier Crenn, SingleThread, and French Laundry in a single weekend.




The setting sun shining some light at the French Laundry
The setting sun shining some light at the French Laundry


Thomas Keller, of the French Laundry, was a consultant on the movie Ratatouille, which set my expectations high. I really wanted them to serve the dish from the movie, but sadly, it didn’t happen. The meal was still wonderful, though.



Side challenge completed.



Autumn

I wanted to make another big jump for the 50 list. Getting a restaurant here or there just wasn’t going to cut it. There are five restaurants on the list in Paris. I managed to snag reservations at four of the five to be within three days of each other: Alain Ducasse au Plaza Athénée, Arpège, Alléno Paris au Pavillon Ledoyen, and Astrance. (I seemed to have forgotten about Septime, which is unfortunate.)




Lunch at Arpège was divine
Lunch at Arpège was divine


Paris is also where I learned of a whisky speakeasy hidden under a sake bar. Absolutely amazing. I already want to go back.



Last year, for Thanksgiving, we took Kitt’s parents to Copenhagen to have dinner at Geranium. This year, we took them to Barcelona. Disfrutar and Tickets were the primary targets, inching us further along the Fifty quest. Barcelona is a hotbed of molecular gastronomy. It was home to elBulli, run by Ferran Adria, well known as the creator of culinary foam. Former chefs from the restaurant started Disfrutar. Ferran’s brother, Albert, has since created a collection of restaurant within a stone’s throw of each other including Enigma and Pakta, which we also managed to get reservations to.



Enigma ended up being the most interesting of the bunch—and maybe the most challenging, too. Dishes included hare brain and squid head. There was also some foie gras, which I personally enjoy. Enigma was fascinating as it moved us through six stations and about 30 courses of food, including a speakeasy at the end.



One last Fifty adventure of the year was a trip to Buenos Aires for Don Julio, a steakhouse, and Tegui, a more “traditional” upscale restaurant with a tasting menu. Of course, I discovered that there’s a Latin America’s 50 Best Restaurants list that’s done by the same people who do the World’s list. As such, I made reservations for Mishiguene and Chila.



Mishiguene was a neat experience. It’s very casual but they did a tasting menu that was filling and flavourful. The portions were huge and felt like it could’ve fed a table of four. Chila ended up being the highlight of the trip with great service and amazing dishes. I felt like it deserves to be on the World’s 50 Best.



Ending the year past the halfway mark on the 50 by 50 adventure was very satisfying—and very filling.



Side Adventures

The side adventures have been a lot of fun, too.



With frequent trips to Portland, I’ve tried to get to many of the nice restaurants there and have been delightfully impressed. A return visit to Le Pigeon, for example, wasn’t as gut-busting as the first time I went but was still delicious. I’ve also been to DOC, Beast, Coquine, and Nodoguro. Not to mention the love I have for Bamboo Sushi.



Canada has its own Top 100 list with a handful of restaurants right here in Ottawa: Atelier, who’s head chef once worked at Alinea in Chicago; Riviera; Stofa; and Fauna. Atelier is definitely the fanciest of the bunch but I prefer the slightly more casual experience at the other places. Fauna has been consistent both times I’ve gone. Not on the list are places like Whalesbone and Aperitivo, which were also quite good. It’s nice to see Ottawa’s food scene expand.



Next Year

2020 will bring many more food adventures as I attempt to get to another 15 restaurants or so on the way to completing the 50.



Completing the second half of this adventure gets harder as the restaurants are fewer and farther between.



I already have reservations to Noma, which has returned to Copenhagen after being closed for a couple years. I’m hoping to also do a side trip to Maaemo in Oslo and Frantzen in Stockholm around the same time, which will require short flights from city to city.



I’d like to get to Tokyo, which has three restaurants on the list. Maybe add on an extension to Hong Kong to do the two restaurants there.



Probably the most ambitious will be planning out the possibility of two other trips.



One, to northern Italy. There are three restaurants: Le Calandre, Piazza Duomo, and the venerable Osteria Francescana. But there’s also Hisa Franko that’s a two and a half hour drive to the east, in Slovenia; and Mirazur, that’s a three hour drive to the west, in France. A one or two week road trip through the north of Italy sounds incredible.



The other, equally ambitious adventure, would be a trip to northern Spain, split between Bilbao and San Sebastian, to go to Asador Etxebarri, Nerua, Mugaritz, Elkano, Azurmendi, and Arzak.



Were I able to pull off all four of these trips as desired, I’d be at 46 of the 50 restaurants by the end of the year. Crazy.



Those would be amazing trips, for sure. At the same time, part of the fun of trying to tackle this list is heading off to places I haven’t been before—especially in out-of-the-way places. Hof Van Cleve, sitting out in the middle of rolling green hills, took me to a place I never would’ve picked. Trips to Lima and Buenos Aires were also new adventures to cities and countries I hadn’t been before.



As such, the places that excite me are places like Bangkok, Moscow, and Istanbul.



Onwards

Who knows what, exactly, the new year will bring. I just consider myself lucky to be this far along this journey and hope the new year brings many new adventures.

 •  0 comments  •  flag
Share on Twitter
Published on December 25, 2019 16:22

July 7, 2019

Leggo My Pattern Library Analogy

When you think of a pattern library (or design system), what analogy comes to mind? Lego? If I had a Lego piece for every time somebody used Lego as a pattern library analogy, I’d be able to build the Death Star.



Lego is pretty awesome but also difficult to replicate a design without detailed piece-by-piece instructions.



Someone hands you a box of Lego and tells you to build an interface and that it has to look like the rest of the site. What are the chances that you’ve built something that is technically consistent with what others have done? Did you use two 4x2 bricks, or one 4x2 and two 2x2 bricks? Did you use green bricks or yellow bricks?



Lego gives you plenty of options but very little consistency.



In reality, pattern libraries usually hit an upper limit of around 100 components. Salesforce’s Lightning has 85 components. Shopify’s Polaris has 90. Anything more than that and interfaces become unwieldy. Each component is something that the designer has to design, the developer has to build and maintain, the user has to learn to use.



The combinations with which these components fit together are also limited. A Toast message is generally only going to appear in one or two places within the interface.



Tetris, on the other hand? A limited set of pieces that fit together in a particular set of ways. Sometimes you screw it up and it looks a bit wonky. Other times, when it all comes together, magic happens!



Now that’s the best analogy ever.

 •  0 comments  •  flag
Share on Twitter
Published on July 07, 2019 13:58

July 1, 2019

Why Did I Have Difficulty Learning React?

Just over six months into a job doing React development, I’ve been trying to figure out why it has taken me so long to feel comfortable with it. (Comfortable feels a bit too ambitious of a word. Maybe competent? Unexceptional? Whichever.)



For me, I think it has come down to four different things:




All the Technologies
Writing JS differently
Deep Hierarchies
Evolving Approaches


All the Technologies

Working at Abstract meant learning their tech stack. Every company is different, of course. The Abstract product uses React for their desktop app, based in Electron, and their web app. There’s also Redux. There’s Flow for static type checking. Then there’s all the other libraries that are imported and used along the way.



It meant I needed to jump in and learn everything new and fresh. I didn’t know the APIs of any of these technologies. It has taken me awhile to learn the edges of each one and understand where I was using the concept of one library versus another.



When people talk about learning React, I think that React, in and of itself, is relatively easy to understand. At least, I felt it was. I have components. I have JSX. I hit some hiccups with required keys or making sure I was wrapping child elements properly. But overall, I felt like I grasped it well enough.



Throw in everything else at the same time, though, and things get confusing because it’s hard at first to recognize what belongs to what. “Oh, this is Redux. That is React. That other thing is lodash. Got it.”



Writing JS Differently

I’ve been writing JavaScript since DOM Level 0. I started out writing everything as functions. Then Prototype came out and I had this new way of thinking about writing JavaScript. A year after Prototype, jQuery came out and, again, I was learning new concepts.



Component-based libraries like Dojo and YUI came out but I didn’t feel like I had to dramatically shift the way I write JavaScript. The JavaScript interface—ECMAScript, specifically—went pretty much unchanged for a decade.



And then ES5 and ES6 came out.



I now found myself having to not only learn all the new frameworks and libraries but also learn this new paradigm of developing JavaScript.



Similarly, using a static type checker meant I had to learn what was new JavaScript syntax and what was a part of Flow syntax.



Deep Hierarchies

Another hurdle I ran into was deep object hierarchies. This is a more subtle one but I definitely feel this when I’m digging into an issue.



To some degree, I think Redux is somewhat to blame, with each object needing global state being wrapped in a Connect component. As such, inspecting a React tree is often nearly twice as long than it feels like it needs to be.



Sometimes it’s hard to track down where a component is defined. It might be rendered as a child element but actually gets defined a few levels up, assigned to a prop, and then passed down. Where something “lives” isn’t always clear.



It’s also not always clear where the data is coming from that is populating a component. Sometimes it’s five levels up being passed down through rested props. Sometimes it’s pulled in via Redux.



I feel like a I have a dump truck full of context unloading itself into my brain before I can understand it.



It’s not unusual for me to begin my hunt down the rabbit hole opening 10 different files, trying to trace where the data is coming from.



At Abstract, we’ve started differentiating our Flow typing to make this clearer. This leads me into my last reason.



Evolving Approaches

The way we choose to solve a problem changes over time. Coming into Abstract, I was coming into a three year-old project that has evolved over that time. What started as a desktop-only product evolved to support desktop and web. React has changed in that time. Redux has changed in that time. Flow has changed in that time. Every developer on the team evolves.



As such, going through the project can often be like looking at the cross section of a felled tree. The rings and knots of The Old Ways are made visible under the light of debugging. New approaches don’t necessarily wipe out the old ones. Instead, the old code sits until one day it is uprooted from existence through refactoring and replaced.



I’ve often found myself hopping on a call with a co-worker, someone who has been with the company and the code much longer than I have, to be told, “yup, that should probably be refactored.”



Momentum

The past six months have been about learning all the things. Not just the different frameworks and the evolution of JavaScript but also the more subtle art of trying to learn the nooks and crannies of a codebase.



As such, it has taken me six months to build up some momentum and feel useful and productive.



It was difficult to come in thinking I was a senior developer and instead feeling like a junior. I often spent more time than I should have on my own just trying to understand things, frustrating myself in the process. I’d go a day or two or three of making no progress before reaching out to someone to explain something I didn’t understand but feeling like I should, feeling like I wasn’t good enough.



I put a lot of pressure on myself.



I’ve considered quitting many times.



I needed to reframe why I was at Abstract and come at it from the viewpoint of being a beginner again. As such, I’ve slowly been building momentum. A successful week is one that is better than the last.



I have to give a lot of credit to my managers and co-workers at Abstract. They’ve been patient and helpful and kind. I consider myself quite lucky to be among good people.

 •  0 comments  •  flag
Share on Twitter
Published on July 01, 2019 07:03

Jonathan Snook's Blog

Jonathan Snook
Jonathan Snook isn't a Goodreads Author (yet), but they do have a blog, so here are some recent posts imported from their feed.
Follow Jonathan Snook's blog with rss.