<?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: Shimin Zhang</title>
    <description>The latest articles on DEV Community by Shimin Zhang (@itstrueintheory).</description>
    <link>https://dev.to/itstrueintheory</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%2F813590%2Feb6a779b-b81e-46db-af08-abb25f9a1865.jpg</url>
      <title>DEV Community: Shimin Zhang</title>
      <link>https://dev.to/itstrueintheory</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/itstrueintheory"/>
    <language>en</language>
    <item>
      <title>My Favorite Books of 2022</title>
      <dc:creator>Shimin Zhang</dc:creator>
      <pubDate>Mon, 06 Feb 2023 06:02:35 +0000</pubDate>
      <link>https://dev.to/itstrueintheory/my-favorite-books-of-2022-334g</link>
      <guid>https://dev.to/itstrueintheory/my-favorite-books-of-2022-334g</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2rprwjxdzy75481vbf6u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2rprwjxdzy75481vbf6u.jpg" alt="Favorite Books of 2022" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of my 2022 goals was sticking to a consistent nonfiction reading habit of 1 hour a day, 7 days a week. While I only mostly succeeded, I ended the year with a 33-book-long book list. Here are my favorites books of last year, along with a short review and a key insight.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://every-layout.dev/" rel="noopener noreferrer"&gt;Every Layout&lt;/a&gt; by Heydon Pickering and Andy Bell
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Big Idea&lt;/strong&gt; : &lt;em&gt;Layout should be about the relationship between elements and how they change, not the elements themselves.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A great little book that changed the way I think about web layout and layout separation of concerns when it comes. It also contains some great information about the inner workings of the CSS layout spec that are often missed by developers who find CSS mystifying. The bulk of the book contains a series of fundamental layout relationships along with how to implement them in multiple web technologies. Learning these fundamental layouts is a great way to break down complex designs into modular layout components.&lt;/p&gt;

&lt;p&gt;Fun fact, I used the layout patterns in the book in my day job in the form of CSS layout utilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.momtestbook.com/" rel="noopener noreferrer"&gt;The Mom Test&lt;/a&gt; by Rob Fitzpatrick
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Big Idea:&lt;/strong&gt; &lt;em&gt;Don't ask users about future potential solutions. Ask about their past experiences and specific pains.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;How often have you gotten enthusiastic responses about the latest feature you are in love with, only to release it and find it hardly gets used? The Mom Test help you conduct better customer interviews and separate the problems users don't care enough to fix from the features that solve real pain points they are willing to commit to today.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.amazon.com/Philosophy-Software-Design-John-Ousterhout/dp/1732102201" rel="noopener noreferrer"&gt;Philosophy of Software Design&lt;/a&gt; by John Ousterhout
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Big Idea&lt;/strong&gt; : &lt;em&gt;Good software design is about dealing with the fundamental nature of complexity and our need for information hiding&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This is one of my favorite books on software development – it attempts to build a philosophical framework for what it means to write good software. From the definition of complexity to tactical red flags like 'when the same knowledge is used in multiple places'. While I don't agree with all of the book's recommendations, I wish I had this book earlier in my career to provide a framework for evaluating software design principles.  &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://dataintensive.net/" rel="noopener noreferrer"&gt;Designing Data-Intensive Applications&lt;/a&gt; by Martin Klepperman
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Big Idea&lt;/strong&gt; : &lt;em&gt;Build fault-tolerant systems by finding general-purpose abstractions with good guarantees then build everything on those guarantees.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's hard to pin down a single big idea for this book since it is chock full of them. While I mostly work on the front end,  this book is a must-read for anyone interested in building and understanding scalable applications. This is one of those books that can never be replaced by blog posts or StackOverflow answers, it builds a strong mental shelf of database topics and how they relate to each other, something that you can refer back to for years to come.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.oreilly.com/library/view/badass-making-users/9781491919057/" rel="noopener noreferrer"&gt;Badass: Making Users Awesome&lt;/a&gt;  by Kathy Sierra
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Big Idea&lt;/strong&gt; : &lt;em&gt;Users don't evangelize to their friends because they like the product but because they like their friends.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This book is packed full of insights on what it means to build a product so good that your users will market it for you. I wish more software are built with these principles in mind – instead of the addiction-based model that is so common these days. This book made me much more mindful of the increase in cognitive resources any new features would cause.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.manning.com/books/reactive-design-patterns" rel="noopener noreferrer"&gt;Reactive Design Pattern&lt;/a&gt; by Roland Kuhn with Brian Hanafee and Jamie Allen
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Big Idea&lt;/strong&gt; : &lt;em&gt;Nondeterminism is a necessary evil due to hardware limitations.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Another really good book on creating scalable and fault-tolerant applications, this time through the use of functional reactive programming. While a lot of the message-passing / functional programming paradigms are familiar to AngularJS developers, I found the fault tolerance and recovery patterns very insightful – reminds me of &lt;em&gt;Release It!&lt;/em&gt; by Michael T. Nygard.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.amazon.com/Timeless-Way-Building-Christopher-Alexander/dp/0195024028" rel="noopener noreferrer"&gt;The Timeless Way of Building&lt;/a&gt; by Christopher Alexander
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Big Idea:&lt;/strong&gt; &lt;em&gt;The central task of 'architecture' is the creation of a single, shared, evolving, pattern language that everyone contributes to, and everyone can use.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As someone with 'architect' in my job title, I occasionally find myself reading about architecture to try and live up to my role. Christopher Alexander coined the term &lt;em&gt;design patterns&lt;/em&gt; in &lt;em&gt;the Timeless Way of Building&lt;/em&gt;, and I found the rest of the book equally applicable to the art of software. A long-lasting piece of software -- like a medieval village – is a living thing, and its never-ending stream of maintenance and repairs is what gives it its final shape.&lt;/p&gt;

&lt;p&gt;A particular story from the book has not left my mind since the initial reading :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Suppose that I am trying to make a table for the blackbirds in my garden. In winter, when the snow is on the ground, and the blackbirds are short of food, I will put food out for them on the table. So I build the table; and dream about the clusters of blackbirds which will come flocking to the table in the snow. But it is not so easy to build a table that will really work. The birds follow their own laws; and if I don’t understand them, they just won’t come. If I put the table too low, the birds won’t fly down to it. If it is too high in the air, or too exposed, the wind won’t let them settle on it. If it is near a laundry line, blowing in the wind, they will be frightened by the moving line. Most of the places where I put the table actually don’t work. I slowly learn that blackbirds have a million subtle forces guiding the in their behavior. If I don’t understand these forces, there is simply nothing I can do to make the table come to life. So long as the placing of the table is inexact, my image of the blackbirds flocked around the table eating is just wishful thinking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I hope we can all chase fewer software fads and learn more about blackbirds in 2023.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>frontend</category>
      <category>discuss</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Javascript readability vs performance: a false tradeoff</title>
      <dc:creator>Shimin Zhang</dc:creator>
      <pubDate>Fri, 15 Jul 2022 15:08:23 +0000</pubDate>
      <link>https://dev.to/itstrueintheory/javascript-readability-vs-performance-a-false-tradeoff-520b</link>
      <guid>https://dev.to/itstrueintheory/javascript-readability-vs-performance-a-false-tradeoff-520b</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L2lXoA__--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1534755563369-ad37931ac77b%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDI2fHxlbmdpbmV8ZW58MHx8fHwxNjU3ODY3NDg5%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L2lXoA__--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1534755563369-ad37931ac77b%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDI2fHxlbmdpbmV8ZW58MHx8fHwxNjU3ODY3NDg5%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" alt="Javascript readability vs performance: a false tradeoff" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have you ever come across a piece of "clever" Javascript code that causes you to slow down and concentrate a little harder in order to digest it?&lt;/p&gt;

&lt;p&gt;"Prefer readability over premature optimization" is a popular developer mantra, but the mantra also implies that the two are mutually exclusive. Does this assumption actually hold true when we are dealing with hard-to-parse one-liners?&lt;/p&gt;

&lt;p&gt;Here's an example of a "clever" piece of code, a one-line solution to the FizzBuzz problem (taken from this &lt;a href="https://codeburst.io/javascript-breaking-down-the-shortest-possible-fizzbuzz-answer-94a0ad9d128a"&gt;medium post&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; function oneLineFizBuzz (n) {
    return ((n % 3 ? '' : 'fizz') + (n % 5 ? '' : 'buzz') || n);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sure, you have to squint a little and think through the use case where &lt;code&gt;n&lt;/code&gt; is divisible by both 3 and 5, and you also have to remember that an empty string evaluates to a falsy value in Javascript, but at least it's fast right?&lt;/p&gt;

&lt;p&gt;For comparison's sake, let's also create a much more straightforward version of the FizzBuzz solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function clearFizzBuzz (n) {
    let result;
    const div3 = n % 3 === 0;
    const div5 = n % 5 === 0;
    if (div3 &amp;amp;&amp;amp; div5) {
        result = 'fizzbuzz';
    } else if (div3) {
        result = 'fizz';
    } else if (div5) {
        result = 'buzz';
    } else {
        result = n;
    }
    return result;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second solution is clearly easier to read and reason about, but is it slower than the one-line version? And if so, by how much?&lt;/p&gt;

&lt;p&gt;By the end of the post, you'll see that because most of our JS code runs on highly optimized engines, performance and readability are not mortal enemies. In fact, readable Javascript is frequently the same as performant Javascript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarking Our Functions
&lt;/h2&gt;

&lt;p&gt;Looking at our two functions, the clear version contains two more constant assignments (&lt;code&gt;div3&lt;/code&gt;, &lt;code&gt;div5&lt;/code&gt;) and one more branching operation (&lt;code&gt;div3&amp;amp;&amp;amp;div5&lt;/code&gt;). It should in theory be slower.&lt;/p&gt;

&lt;p&gt;To make sure, let's run some experiments using the benchmark file from Surma's Is &lt;a href="https://surma.dev/things/js-to-asc/index.html"&gt;WebAssembly magic performance pixie dust?&lt;/a&gt; post (&lt;a href="https://gist.github.com/surma/40e632f57a1aec4439be6fa7db95bc88"&gt;gist&lt;/a&gt;). We'll run each function for integers from 1 to 10e5 for 10 iterations and average the results. We'll also run 10 iterations before recording results, allowing the V8 engine to warm up and optimize the two functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const ITERATIONS = 10;
const oneLineResults = benchmark({
  run() {
    for (let i = 1; i &amp;lt; 10e5; i++) {
      oneLineFizBuzz(i);
    }
  },
  numWarmup: 10,
  numIterations: ITERATIONS
});
print('one line version result:', oneLineResults.average);

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

&lt;/div&gt;



&lt;p&gt;Here's our result running the testing code with NodeJS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;one line version result: 4.6
clear version result: 2.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The more verbose version is significantly faster. Huh, what gives?&lt;/p&gt;

&lt;h2&gt;
  
  
  V8 Bytecode
&lt;/h2&gt;

&lt;p&gt;To get a better understanding of why our clever one-liner FizzBuzz solution is slower, we need to take a look at how V8 works. V8 is the Javascript engine that powers NodeJS, you can directly download a binary version of the engine either via &lt;a href="https://github.com/GoogleChromeLabs/jsvu"&gt;JSVU&lt;/a&gt; instead of compiling locally.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The results below are from v8-debug-10.4.132 on my local Linux 64-bit system.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's a diagram of how V8 processes our Javascript source code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JNKu2-iP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.shimin.io/content/images/2022/07/v8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JNKu2-iP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.shimin.io/content/images/2022/07/v8.png" alt="Javascript readability vs performance: a false tradeoff" width="641" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;_Note: this diagram is out of date, the V8 engine v10.4 no longer uses Crankshaft and instead has two additional optimizers before TurboFan – Sparkplug and Maglev.  _&lt;/p&gt;

&lt;p&gt;On engine start, V8 first parses the JS code into its AST, then the Ignition interpreter translates the AST into platform-independent V8 Bytecode before passing it on to additional optimizing compilers. Its the optimizers' job to turn the platform-independent bytecode into platform-specific machine optimized code.&lt;/p&gt;

&lt;p&gt;Here's what the Bytecode of our one-liner FizzBuzz function looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[generated bytecode for function: oneLineFizBuzz (0x12ea00253ad9 &amp;lt;SharedFunctionInfo oneLineFizBuzz&amp;gt;)]
Bytecode length: 35
Parameter count 2
Register count 1
Frame size 8
Bytecode age: 0
         0x12ea00253d76 @ 0 : 0b 03 Ldar a0
         0x12ea00253d78 @ 2 : 49 03 01 ModSmi [3], [1]
         0x12ea00253d7b @ 5 : 97 06 JumpIfToBooleanFalse [6] (0x12ea00253d81 @ 11)
         0x12ea00253d7d @ 7 : 13 00 LdaConstant [0]
...
         0x12ea00253d94 @ 30 : 96 04 JumpIfToBooleanTrue [4] (0x12ea00253d98 @ 34)
         0x12ea00253d96 @ 32 : 0b 03 Ldar a0
         0x12ea00253d98 @ 34 : a9 Return 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;You can generate function bytecode by running the debug-v8 engine with the flag &lt;code&gt;--print-bytecode&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And as suspected, the Bytecode of our &lt;code&gt;clearFizzBuzz&lt;/code&gt; the function is longer than its one-liner counterpart (note the length of 63 vs 35 for oneLineFizzBuzz).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[generated bytecode for function: clearFizzBuzz (0x12ea00253b11 &amp;lt;SharedFunctionInfo clearFizzBuzz&amp;gt;)]
Bytecode length: 63
Parameter count 2
Register count 4
Frame size 32
Bytecode age: 0
         0x12ea00253e1e @ 0 : 0e LdaUndefined 
         0x12ea00253e1f @ 1 : c4 Star0 
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In fact, if we run our benchmark test without using any of V8's optimizers, the one-liner version is indeed faster – though not by much.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;one line version result: 3948.4
clear version result: 4085.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  V8 Optimized Javascript
&lt;/h2&gt;

&lt;p&gt;The most surprising thing about our previous result is not how similar the function performances are. It's the fact that TurboFan optimization gave us a 1000-fold increase in execution speed.&lt;/p&gt;

&lt;p&gt;As mentioned earlier, once a piece of JS code is invoked multiple times,  V8's TurboFan optimizer kicks in and produces an optimized version of our functions. You can view the optimized code via V8's &lt;code&gt;--print-opt-code&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;Here are the first few lines of our optimized clear function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;optimization_id = 0
source_position = 135
kind = TURBOFAN
name = clearFizzBuzz
stack_slots = 6
compiler = turbofan
address = 0x7f88c0084001

Instructions (size = 480)
0x7f88c0084040 0 488d1df9ffffff REX.W leaq rbx,[rip+0xfffffff9]
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;versus our one-line function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;optimization_id = 1
source_position = 31
kind = TURBOFAN
name = oneLineFizBuzz
stack_slots = 6
compiler = turbofan
address = 0x7f88c0084241

Instructions (size = 592)
0x7f88c0084280 0 488d1df9ffffff REX.W leaq rbx,[rip+0xfffffff9]
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important bit here is the instruction size. Our one-liner FizzBuzz solution has an instruction size of 592 while the readable variation is only 480 instructions long.&lt;/p&gt;

&lt;p&gt;While both our intuition and the V8 bytecode informed us the one-liner function should be faster, the optimized TurboFan result is the reverse.&lt;/p&gt;

&lt;p&gt;While I did not perform additional testing to confirm exactly why our 'clever' FizzBuzz solution is slower in practice. Though I suspect the culprit is the string concatenation that must be done on every iteration that slows it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;I hope this post has convinced you that code readability and performance are not mutually exclusive — at least not in the case of Javascript running on a highly optimized compiler.&lt;/p&gt;

&lt;p&gt;So next time you see a piece of clever code in an MR that makes you pause and squint, point out that it can be written more clearly – and potentially without any performance penalties.&lt;/p&gt;

&lt;p&gt;And next time you are tempted to write something &lt;em&gt;clever and super concise&lt;/em&gt;, consider rewriting it for &lt;strong&gt;readability and for performance&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;Thanks for reading this far. As always, if you found this post helpful, please share it with others. You may also be interested in learning about &lt;a href="https://dev.toTroubleshooting%20a%20JavaScript%20memory%20leak"&gt;Troubleshooting Javascript memory leaks&lt;/a&gt; or &lt;a href="https://blog.shimin.io/measure-web-performance-with-navigation-timing-api/"&gt;How to measure web performance with the Navigation TIming API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Readings
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Franziska Hinkelmann's excellent &lt;a href="https://medium.com/dailyjs/understanding-v8s-bytecode-317d46c94775"&gt;Understanding V8's Bytecode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Matt Zeunert's &lt;a href="https://www.mattzeunert.com/2015/08/19/viewing-assembly-code-generated-by-v8.html"&gt;Compiling V8 and Viewing the assembly code it generates&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;V8 Blog's &lt;a href="https://v8.dev/blog/sparkplug"&gt;Sparkplug — a non-optimizing JavaScript compiler&lt;/a&gt;, &lt;a href="https://v8.dev/blog/ignition-interpreter"&gt;Firing up the Ignition interpreter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.google.com/presentation/d/1H1lLsbclvzyOF3IUR05ZUaZcqDxo7_-8f4yJoxdMooU/edit#slide=id.g18ceb14721_0_83"&gt;An Overview of the TurboFan Compiler&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>performance</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Troubleshooting a JavaScript memory leak</title>
      <dc:creator>Shimin Zhang</dc:creator>
      <pubDate>Fri, 17 Jun 2022 18:15:15 +0000</pubDate>
      <link>https://dev.to/itstrueintheory/troubleshooting-a-javascript-memory-leak-15oc</link>
      <guid>https://dev.to/itstrueintheory/troubleshooting-a-javascript-memory-leak-15oc</guid>
      <description>&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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2Ferik-mclean-GjCx5KhulZI-unsplash.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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2Ferik-mclean-GjCx5KhulZI-unsplash.jpg" alt="Troubleshooting a JavaScript memory leak"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I got a chance to debug an app memory leak issue this week, when I took a heap snapshot in Chrome it dawned on me:&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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2Fscreenshot.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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2Fscreenshot.png" alt="Troubleshooting a JavaScript memory leak"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What the heck am I looking for?&lt;/p&gt;

&lt;p&gt;Should I be sorting heap objects by distance, shallow size, or retained size?&lt;/p&gt;

&lt;h2&gt;
  
  
  JS Garbage Collection
&lt;/h2&gt;

&lt;p&gt;JavsScript memory is managed automatically, meaning the JS engine's garbage collector releases heap memory automatically when they are no longer in use.&lt;/p&gt;

&lt;p&gt;All modern web browsers (i.e. not IE) use some variation of the mark-and-sweep algorithm to determine which heap objects are safe for garbage collection (GC). The algorithm has two phases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Marking phase&lt;/strong&gt; : Starting from a root object, recursively traverse all heap objects referenced by the root GC node and mark them as &lt;code&gt;in-use&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sweeping phase&lt;/strong&gt; : Iteratively visit all objects in the heap and release any that are not marked as &lt;code&gt;in-use&lt;/code&gt;. &lt;/li&gt;
&lt;/ol&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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2FAnimation_of_the_Naive_Mark_and_Sweep_Garbage_Collector_Algorithm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2FAnimation_of_the_Naive_Mark_and_Sweep_Garbage_Collector_Algorithm.gif" alt="Troubleshooting a JavaScript memory leak"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a simplified description of the V8 GC process. In actuality, the Chrome GC keeps heap objects in multiple categories bucked by their generation and incrementally garbage collects them.  &lt;/p&gt;

&lt;p&gt;The distance column in the heap snapshot screenshot above indicates the reference distance between an object and the GC root. A memory leak occurs when an object that otherwise should be garbage collected is marked as &lt;code&gt;in-use&lt;/code&gt; by the marking phase of the algorithm – meaning some other object is unintentionally holding its reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up
&lt;/h2&gt;

&lt;p&gt;The heap snapshot of a completely empty webpage still contains a significant amount of objects in its heap. So let's set up a test example to better monitor our heap usage using Chrome's built-in snapshot comparison function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;script&amp;gt;
    var memBuffer;
    function start() {
      memBuffer = { 
          value: new ArrayBuffer(1000)
      };
    }
  &amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;button onclick="start()"&amp;gt;start&amp;lt;/button&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we had to declare the &lt;code&gt;memBuffer&lt;/code&gt; variable at the global scope to prevent the object from being garbage collected once the &lt;code&gt;start&lt;/code&gt; function finishes execution. This is our memory leak into the global scope.&lt;/p&gt;

&lt;p&gt;To use the snapshot comparison feature, we first take a snapshot of the page on page load, then click on the start button to allocate additional memory to our &lt;code&gt;memBuffer&lt;/code&gt; object. We can then view new objects allocated between Snapshot 1 and 2 and filter for our new ArrayBuffer.&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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2FScreenshot-from-2022-06-17-00-28-58.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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2FScreenshot-from-2022-06-17-00-28-58.png" alt="Troubleshooting a JavaScript memory leak"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Shallow vs Retained Size
&lt;/h2&gt;

&lt;p&gt;Once we've filtered for new &lt;code&gt;JSArrayBufferData&lt;/code&gt; type heap objects, we see it has been added to the heap at 1kb for both shallow and retained sizes.&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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2FScreenshot-from-2022-06-17-00-37-03-1.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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2FScreenshot-from-2022-06-17-00-37-03-1.png" alt="Troubleshooting a JavaScript memory leak"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The retainer path provides us with details on the path that connects our buffer to the garbage collector root. GR root -&amp;gt; Window Object -&amp;gt;  memBuffer object -&amp;gt; value key -&amp;gt; memory buffer for a total distance of 4. In Firefox, we can pull up the same information under the &lt;em&gt;dominators&lt;/em&gt; view, although the exact object size and graph shape differ slightly due to implementation differences. FF also gives us a nice retaining path chart.&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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2FScreenshot-from-2022-06-17-09-42-51.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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2FScreenshot-from-2022-06-17-09-42-51.png" alt="Troubleshooting a JavaScript memory leak"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Going back to the value key in Chrome's retained size column, we see that 16b is the size of pointers used to keep track of key-value reference while the 1188b retained size includes the buffer object memory that will be freed when the value key is deleted.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In other words, we should look at the retained size column when looking at heap snapshots, it determines the amount of memory that will be released when an object is garbage collected.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To show the retained / shallow size difference, let's move our &lt;code&gt;ArrayBuffer&lt;/code&gt; outside of the object instantiation and establish a global reference to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    var memBuffer;
    var ab = new ArrayBuffer(1000);
    function start() {
      memBuffer = { 
          value: ab
      };
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2FScreenshot-from-2022-06-17-09-12-49.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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2FScreenshot-from-2022-06-17-09-12-49.png" alt="Troubleshooting a JavaScript memory leak"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Running the test again, we see the value key's retained size has reduced from 1188b to only 124b. By adding another reference path to our &lt;code&gt;ArrayByffer&lt;/code&gt; from GC root, the GC can no longer release the entire 1kb if our value key is deleted.&lt;/p&gt;

&lt;p&gt;Going back to Firefox, we see an updated retaining path graph with the alternate path to our ArrayBuffer through the &lt;code&gt;ab&lt;/code&gt; variable. Now there are two paths from the GC root to our ArrayBuffer.&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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2FScreenshot-from-2022-06-17-09-37-22.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%2Fblog.shimin.io%2Fcontent%2Fimages%2F2022%2F06%2FScreenshot-from-2022-06-17-09-37-22.png" alt="Troubleshooting a JavaScript memory leak"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In graph theory terms, a node &lt;em&gt;x&lt;/em&gt; is said to &lt;a href="https://en.wikipedia.org/wiki/Dominator_(graph_theory)" rel="noopener noreferrer"&gt;dominate&lt;/a&gt; another node &lt;em&gt;y&lt;/em&gt; if every path from the root node to &lt;em&gt;y&lt;/em&gt; must pass through &lt;em&gt;x&lt;/em&gt;. The retainer size of a heap object is the size of all objects that it dominates. In the first example, the &lt;code&gt;memBuffer&lt;/code&gt; object is a dominator for the ArrayBuffer while in the second example it is the Window object.&lt;/p&gt;

&lt;p&gt;In summary, when troubleshooting memory issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the snapshot comparison functionality to narrow your search down to newly created heap objects.&lt;/li&gt;
&lt;li&gt;Look for heap objects with a large retained size that should be garbage collected.&lt;/li&gt;
&lt;li&gt;To determine whether an object should be garbage collected, check its retainer path and examine reference validity. &lt;/li&gt;
&lt;li&gt;Some common memory leak issues are easy to resolve, if you see signs for detached elements, detached element event listeners, and large global cache objects, consider removing their dominator references. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope that was helpful! If you like the post, please share it with others. You may also be interested in learning about &lt;a href="https://blog.shimin.io/measure-web-performance-with-navigation-timing-api/" rel="noopener noreferrer"&gt;how to measure web performance with Navigation Timing API&lt;/a&gt; or &lt;a href="https://blog.shimin.io/css-custom-properties-as-style-api/" rel="noopener noreferrer"&gt;how to use CSS custom properties to create style API&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>performance</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>3 useful CSS properties to customize your web interactions</title>
      <dc:creator>Shimin Zhang</dc:creator>
      <pubDate>Fri, 10 Jun 2022 21:03:19 +0000</pubDate>
      <link>https://dev.to/itstrueintheory/3-useful-css-properties-to-customize-your-web-interactions-135g</link>
      <guid>https://dev.to/itstrueintheory/3-useful-css-properties-to-customize-your-web-interactions-135g</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7vmbSKkI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.shimin.io/content/images/2022/06/niranjan-_-photographs-4cVfDseo2e0-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7vmbSKkI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.shimin.io/content/images/2022/06/niranjan-_-photographs-4cVfDseo2e0-unsplash.jpg" alt="3 useful CSS properties to customize your web interactions" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A CSS complaint I often see online — one that I largely agree with — is there are too many properties to learn. After learning the basics, it feels like you are then asked to 'memorize the rest of the dictionary'.&lt;/p&gt;

&lt;p&gt;Like building a vocabulary, it's easier to add to your CSS knowledge slowly over time than reading the entire spec over a weekend. Today, I want to share 3 of my favorite "new to me" CSS properties from the last year.&lt;/p&gt;

&lt;h2&gt;
  
  
  user-select
&lt;/h2&gt;

&lt;p&gt;There are few things more frustrating than site owners disabled text selection with &lt;code&gt;user-select: none;&lt;/code&gt;. This is usually done with the intent of copy-prevention. Doing so not only violates web conventions but it doesn't even work since one can always access the HTML directly.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;user-select: none&lt;/code&gt; is not what I want to focus on. I want to mention the lesser-known value: &lt;code&gt;user-select: all;&lt;/code&gt;. The &lt;code&gt;all&lt;/code&gt; value causes any selection inside the element to select all element text, even with a single click.&lt;/p&gt;

&lt;p&gt;This means you can use HTML elements as semantic 'highlight sections' to group related content together. Some interesting use-cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;address&amp;gt;&lt;/code&gt; it makes sense to wrap an entire name/address /telephone in a single copy section. So the user can copy an entire address in a rental listing into Google Maps to lookup commute distance.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; you can wrap sections of code in its own &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; to make copy/pasting easier. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/GRQwmmw?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Like all techniques, &lt;code&gt;user-select: all&lt;/code&gt; involves some tradeoff, it can make common copy/highlights tasks easier but comes at a cost of breaking existing user expectations.&lt;/p&gt;

&lt;h2&gt;
  
  
  pointer-events
&lt;/h2&gt;

&lt;p&gt;Pointer event is yet another CSS property that affects interactions, you can use it to change how an element interacts with mouse events.&lt;/p&gt;

&lt;p&gt;The most common use case for pointer events is adding &lt;code&gt;pointer-events:none&lt;/code&gt; to an element so that it can no longer be clicked on — see &lt;a href="https://davidwalsh.name/css-facts"&gt;this example&lt;/a&gt; from David Walsh. This way, you can use CSS selectors to determine whether some elements should be transparent to the hit-testing algorithm, a better alternative to adding checks inside the click event handler for its current target and manually calling &lt;code&gt;preventDefault()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Aside from using it to disable buttons and links,  &lt;code&gt;pointer-events:none&lt;/code&gt; is helpful when you have some overlapping components and want to pass the click event through one layer to another one underneath. See this example where inline SVG icons overlap with a &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; element, yet clicking on the icons will pass the event through to the select.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/vYdQJGy?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Resize
&lt;/h2&gt;

&lt;p&gt;The last CSS property I want to point out is &lt;code&gt;resize&lt;/code&gt;, the &lt;code&gt;resize&lt;/code&gt; prop allows users to modify an HTML element's size — hence the name.&lt;/p&gt;

&lt;p&gt;You are probably already familiar with the resizing behavior in the context of the &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; element. Resize behavior works well with textarea because we do not know in advance how much content a user will supply. You can disable this default behavior via &lt;code&gt;resize: none&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;resize&lt;/code&gt; is not limited to just &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; elements. You can make all content without &lt;code&gt;overflow: visible&lt;/code&gt; resizable. Either in the &lt;code&gt;horizontal&lt;/code&gt;, &lt;code&gt;vertical&lt;/code&gt; or &lt;code&gt;both&lt;/code&gt; directions.&lt;/p&gt;

&lt;p&gt;Here's a demo of a resizable reading window with a resizable range input that allows you to change the reading font size.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/bGLQoeJ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Depending on the input range, a resizable range input could be a more intuitive approach than using the keyboard or clicking with the mouse for a pixel-perfect value.  &lt;/p&gt;

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

&lt;p&gt;While we generally consider HTML to be about a document's semantics, CSS for its look and feel, and JS for user interaction, this categorization is not absolute.&lt;/p&gt;

&lt;p&gt;Just as the &lt;code&gt;disabled&lt;/code&gt; HTML attributes can affect an element's interactivity, there are a number of  CSS properties that handle more than styling. Following the &lt;a href="https://en.wikipedia.org/wiki/Rule_of_least_power"&gt;Rule of Least Power&lt;/a&gt;, we should look for HTML and CSS solutions before reaching for a pure JS one.&lt;/p&gt;

&lt;p&gt;If you are not familiar with the &lt;code&gt;resize&lt;/code&gt;, &lt;code&gt;user-select&lt;/code&gt;, and &lt;code&gt;pointer-events&lt;/code&gt; properties — or it's been a while since you last looked them up — I encourage you to take a look at the examples and maybe look up the docs to refresh your memory.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>Are negative CSS margins bad practice?</title>
      <dc:creator>Shimin Zhang</dc:creator>
      <pubDate>Fri, 03 Jun 2022 19:40:26 +0000</pubDate>
      <link>https://dev.to/itstrueintheory/are-negative-css-margins-bad-practice-lh7</link>
      <guid>https://dev.to/itstrueintheory/are-negative-css-margins-bad-practice-lh7</guid>
      <description>&lt;p&gt;The negative CSS margin is a bit of a black sheep of the box model family. Unlike its siblings the negative padding and border – which are simply invalid – the negative margin is useful yet often misused.&lt;/p&gt;

&lt;p&gt;So is using negative margins 'back practice'?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short answer is no, as long as you are only using negative CSS margins to bring elements closer together than their box model properties would allow&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Since positive margins are used to bring box model objects away from each other, the canonical use case for negative margins is to remove the positional constraints applied by another element's content, padding, or border.&lt;/p&gt;

&lt;p&gt;The downside of negative margins is they are difficult to debug and will make your CSS harder to read. The most often misuses of negative margins that I encounter is when it is used to make up for incorrect layouts elsewhere on the site. This is indeed bad practice.&lt;/p&gt;

&lt;p&gt;So when should you use negative margins? Let's take a look at some examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Offset Padding
&lt;/h2&gt;

&lt;p&gt;One common use case for negative margins is to remove the padding and border constraints applied by a parent element. Let's start with a card containing Keat's poem To Autumn:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/KKQexBN?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We want to enlarge the title of the poem so it takes up the entire upper section of the card, but the size of the &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; is constrained by the card's outer padding. Negative margins allow us to override the constraints:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/VwQdbVa?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;You can achieve the same effect using absolute positioning – see below.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/poaKPYx?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The Absolute positioning approach is significantly more brittle since it takes the element out of the document flow. Now we need to add more padding elsewhere on the page to compensate for the size of the title. Changing the size or content of the title now requires changing multiple lines of CSS to update card layout – the dreaded "multiple CSS tweaks for a small change".&lt;/p&gt;

&lt;h2&gt;
  
  
  Overlapping Boxes
&lt;/h2&gt;

&lt;p&gt;Because negative margins bring elements closer together, it is perfect for creating overlapping elements.&lt;/p&gt;

&lt;p&gt;Let's add a little emphasis to the Keat's name in our card and overlap it with card header to add emphasis:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/MWQXqZo?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This is a valid use case for negative margins since we are intentionally breaking out of the box model. We can similarly do this with absolute positioning:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/MWQXqZo?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Like the padding example, the absolute positioning method requires 2 changes when we make future changes: one to update the copy and another to update the offset to compensate for the copy. This makes our CSS &lt;a href="https://blog.shimin.io/understanding-css-complexity/"&gt;more complex&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Break Out of Parent Container
&lt;/h2&gt;

&lt;p&gt;The last example I want to look at is how negative margins can be used to change a parent component's content width constraint. Let's say we want to add a popover on hover with the author's bio, using absolute position so it doesn't take up document flow:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/MWQXPyQ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We see that popover content width is limited by its parent. This is an ugly look. We can set a fixed width for our popover, but the width is now static. With a short copy, this means lots of white space.&lt;/p&gt;

&lt;p&gt;Instead of having a fixed width, we can use a negative margin on the child element to allow ample space for growth as the copy needs:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/MWQXPyQ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;However, this is no longer the preferred way to achieve this effect with the introduction of CSS sizing 3 values &lt;code&gt;min-content&lt;/code&gt;, &lt;code&gt;max-content&lt;/code&gt;, and &lt;code&gt;fit-content&lt;/code&gt;. To achieve this effect with modern browsers we can simply use &lt;code&gt;width: max-content&lt;/code&gt; instead:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/eYVKRJq?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This is a cleaner, more readable approach that unfortunately does not work in Internet Explorer. Consider adding the negative margin trick as a fallback for IE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take-Aways
&lt;/h2&gt;

&lt;p&gt;What should we take away from this exercise in negative CSS margins? A few things to note:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Use negative CSS margins to overcome box model constraints inaccessible to layout algorithm changes.&lt;/li&gt;
&lt;li&gt; Negative margins can be easier to work with than their absolute positioned counterparts. By preserving the document flow, fewer layout tweaks are required on content and style changes.&lt;/li&gt;
&lt;li&gt; Negative margins can be hard to debug. Consider using CSS custom properties for negative margin values to make your code easier to read and to change.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.parent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--top-padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--border-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--top-padding&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;border-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--border-width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.child&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--top-padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="n"&gt;--border-width&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;If you found this post helpful, please share it with others. You may also be interested in learning about &lt;a href="https://blog.shimin.io/css-custom-properties-as-style-api/"&gt;how to use CSS custom properties to create style API&lt;/a&gt; or &lt;a href="https://blog.shimin.io/whats-the-big-deal-with-tailwind-css-anway/"&gt;why Tailwind CSS is a big deal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Follow me on Twitter &lt;a href="https://twitter.com/ItsTrueInTheory"&gt;@ItsTrueInTheory&lt;/a&gt; to get the latest blog updates.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>When &lt;br&gt; is not enough – A tour of 11 HTML and CSS line break examples</title>
      <dc:creator>Shimin Zhang</dc:creator>
      <pubDate>Fri, 27 May 2022 17:26:29 +0000</pubDate>
      <link>https://dev.to/itstrueintheory/when-is-not-enough-a-tour-of-11-html-and-css-line-break-examples-4f7c</link>
      <guid>https://dev.to/itstrueintheory/when-is-not-enough-a-tour-of-11-html-and-css-line-break-examples-4f7c</guid>
      <description>&lt;p&gt;The other day I was making copy changes and needed to add a line break to a CTA. When I reached for the trusty line break element &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt;, I got a PTSD flashback of early 2000's web development – when &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; was frequently used to add vertical spacing. This got me thinking:&lt;/p&gt;

&lt;p&gt;When is it wrong to used &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; and should I be using &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; instead?&lt;/p&gt;

&lt;p&gt;Should I use CSS to style line breaks instead of HTML elements? If so, how should I do it?&lt;/p&gt;

&lt;p&gt;In this post, I'll go over various HTML and CSS-based methods for creating line breaks in your text, as well as methods for breaking up words to achieve the right typeset. I'll use the first stanza of Walt Whitman's 1865 poem 'O Captain! My Captain!' to demo each method.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTML Line Break
&lt;/h2&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/jOZYmgW?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example 1:&lt;/em&gt; By default, browsers collapse all HTML whitespace characters into a single space character, removing all line breaks from the content. This is obviously an inappropriate choice. It strips away all rhythm from the poem.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example 2:&lt;/em&gt; You may be tempted to break each line of the poem into its own paragraph element. This creates hard line breaks, but removes element semantics – a paragraph should be an entire stanza containing multiple lines. It also introduces unnecessary margins and padding between lines.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example 3:&lt;/em&gt; This is the canonical use-case of a line break element &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; – to break up a line without introducing additional semantics. However, looking at the text of the poem we see that lines 5-8 contain indentations that are now stripped from the output.  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example 4:&lt;/em&gt; The preformatted element &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; preserves both line breaks and additional white space characters from the HTML. But the &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; element faithfully preserves all formats and does not allow for text-wrap. This causes overflow for our text, making it better suited for ASCII art and code blocks.&lt;/p&gt;

&lt;p&gt;We've reached the limit of what HTML-only line-breaks can do for us, let's take a look at some CSS options.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS Line Break
&lt;/h2&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/ZErvyQK?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Examples 5 &amp;amp; 6:&lt;/em&gt; The &lt;code&gt;white-space&lt;/code&gt; &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/white-space"&gt;CSS property&lt;/a&gt; is the main corresponding CSS method for controlling line breaks. Interestingly, there is a CSS &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/line-break"&gt;line-break&lt;/a&gt; attribute, but it only deals with how punctuations behave with line-break for East Asian languages.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;white-space&lt;/code&gt; property's &lt;code&gt;normal&lt;/code&gt; and &lt;code&gt;pre&lt;/code&gt; values correspond to the default &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag and &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; tag behavior, respectively.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example 7:&lt;/em&gt; Things start to get interesting when we move on to &lt;code&gt;white-space: pre-line&lt;/code&gt;, where whitespace characters are still collapsed but newline characters now create new lines. Note the indentation from lines 5-8 are still lost, it's as if all new line characters are now treated like &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example 8:&lt;/em&gt; The &lt;code&gt;white-space&lt;/code&gt; value &lt;code&gt;pre-wrap&lt;/code&gt; acts like the &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; element, but also creates new lines so our text does not bleed outside of the parent container. This is the best CSS line break solution we have so far for our Whitman poem use case.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;white-space&lt;/code&gt; has two more potential values. &lt;code&gt;nowrap&lt;/code&gt; disables line breaks and collapses whitespace, and &lt;code&gt;break-spaces&lt;/code&gt; that behaves like &lt;code&gt;pre-wrap&lt;/code&gt; but treats end-of-line spaces without hanging.&lt;/p&gt;

&lt;p&gt;So far, we've looked at solutions that break lines up using whitespace or newline character. What if we want to break a line up in the middle of a word?&lt;/p&gt;

&lt;h2&gt;
  
  
  Word Break
&lt;/h2&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/shimin-zhang/embed/oNEpwYa?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example 9:&lt;/em&gt; The canonical HTML solution for dealing with word-break is the line break opportunity element &lt;code&gt;&amp;lt;wbr&amp;gt;&lt;/code&gt; and its cousin the soft-hyphen &lt;code&gt;­&amp;amp;shy;&lt;/code&gt;. They both indicates to the browser that the location is a preferred location for word-break, but only if the browser deemed a word-break necessary.  &lt;br&gt;
&lt;em&gt;Example 10:&lt;/em&gt; Instead of manually finding all word-break opportunities in your copy, you can use the CSS property &lt;code&gt;word-break&lt;/code&gt; with the value &lt;code&gt;break-all&lt;/code&gt; to let the browser choose when a word should be broken to form a new line. This is akin to automatically inserting &lt;code&gt;&amp;lt;wbr&amp;gt;&lt;/code&gt; after every character.&lt;/p&gt;

&lt;p&gt;_Example 11: La_stly, the CSS property &lt;code&gt;hyphens&lt;/code&gt; with the value &lt;code&gt;auto&lt;/code&gt; can be used to generate browser-determined hyphens for word-break. This is as if we added &lt;code&gt;&amp;amp;shy;&lt;/code&gt; to every non-whitespace character in our text. In my opinion, this option gives us our best poem typeset yet, I especially like how fearful's broken into 'fear-ful' and flows naturally from one line to the next. &lt;code&gt;hyphens: manual&lt;/code&gt; uses the soft hyphen character to insert line breaks instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Word
&lt;/h2&gt;

&lt;p&gt;There you have it, 11 examples of adding line breaks to your text!&lt;/p&gt;

&lt;p&gt;Here are some rules of thumb:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  In general, use CSS line breaks options over their HTML equivalent – separation of concerns between style and content.&lt;/li&gt;
&lt;li&gt;  The exception to the above rule is when the line break is semantic, such as adding &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; tags to indicate typographic line breaks.&lt;/li&gt;
&lt;li&gt;  Another exception is the usage of &lt;code&gt;&amp;amp;shy;&lt;/code&gt; choice of hyphen location is a semantic property of text.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found this post helpful, please share it with others. You may also be interested in learning &lt;a href="https://blog.shimin.io/should-you-use-multiple-h1-s-in-2022/"&gt;if it's acceptable to use multiple H1 elements in 2022&lt;/a&gt; or &lt;a href="https://blog.shimin.io/three-questions-to-ask-when-using-css-px/"&gt;when you should use the px unit for styling&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>html</category>
    </item>
    <item>
      <title>How to Change CSS Styles with JavaScript – From Basic to Advanced Methods</title>
      <dc:creator>Shimin Zhang</dc:creator>
      <pubDate>Fri, 20 May 2022 18:11:27 +0000</pubDate>
      <link>https://dev.to/itstrueintheory/how-to-change-css-styles-with-javascript-from-basic-to-advanced-methods-355p</link>
      <guid>https://dev.to/itstrueintheory/how-to-change-css-styles-with-javascript-from-basic-to-advanced-methods-355p</guid>
      <description>&lt;p&gt;How do you use JavaScript to change CSS styles? This seems like an obvious question with an obvious answer: 'modify your site's stylesheets – potentially followed by a compilation step – then update styles at runtime via changing element attributes such as &lt;code&gt;class&lt;/code&gt; and &lt;code&gt;aria-*&lt;/code&gt;'.&lt;/p&gt;

&lt;p&gt;Yet the answer is not complete, consider the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; How do you update styles at run-time based on user interaction instead of a preset value? It's not feasible to programmatically generate unique class names for every possible color combination.&lt;/li&gt;
&lt;li&gt; What if you do not have modification access to stylesheets or HTML?  Such as a site builder generated site with third-party CSS files littered with &lt;code&gt;!important&lt;/code&gt; properties.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this post, I'll go over 4 methods of style updates using JavaScript and their use cases. We'll also consider each method's usefulness in terms of its &lt;a href="https://blog.shimin.io/understanding-css-complexity/"&gt;CSS Complexity&lt;/a&gt;. That is, how easy is it to understand and modify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Inline Style
&lt;/h2&gt;

&lt;p&gt;Before the invention of CSS, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes"&gt;legacy HTML attributes&lt;/a&gt; such as &lt;code&gt;color&lt;/code&gt;, &lt;code&gt;background&lt;/code&gt;, and &lt;code&gt;border&lt;/code&gt; were used to style web pages. Inline CSS is the spiritual successor of these attributes, where CSS properties are controlled via the element's &lt;code&gt;style&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;The following two ways of changing font size on a hero element are equivalent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hero&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;font-size: 12rem;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hero&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fontSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;12rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using JavaScript to update inline CSS is generally considered bad practice for the following reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; It violates the separation of concerns between style and content, making the document hard to read and modify.&lt;/li&gt;
&lt;li&gt; It removes the ability of CSS selectors to form semantic abstractions.&lt;/li&gt;
&lt;li&gt; Without selectors, updating multiple elements on the page requires iterating through each element – a slow and error-prone process.&lt;/li&gt;
&lt;li&gt; It bloats your HTML via repeated styles.&lt;/li&gt;
&lt;li&gt; It does not have access to pseudo-elements and pseudo-classes that are only available via CSS selectors.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We are currently seeing a resurgence of &lt;em&gt;inline CSS-lite&lt;/em&gt; via atomic CSS frameworks such as Tailwind CSS – see my &lt;a href="https://blog.shimin.io/why-i-dont-use-tailwind-in-production/"&gt;previous posts&lt;/a&gt; on Tailwind. Atomic frameworks use CSS class names that translate to roughly one CSS property and rely on JS generate components to increase style reuse. This overcomes shortcomings 3, 5, and 4 from above – though I think the HTML bloat is still considerable.  &lt;/p&gt;

&lt;p&gt;While inline is CSS generally harmful, it has the benefit of not requiring stylesheet access to make style updates and can be used to make arbitrary run-time style changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to modify inline-CSS&lt;/strong&gt;: Run-time update of a single element style on the page, for quick dev tool tests, and when stylesheet access is unavailable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use HTML Attributes
&lt;/h2&gt;

&lt;p&gt;Next up, we have the canonical answer of modifying element attributes other than style. It is the most popular for a good reason, it does a great job at creating reusable and semantically meaningful styles. Here are some examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// toggles HTML semantic state&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cta&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// a aria based semantic button state &lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cta&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;ariaExpanded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="c1"&gt;// a class based semantic primary variation&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cta&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

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

&lt;/div&gt;



&lt;p&gt;Not much to add here, you are probably both familiar with and use this method extensively. It's both easy to understand and modify, and we have plenty of &lt;a href="https://2020.stateofcss.com/en-US/technologies/methodologies/"&gt;CSS methodologies&lt;/a&gt; to control its complexity.&lt;/p&gt;

&lt;p&gt;I do want to point out that the examples above listed are in their order of meaningfulness. We should give precedence to HTML attribute-based states before leaning on class-based states – easier now that &lt;code&gt;:has()&lt;/code&gt; selector is on the horizon.&lt;/p&gt;

&lt;p&gt;The only downsides of the method are the two I mentioned in the introduction: that it is not possible to generate all arbitrary CSS styles ahead of time, and you need to be able to modify all stylesheets on the site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to modify (non-style) attributes:&lt;/strong&gt; all cases when you have access to stylesheets and have pre-defined styles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use CSSOM
&lt;/h2&gt;

&lt;p&gt;The next method for JavaScript-based CSS modification is the surgical knife of the front-end toolkit: directly modifying CSS stylesheet objects. While the previous two methods modify the HTML DOM to affect the style, in some instances it is easier to directly change the CSS Object Model (CSSOM) instead.&lt;/p&gt;

&lt;p&gt;By accessing the document's &lt;code&gt;styleSheets&lt;/code&gt; object, we can make arbitrary changes to a site's styles with the full power of CSS. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;thirdPartyStylesheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;styleSheets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="c1"&gt;//index 15 rule color: red !important;&lt;/span&gt;
&lt;span class="nx"&gt;thirdPartyStylesheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleteRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can even add new dynamically generated stylesheets to the site via the &lt;code&gt;CSSStyleSheet&lt;/code&gt; &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet"&gt;constructor&lt;/a&gt;. In my experience, this is the best way to deal with third-party CSS stylesheets or site builders with limited CSS capabilities.&lt;/p&gt;

&lt;p&gt;The CSSOM approach avoids the dreaded CSS selector escalation where you litter inline style with &lt;code&gt;!important&lt;/code&gt; to override third-party styles. It can also be more performant than looping through multiple elements to dynamically update their styles.&lt;/p&gt;

&lt;p&gt;The main drawback of the CSSOM approach is how difficult it is to understand and debug. Dev-tool support for modified CSSOM is lacking and unless documented in 24-point font, it can drive future maintainers crazy. Like a surgical knife, use it sparingly and provide plenty of warning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to modify CSSOM&lt;/strong&gt;: best used to remove unwanted third-party styles instead of adding new styles, good for changing styles you have no control over.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use CSS Custom Properties
&lt;/h2&gt;

&lt;p&gt;The last approach for dynamically updating CSS styles is through CSS custom properties. Though it technically does not use any new APIs, using custom properties is sufficiently different from the previous approaches that it deserves mentioning.&lt;/p&gt;

&lt;p&gt;The custom properties can be used with any of the previous methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;themeColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;color-picker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// use with inline style&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;`--theme-color: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;themeColor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// use in CSSOM&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stylesheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;styleSheets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;stylesheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;insertRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`:root { --theme-color: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;themeColor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;; }`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

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

&lt;/div&gt;



&lt;p&gt;An element's CSS custom properties are inherited by its children. We can use them with inline styles and not worry about selecting and looping through all elements in DOM – we just need to find their shared ancestor. Because of this, custom properties can also be used to modify pseudo-elements with inline style.&lt;/p&gt;

&lt;p&gt;The biggest downside of using custom properties is they require planning and stylesheet access. When used judiciously, they can modify multiple styles with a single style update, such as &lt;a href="https://css-tricks.com/creating-color-themes-with-custom-properties-hsl-and-a-little-calc/"&gt;generating an entire color palette with one color update&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Compare to the previous approaches, custom properties require as much if not more planning than the element attribute approach, but can be used for run-time style updates. It's easier to maintain than the CSSOM approach– there are fewer changes to keep track of – but you need stylesheet access.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use CSS Custom Properties&lt;/strong&gt;: When you need to make complex run-time style changes, when you want to create new relationships between styles properties, or when you need to pierce the Shadow DOM to style lots of web components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take-Aways
&lt;/h2&gt;

&lt;p&gt;Next time you need to change CSS style via Javascript, ask yourself:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Is this a pre-defined style update or is its value determined dynamically at run-time?&lt;/li&gt;
&lt;li&gt; Am I overriding an existing third-party style?&lt;/li&gt;
&lt;li&gt; Do I need to modify a single element, or multiple ones on the page, including pseudo-elements and classes?&lt;/li&gt;
&lt;li&gt; Do I want this change to affect multiple derived properties, or shared by multiple elements on the page?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Front-end development is evolving quicker than ever and with no signs of slowing down. It's helpful to periodically slow down and take a look at all the tools available in our front-end toolkit.&lt;/p&gt;

&lt;p&gt;And speaking of new tools, I am especially looking forward to learning and using typed style properties through the &lt;a href="https://web.dev/css-props-and-vals/"&gt;Houdini custom properties API&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>css</category>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>The Unreasonable Effectiveness of the To-do List – Zeigarnik Effect and Developer Productivity</title>
      <dc:creator>Shimin Zhang</dc:creator>
      <pubDate>Fri, 13 May 2022 17:05:29 +0000</pubDate>
      <link>https://dev.to/itstrueintheory/the-unreasonable-effectiveness-of-the-to-do-list-zeigarnik-effect-and-developer-productivity-378o</link>
      <guid>https://dev.to/itstrueintheory/the-unreasonable-effectiveness-of-the-to-do-list-zeigarnik-effect-and-developer-productivity-378o</guid>
      <description>&lt;p&gt;I touched on the business cost of context switching in &lt;a href="https://blog.shimin.io/the-business-case-for-fewer-developer-meetings/"&gt;last week's post&lt;/a&gt;. This week, I want to dig deeper into a hidden cost of context switching: the cognitive costs of unfinished tasks.&lt;/p&gt;

&lt;p&gt;Ever notice you are more effective when working on one project at a time instead of juggling multiple projects concurrently?&lt;/p&gt;

&lt;p&gt;Do you have multiple meetings in the day so you are constantly stressed about what to do next and unable to focus?&lt;/p&gt;

&lt;p&gt;In a more general form, do work-related thoughts intrude into your non-working hours?&lt;/p&gt;

&lt;p&gt;I'm an anxious person by nature. Learning about the &lt;a href="https://en.wikipedia.org/wiki/Zeigarnik_effect"&gt;Zeigarnik Effect&lt;/a&gt; and how it shapes my mental capacity has been a productivity and mental health game-changer. While I am not a 'productivity expert', I want to document how I deal with the cognitive cost of juggling multiple unfinished tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Zeigarnik Effect
&lt;/h2&gt;

&lt;p&gt;The Zeigarnik Effect states that an uncompleted task has an associated cognitive overhead. The task will periodically demand our attention and drains our mental resources until it is completed.  &lt;/p&gt;

&lt;p&gt;The effect is named after the Russian psychologist Bluma Zeigarnik. While on vacation in 1923, Zeigarnik noticed the same restaurant server who previously remembered the entire table's orders did not recognize her when she went back to fetch her forgotten purse – merely minutes after the table finished paying.&lt;/p&gt;

&lt;p&gt;Inspired by this realization, Zeigarnik later performed a series of experiments to confirm that we keep a 'cognitive cache' for any uncompleted tasks, making their context easily retrievable. Later studies confirm her initial hypothesis, though with the caveat that this cognitive penalty only occurs when we do not have a well-formed plan on how to complete the tasks. See &lt;a href="https://doi.apa.org/doiLanding?doi=10.1037%2Fa0024192"&gt;Masicampo 2011&lt;/a&gt; on how plan making can eliminate the negative cognitive effects of unfinished tasks.&lt;/p&gt;

&lt;p&gt;The Zeigarnik Effect partly explains why we have trouble constantly context-switching and juggling multiple projects. Each unfinished task drains our mental capacity and reduces our ability to focus – that is, until they are 'garbage collected'. According to this &lt;a href="https://doi.apa.org/doiLanding?doi=10.1037%2Fa0037127"&gt;2020 study,&lt;/a&gt; unfinished work tasks can lead to excess rumination and negatively affect our sleep quality – even on the weekends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dealing with Unfinished Tasks
&lt;/h2&gt;

&lt;p&gt;My number one tool for dealing with the Zeigarnik Effect is the humble text-based to-do list. Specifically, I use a single page of the macOS Notes app to keep all my work-related to-dos.&lt;/p&gt;

&lt;p&gt;If I'm in the middle of a task and have to context switch to a meeting or bug intake, I chunk the unfinished portion of the task into a new to-do list item and add it to the front of the queue. Whenever a new task comes up during a meeting, I translate it into an actionable item – even if it's as simple as a 'ping X to confirm Y'.&lt;/p&gt;

&lt;p&gt;I rearrange the to-do list periodically based on priority – oftentimes multiple times a day – so I always have a rough plan of attack for the next few business days. And because the tasks are in actionable form, they do not drain my attention the same way a list of unknowns would. This allows me to focus deeply on the task at hand.&lt;/p&gt;

&lt;p&gt;I first came across the benefits of this approach when I read David Allen's &lt;a href="https://en.wikipedia.org/wiki/Getting_Things_Done"&gt;Getting Things Done&lt;/a&gt;. As part of the GTD workflow, I wrote down goals that captured my attention and clarified the actionable steps needed to achieve them. The simple act of writing actionable steps towards a goal down and putting them away provided immediate and immense stress relief.&lt;/p&gt;

&lt;p&gt;Why do I use a text to-do list when Jira tickets, Trello boards, and Gitlab issues are available? Because it is easy – which epic and milestone should I tie 'ping Sarah about the checkout workflow copy' to? Plus, small tasks that do not merit an entire Jira ticket will still drain your mental resources – so they are added to the list regardless of size. If the list gets uncomfortably long overtime, sharpen your machete and remove the lowest priority items – anything that's truly important will resurface later – another tactic I borrowed from Getting Things Done.&lt;/p&gt;

&lt;p&gt;Meditation's another tool that helped me deal with the negative aspects of the Zeigarnik Effect. I try to meditate between 5-10 minutes a day – it's the garbage collection process for my mental health. Any unfinished tasks occupying my mind will surface to the conscious mind during meditation. I can either make a quick plan to deal with it and file it away mentally or physically  – or failing at that, meditation is the daily practice of not being so easily distracted by them.&lt;/p&gt;

&lt;p&gt;The last thing I do to shield myself from the Zeigarnik effect is I always choose to stop coding after finishing a milestone instead of leaving code half-finished. While some developers swear by finishing the day mid-code – so they can easily jump in the next day – I find the practice causes work to bleed into my personal life. If forced to, I add a 'fix failing tests' to the top of the to-do pile before switching to something else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Word
&lt;/h2&gt;

&lt;p&gt;I first came across the term Zeigarnik Effect in Kathy Sierra's &lt;a href="https://www.oreilly.com/library/view/badass-making-users/9781491919057/"&gt;Badass: Making Users Awesome&lt;/a&gt;. While I mostly wrote about its detrimental effects in this post, you can also use it to help you perform your best – see &lt;a href="https://link.springer.com/chapter/10.1007/978-3-030-46463-9_10#Bib1"&gt;this article&lt;/a&gt; on how professional athletes use the Zeigarnik Effect to reduce performance anxiety.  &lt;/p&gt;

&lt;p&gt;Here are the key take ways points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Interrupted and unfinished tasks will drain your mental resources, leading to &lt;em&gt;stress and poor performance&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;  You can &lt;em&gt;eliminate&lt;/em&gt; the negative effects of unfinished tasks through &lt;em&gt;plan-making&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;  The act of turning unfinished thoughts and tasks into &lt;em&gt;concrete next steps&lt;/em&gt; – such as a to-do list – can be a quick and effective way to combat the Zeigarnik Effect.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found this post helpful, please share it with others. You may also be interested in learning about &lt;a href="https://blog.shimin.io/interview-questions-for-fake-agile-teams/"&gt;how to spot 'Fake Agile' teams during interviews&lt;/a&gt; or &lt;a href="https://blog.shimin.io/bloom-taxomony-and-front-end-skill-development/"&gt;using Bloom's Taxonomy for faster skill development&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have any tips on how you deal with the Zeigarnik Effect, leave a comment below or ping me on Twitter &lt;a href="https://twitter.com/ItsTrueInTheory"&gt;@ItsTrueInTheory&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>career</category>
    </item>
    <item>
      <title>Why a Meeting Costs More than a MacBook Pro – the Business Case for Fewer Developers in Meetings</title>
      <dc:creator>Shimin Zhang</dc:creator>
      <pubDate>Fri, 06 May 2022 15:37:52 +0000</pubDate>
      <link>https://dev.to/itstrueintheory/why-a-meeting-costs-more-than-a-macbook-pro-the-business-case-for-fewer-developers-in-meetings-1cll</link>
      <guid>https://dev.to/itstrueintheory/why-a-meeting-costs-more-than-a-macbook-pro-the-business-case-for-fewer-developers-in-meetings-1cll</guid>
      <description>&lt;p&gt;Developers are famous for disdaining meetings. Meetings force us to context switch, kill our flow, and sap our job satisfaction long term. Yet, managers and scrum masters can't seem to get enough of them, and the resulting tension is all over our calendars. Paul Graham (internet) famously documented this phenomenon in his essay &lt;a href="http://www.paulgraham.com/makersschedule.html"&gt;Maker's Schedule, Manager's schedule&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Large organizations are especially known for overstuffing developer calendars with pointless meetings – at least pointless to developers. And when a scrum master goes rogue, a dev can have days when nothing of actual value gets done between retros, sprint plannings, demos, and process alignments.&lt;/p&gt;

&lt;p&gt;I sat through a particularly useless meeting the other week with a meeting screen full of other devs – oddly, it was initiated by a tech lead on a different team. During the boredom, I started wondering :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  How can we make a business case for fewer pointless meetings on our calendars?&lt;/li&gt;
&lt;li&gt;  How can we add more value to the meetings we attend?&lt;/li&gt;
&lt;li&gt;  How can we have fewer meetings of the pointless kind and more of the value-added kind?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Opportunity Cost
&lt;/h2&gt;

&lt;p&gt;I was an accountant in my previous life, so I want to put a number on exactly how much a meeting can cost. Here's my ballpark calculation of the &lt;a href="https://en.wikipedia.org/wiki/Opportunity_cost"&gt;opportunity cost&lt;/a&gt; of a meeting for the company, regardless of whether it is pointless.&lt;/p&gt;

&lt;p&gt;Here are my assumptions: these are US-centric, adjust for your local market conditions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The meeting is &lt;em&gt;1 hour long&lt;/em&gt;, involving a PM and a team of &lt;em&gt;4 developers&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;  The developers have an average total compensation of &lt;em&gt;$200,000 and 2 Weeks of PTO.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  On average, an employee costs an employer &lt;em&gt;1.5X their compensation&lt;/em&gt; in other benefits.&lt;/li&gt;
&lt;li&gt;  An average developer is in a maximally productive flow-state on average between 4-6 hours per day, we'll use &lt;em&gt;5 hours&lt;/em&gt; for our calculation.&lt;/li&gt;
&lt;li&gt;  The business value-added per developer is &lt;em&gt;80% from flow state&lt;/em&gt; and &lt;em&gt;20% from non-flow state&lt;/em&gt; following the &lt;a href="https://en.wikipedia.org/wiki/Pareto_principle"&gt;Pareto principle&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  This is a badly scheduled meeting in an organization with too many meetings already – cutting into flow state time. Each developer on average &lt;em&gt;wastes 30 minutes before and after&lt;/em&gt; the meeting to context switch and the time is otherwise non-value adding. (See &lt;a href="https://www.researchgate.net/publication/317989659_Impact_of_task_switching_and_work_interruptions_on_software_development_processes#pf2"&gt;this study&lt;/a&gt; for the cost of context switching).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using these assumptions, we see that each developer's inflow state per hour costs to the company is &lt;em&gt;($200,000 * 1.5 * 0.8) / ((52-2) * 5 * 5) =&lt;/em&gt; &lt;strong&gt;&lt;em&gt;$192&lt;/em&gt;&lt;/strong&gt; per 'flow hour'.&lt;/p&gt;

&lt;p&gt;At a cost of 2 hours in 'flow hours' per developer and 4 developers in this meeting, the meeting's developer opportunity cost is &lt;em&gt;&lt;strong&gt;$1536&lt;/strong&gt;&lt;/em&gt;. The meeting's opportunity cost is higher than the price of a brand-new &lt;a href="https://www.apple.com/shop/buy-mac/macbook-pro/13-inch"&gt;M1 MacBook Pro&lt;/a&gt;. If the meeting was pointless, might as well cancel it and fly one of the devs to Bali instead.&lt;/p&gt;

&lt;p&gt;In my experience, corporations with the most meetings are often also stingiest with dev equipment and educational/training expenses – a classic case of penny wise and pound foolish.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--49B0_AzP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wf0ssvxh68w50y1kvzt5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--49B0_AzP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wf0ssvxh68w50y1kvzt5.jpg" alt="a sea turtle swimming" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What you could be looking at instead of your PM's screen with his favorite spreadsheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Value-Added Meetings
&lt;/h2&gt;

&lt;p&gt;Because of my accountant tendencies – and because I used to be a freelancer – I try my best to make sure I add enough business value to every meeting to justify my presence. Politics aside, it actually makes me feel a bit bad to only sit in on one. I hate wasting my time.&lt;/p&gt;

&lt;p&gt;Value-added can be everything from providing actual technical perspective and expertise to simply keeping everyone on track. Cutting a 15-minute detour in an 8 developer meeting is enough value added to justify attending. Of course, it's even better if you cut the meeting short when it's going nowhere, or suggest it be canceled, to begin with.&lt;/p&gt;

&lt;p&gt;An even better way to get value from a meeting – especially for senior devs and tech leads – is to attend for the rest of the team and write a one-page summary that can be consumed at the rest of the team's leisure.&lt;/p&gt;

&lt;p&gt;Take the meeting from the previous section: A senior dev hashed out the issue with the PM one on one and spends an extra 30 minutes post-meeting summarizing the key points learned and decisions made. The senior dev just added $1500 worth of business value in an hour and a half of work – a real force multiplier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Have Better Meetings
&lt;/h2&gt;

&lt;p&gt;I'm by no means a meeting expert (nor do I really wish to become one), but here are some meeting tips that work well for me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Batching meetings&lt;/strong&gt;: When possible, reschedule meetings to right around my team's daily standup and at the end of the day when I'm ready for a mental break. I try to keep the 11 am-4 pm block of my day free. Bonus point: the best way to batch meetings is to skip them.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Have an agenda&lt;/strong&gt;: This is meeting 101 stuff, but it is too often ignored. Have the action items and desired meeting results spelled out ahead of time, this allows you to cut them short once a decision is made. Bonus point: be the guy who says 'sounds like we finished everything on the agenda, shall we call it?'.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Separate the async from the sync&lt;/strong&gt;&lt;em&gt;:&lt;/em&gt; You wouldn't block the main JS thread with functions that can be resolved asynchronously, so why block a synchronous meeting going over information that can be provided via email and read whenever? Bonus point: sometimes the act of writing down the context turns a meeting into an email or slack poll.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Word
&lt;/h2&gt;

&lt;p&gt;Skip more meetings, make a case that the shareholders aren't paying you hundreds of dollars an hour to listen – that could get through the MBA types.&lt;/p&gt;

&lt;p&gt;Manage your meetings, and crush the ones you choose to attend. Be a force multiplier and your team will thank you for your leadership.&lt;/p&gt;

&lt;p&gt;If you found this post helpful, please share it with others. You may also be interested in learning about &lt;a href="https://blog.shimin.io/are-code-reviews-crippling-your-delivery-process-how-categorizing-your-code-review-comments-can-speed-things-up/"&gt;How an MR comment hierarchy can Speed Up Delivery&lt;/a&gt; or &lt;a href="https://blog.shimin.io/afraid-your-technical-discussion-is-hurting-team-morale-heres-a-principle-to-keep-in-mind-during-technical-disagreements/"&gt;Use 'Disagree and Commit' to get through technical disagreements&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have any tips for the community about better meetings, leave a comment below or ping me on Twitter &lt;a href="https://twitter.com/ItsTrueInTheory"&gt;@ItsTrueInTheory&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>career</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Got Messy Spaghetti Stylesheets? 4 Techniques for Managing CSS Complexity</title>
      <dc:creator>Shimin Zhang</dc:creator>
      <pubDate>Fri, 29 Apr 2022 19:31:58 +0000</pubDate>
      <link>https://dev.to/itstrueintheory/got-messy-spaghetti-stylesheets-4-techniques-for-managing-css-complexity-581d</link>
      <guid>https://dev.to/itstrueintheory/got-messy-spaghetti-stylesheets-4-techniques-for-managing-css-complexity-581d</guid>
      <description>&lt;p&gt;Last week, I wrote about &lt;a href="https://blog.shimin.io/understanding-css-complexity/"&gt;the definition of CSS complexity&lt;/a&gt; and how CSS features have inherent complexity – that is, complexity outside of a web designer's control.&lt;/p&gt;

&lt;p&gt;This week, I want to take a look at some tried and true techniques for unwinding your spaghetti CSS. The techniques are covered in their general form – with links to framework level implementation examples.&lt;/p&gt;

&lt;p&gt;This is not a 'list of CSS methodologies' post – there are enough of those. Nor will I try to convince you to use 'The One Framework / Process' – every team is different and every project's needs are unique.&lt;/p&gt;

&lt;p&gt;My goal for this post is to provide a few metrics to analyze CSS technologies, which will hopefully help you (and myself) choose the right one for a new project.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Complexity Recap
&lt;/h3&gt;

&lt;p&gt;Here's a quick summary of CSS complexity:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;CSS complexity is anything related to the CSS of a project that makes it hard to understand and modify.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;CSS complexity shows up in 3 forms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Change Amplification&lt;/em&gt;: making a style change require multiple edits.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;High Cognitive load&lt;/em&gt;: a large amount of context is needed to make a change_._&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Unknown unknowns:&lt;/em&gt; when it is not clear where to make a change.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok, on to the techniques!&lt;/p&gt;

&lt;h3&gt;
  
  
  Limit Selector Combination
&lt;/h3&gt;

&lt;p&gt;One of the biggest source of CSS complexity is selector explosion and the resulting specificity escalation – where an &lt;code&gt;n&lt;/code&gt;th level element with a single class on the page has &amp;gt;&lt;code&gt;2^n&lt;/code&gt; possible combination of potential class based selectors. CSS's machine friendly specificity score calculations only adds to this problem. (See example from &lt;a href="https://blog.shimin.io/understanding-css-complexity/"&gt;last post&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;This problem affects all 3 symptoms of complexity: In order to make a style change, you now have to remember all selectors targeting the element (&lt;em&gt;high cognitive load&lt;/em&gt;) track down the right ones (&lt;em&gt;unknown unknowns&lt;/em&gt;), and potentially change multiple files (&lt;em&gt;change amplification&lt;/em&gt;),&lt;/p&gt;

&lt;p&gt;Because this is a foot-gun, all CSS frameworks and best practices &lt;strong&gt;&lt;em&gt;imposes limits to the selector space&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;.&lt;/em&gt; The the advice 'don't use elements in your selectors' as an example, it removes a substantial subsets of potential selectors.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Framework examples&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://tailwindcss.com/"&gt;Tailwind&lt;/a&gt; sticks to a single level of class based specificity – not including normalizing CSS.&lt;/li&gt;
&lt;li&gt;  &lt;a href="http://getbem.com/introduction/"&gt;Block Element Modifier (BEM)&lt;/a&gt; takes a similar approach and recommends against using &lt;a href="http://getbem.com/faq/"&gt;combined selector for variations&lt;/a&gt; – limiting selector space to class based selectors with at most 2 levels.&lt;/li&gt;
&lt;li&gt;  &lt;a href="http://smacss.com/"&gt;Scalable and Modular Architecture for CSS (SMACSS)&lt;/a&gt; does not restrict selector type, instead opting for limiting depth. It allows for layout ids and modules can potentially &lt;a href="http://smacss.com/book/type-module"&gt;double up on class selectors&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  The example of never using elements in your selector came from &lt;a href="https://www.slideshare.net/stubbornella/object-oriented-css"&gt;Object Oriented CSS (OOCSS)&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exact number of allowed selectors isn't as important as the need to have a principled way to limit selector depth.&lt;/p&gt;

&lt;p&gt;The difficulty of limiting selectors is it needs to be both documented and enforced. It's easy to slip up when 'design needs this change done yesterday'.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reduce Property Overlap
&lt;/h3&gt;

&lt;p&gt;Source order is another major source (sorry) of CSS complexity. The same component on different pages might have different styles due to different import orders – especially if selector specificity is flattened.&lt;/p&gt;

&lt;p&gt;This leads to both &lt;em&gt;unknown unknowns&lt;/em&gt; (which file to change?) and high &lt;em&gt;cognitive load&lt;/em&gt; (remember to always include &lt;code&gt;foo.css&lt;/code&gt; before &lt;code&gt;bar.css&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The best way to combat this is &lt;em&gt;&lt;strong&gt;ensuring overlapping selectors do not overlap in CSS properties&lt;/strong&gt;&lt;/em&gt;. And if they have to overlap, make sure their relative specificity is unambiguous.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Framework examples&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Atomic frameworks like &lt;a href="https://acss.io/"&gt;Atomic CSS&lt;/a&gt; and Tailwind takes a single purpose approach to selectors, so CSS properties are naturally never overlapping – this is also why Tailwind's &lt;code&gt;@apply&lt;/code&gt; is an anti-pattern when overused.&lt;/li&gt;
&lt;li&gt;  BEM is &lt;a href="http://getbem.com/faq/#can-i-create-global-modifier"&gt;against global modifiers&lt;/a&gt; for this reason also, and modifier styles should always be declared after the block.&lt;/li&gt;
&lt;li&gt;  When global utilities are encouraged, as is the case with &lt;a href="https://itcss.io/"&gt;ITCSS&lt;/a&gt;, utility classes are encouraged to have &lt;code&gt;!important&lt;/code&gt; applied to all values. So the property value is always clear.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://cube.fyi/"&gt;CUBE CSS&lt;/a&gt; gets around to this problem by &lt;a href="https://cube.fyi/composition.html#why-macro-level-thinking"&gt;separating layer concerns from visual properties&lt;/a&gt;. Layout classes and blocks should not share properties.  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When not using a utility first approach, it can be difficult to keep track of all classes' overlapping properties in a project. I think this is an area with a need for better tooling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Restrict Selector Scope
&lt;/h3&gt;

&lt;p&gt;CSS is global in scope – at least pre &lt;a href="https://css-tricks.com/css-cascade-layers/"&gt;cascade layers&lt;/a&gt;. As with code, global CSS leads to name conflicts in large projects. When creating a new component, you need to keep in mind every class name used in the project along with potential 3rd-party classes.&lt;/p&gt;

&lt;p&gt;This imposes a &lt;em&gt;cognitive load&lt;/em&gt; penalty that scales with the size of the project and the number of developers working on it.&lt;/p&gt;

&lt;p&gt;The solution to this problem is the same as in programming, you &lt;em&gt;&lt;strong&gt;reduce selector scope to eliminate possibility of collision&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Framework examples:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Component based CSS frameworks originating with &lt;a href="https://github.com/stubbornella/oocss/wiki"&gt;OOCSS&lt;/a&gt; inherently limits selector scope to only elements inside the 'CSS object'.&lt;/li&gt;
&lt;li&gt;  ITCSS / BEMIT introduces a &lt;a href="https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/"&gt;Hungarian notation of class names&lt;/a&gt; to aid in reading – this reduces cognitive load when reading CSS.&lt;/li&gt;
&lt;li&gt;  Taking the idea to somewhat of an extreme, &lt;a href="https://github.com/css-modules/css-modules"&gt;CSS modules&lt;/a&gt; explicitly makes all CSS locally scoped by default.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's not much downside to limiting CSS scope, although when taken too far you'll end up with larger stylesheets than needed. You can prevent this through planning out sensible global default styles, I especially like CUBE CSS's approach to &lt;a href="https://cube.fyi/css.html"&gt;progress enhancement&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Style Colocation
&lt;/h3&gt;

&lt;p&gt;The last problem I want to take a look at is the inherent complexity of using class name based CSS hooks.&lt;/p&gt;

&lt;p&gt;Image you have a large, existing e-commerce site. One day, your designer asks you to add a purple decorator to female gendered product category headings and another for male ones. Assuming this was not an abstraction previously included in your site's markup, now you need to come up with a semantic and non clashing class name for gendered heading variation. Then you need to update the code that generates the reusable heading template to add logic for &lt;code&gt;heading--male&lt;/code&gt; and &lt;code&gt;heading--female&lt;/code&gt;. &lt;em&gt;Side Note: there are lots of other ways to do this, but for this example I'm limiting it to a BEM modifier.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In my opinion, this is 'play-pretend separation of concerns', a style-only update now triggers a 'semantic' html rabbit hole. I'm not the only one to feel this way, I first came across a clear description of this problem in this &lt;a href="https://adamwathan.me/css-utility-classes-and-separation-of-concerns/"&gt;Adam Wathan post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This pattern leads to &lt;em&gt;change amplification and unknown unknowns&lt;/em&gt;, you have to find the right HTML template and its corresponding CSS file, make the same modification in both places at the same time, and if you make a typo in either case, check two files to find it.&lt;/p&gt;

&lt;p&gt;This problem is best mitigated by &lt;strong&gt;placing style information right next to HTML templates&lt;/strong&gt;. This way, even if you have to invent a new 'semantic classname', you at least can do it in the same file.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Framework examples:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Some leave out style hook class names all together, instead use aria attribute and semantic HTML elements to separate style from markup. See this &lt;a href="https://www.smashingmagazine.com/2012/06/classes-where-were-going-we-dont-need-classes/"&gt;Heydon Pickering Smashing Magazine Article&lt;/a&gt; and &lt;a href="https://ecss.benfrain.com/chapter6.html"&gt;Enduring CSS chapter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  Atomic approaches (&lt;a href="https://www.smashingmagazine.com/2013/10/challenging-css-best-practices-atomic-approach/"&gt;ACSS&lt;/a&gt;, &lt;a href="https://tailwindcss.com/docs/utility-first"&gt;Tailwind&lt;/a&gt;) get around this by using only style based hooks, reading the class is looking at its style – no need to cross reference.&lt;/li&gt;
&lt;li&gt;  CSS-in-JS category of tooling (&lt;a href="https://cssinjs.org/?v=v10.9.1-alpha.2"&gt;JSS&lt;/a&gt;, &lt;a href="https://styled-components.com/"&gt;Styled-Components&lt;/a&gt;, etc.) does 'inline++' styling, which also has the added benefit of placing style information right next to template.&lt;/li&gt;
&lt;li&gt;  Lastly, JS frameworks like &lt;a href="https://vue-loader.vuejs.org/guide/scoped-css.html"&gt;Vue&lt;/a&gt; and &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt; provide an all in one experience, where template, style, and functionality all live in the same file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The largest drawback of this approach is it violates the traditional concept of separate JS, CSS and HTML files, each responsible for its own domain of the web experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Take Aways
&lt;/h3&gt;

&lt;p&gt;Next time you read about 'the next big CSS paradigm', you can map its features to one of the general techniques above. And if you are looking to create your own CSS workflow / framework, I hope you will take these general patterns into your consideration.&lt;/p&gt;

&lt;p&gt;I finished the initial draft of this post feeling like I've only made a dent in the topic – serves me right for trying to cover an area as broad as 'how make CSS less complex'. So please let me know if I've missed one – or a dozen – of your favorites. Leave a comment below or ping me on Twitter &lt;a href="https://twitter.com/ItsTrueInTheory"&gt;@ItsTrueInTheory&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why Your CSS is Always Messy and Chaotic – Understanding CSS Complexity</title>
      <dc:creator>Shimin Zhang</dc:creator>
      <pubDate>Fri, 22 Apr 2022 16:14:02 +0000</pubDate>
      <link>https://dev.to/itstrueintheory/why-your-css-is-always-messy-and-chaotic-understanding-css-complexity-3o94</link>
      <guid>https://dev.to/itstrueintheory/why-your-css-is-always-messy-and-chaotic-understanding-css-complexity-3o94</guid>
      <description>&lt;p&gt;Does the thought of making a minor style update in a large front-end project give you pause? It does for me. It can be especially hard when I'm modifying a project written by another team, even if the change is small.&lt;/p&gt;

&lt;p&gt;Somehow, CSS stylesheets (preprocessed or otherwise) are always a jumbled mess of classes and ids. Why is it common to have clean JS/Python/PHP code and spaghetti CSS in the same code base?&lt;/p&gt;

&lt;p&gt;This week, I want to take a look at what makes CSS complex, using the ontology of software complexity from John Ousterhout's excellent book &lt;a href="https://web.stanford.edu/~ouster/cgi-bin/book.php"&gt;A Philosophy of Software Design&lt;/a&gt;. This post sets the table for why CSS gets so messy – before we dig into design patterns and solutions next week.&lt;/p&gt;

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

&lt;p&gt;Let's start off with a complexity definition. From &lt;em&gt;A Philosophy of Software Design&lt;/em&gt;: "Complexity is anything related to the structure of a software system that makes it hard to understand and modify the system.".&lt;/p&gt;

&lt;p&gt;This definition fits CSS quite well. Complex CSS is hard to understand and harder to modify – obligatory &lt;a href="https://twitter.com/thomasfuchs/status/493790680397803521"&gt;link to the CSS stool joke&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ousterhout also points out three symptoms of complexity that make a piece of code hard to work with:&lt;/p&gt;

&lt;h3&gt;
  
  
  Change Amplification
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Change amplification&lt;/em&gt; occurs when a seemingly simple change requires changes in multiple places.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example in CSS land:&lt;/em&gt; you are tasked with changing all paragraph text colors on a website from black to navy. With a simple HTML page, it's as simple as a one-line &lt;code&gt;p { color: navy; }&lt;/code&gt;. On a large project, you spend the whole day defeating the highest specificity that applies to all &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; elements on all pages – only to discover the checkout gadget's shipping confirmation modal has a paragraph element that somehow inherited text color from the teal heading.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cognitive Load
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Cognitive load&lt;/em&gt; is the amount of information a developer needs to keep in mind in order to make a change.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example in CSS land:&lt;/em&gt; You are asked to change the &lt;code&gt;font-size&lt;/code&gt; of the hero section CTA button on large viewports from 20px to 22px. Here's a list of information you may have to keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Default body &lt;code&gt;font-size&lt;/code&gt; from user agent stylesheets.&lt;/li&gt;
&lt;li&gt;  Existing button &lt;code&gt;font-size&lt;/code&gt; for small and medium viewports.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;font-size&lt;/code&gt; of hero section text because the &lt;code&gt;em&lt;/code&gt; unit seems like a good fit.&lt;/li&gt;
&lt;li&gt;  Maybe we use &lt;code&gt;rem&lt;/code&gt; instead, does the project use the standard &lt;code&gt;16px&lt;/code&gt; rem size or &lt;code&gt;10px&lt;/code&gt; rem size for ease of calculation?&lt;/li&gt;
&lt;li&gt;  Potential hero section variation of the button and its &lt;code&gt;font-size&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Any &lt;code&gt;font-size&lt;/code&gt; utility classes the project may have.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Unknown Unknowns
&lt;/h3&gt;

&lt;p&gt;You face &lt;em&gt;unknown unknowns&lt;/em&gt; when it is not obvious where to get the information needed to complete a task, or where to make the necessary change.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example in CSS land:&lt;/em&gt; You are changing the error message color for a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; element in a login widget on the category page. Do you make the change in &lt;code&gt;utilities.css&lt;/code&gt;, &lt;code&gt;form.css&lt;/code&gt;, &lt;code&gt;widget.css&lt;/code&gt;, &lt;code&gt;login.css&lt;/code&gt;, &lt;code&gt;category.css&lt;/code&gt;, or &lt;code&gt;index.css&lt;/code&gt;? Depending on your project's CSS methodology, this could be a component variation, a new component, or a new utility class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CSS gets Complex
&lt;/h2&gt;

&lt;p&gt;Next, let's take a look at different technical causes of CSS complexity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Selector Space
&lt;/h3&gt;

&lt;p&gt;While CSS properties belong to a single matched element at a time, CSS selectors are matched against all elements in the DOM. So, as a project grows in size and the number of total selectors – both actual and potential – grows, we have a natural increase in CSS complexity.&lt;/p&gt;

&lt;p&gt;The total number of CSS properties in the DOM grows linearly with DOM size – a page with &lt;code&gt;n&lt;/code&gt; total elements at &lt;code&gt;x&lt;/code&gt; properties per element have at most &lt;code&gt;nx&lt;/code&gt; total adjustable properties.&lt;/p&gt;

&lt;p&gt;On the other hand, the size of the set of potential selectors grows exponentially with respect to DOM depth. Assume using only a single class per element, a &lt;code&gt;m&lt;/code&gt; level deep DOM element has &lt;code&gt;2^m&lt;/code&gt; number of applicable class-based selectors.&lt;/p&gt;

&lt;p&gt;Since the total number of potential selectors grows exponentially on large projects, it impacts both cognitive load and change amplification – to understand and modify its implemented subset.&lt;/p&gt;

&lt;p&gt;If &lt;em&gt;you ever wondered why front-end developers spend so much time tinkering with and cursing at CSS selectors, it's because the selector solution space for any given change is HUGE.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Specificity
&lt;/h3&gt;

&lt;p&gt;In my experience, there's no quicker road to unmanageable CSS than "specificity escalation". Because any moderately complex project will have a huge set of potential selectors for each change, and because CSS selector specificity score is additive in nature, a project's average CSS selector specificity tends to increase as it grows.&lt;/p&gt;

&lt;p&gt;As Chris Coyier pointed out in this answer about &lt;a href="https://www.smashingmagazine.com/2012/07/coding-qa-with-chris-coyier-code-smell-type-grid/"&gt;CSS code smell&lt;/a&gt;, when you see a selector like &lt;code&gt;#articles .comments ul &amp;gt; li &amp;gt; a.button&lt;/code&gt; in your dev tools, it's already too late.  &lt;/p&gt;

&lt;p&gt;Specificity-related complexity is symptomatic in all 3 categories. We already covered the need to create ever more specific CSS selectors in the change amplifications case – eventually reaching id selectors, &lt;code&gt;!important&lt;/code&gt;, and inline styles.&lt;/p&gt;

&lt;p&gt;Specificity escalation also means developers reading and modifying CSS now need to keep a detailed mental model of the DOM in their mind when working – is it &lt;code&gt;.comments&lt;/code&gt; inside &lt;code&gt;#articles&lt;/code&gt; or is it &lt;code&gt;.comments&lt;/code&gt; inside &lt;code&gt;ul&lt;/code&gt;s inside &lt;code&gt;#articles&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Lastly, ever-increasing selector length means the number of locations that a style change may belong to also increases linearly. In the selector example above, should the change go in &lt;code&gt;articles.css&lt;/code&gt;, &lt;code&gt;comments.css&lt;/code&gt;, &lt;code&gt;global.css&lt;/code&gt; or just use 'find in the project' –  and what if you use a preprocessor that supports nested selector?&lt;/p&gt;

&lt;h3&gt;
  
  
  Source Order
&lt;/h3&gt;

&lt;p&gt;CSS source order gives us a way to consistently predict how a style resolves when multiple selectors have the same specificity score. It also handles when multiple values are declared for the same property in the same scope – an especially tricky combination with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Shorthand_properties"&gt;CSS shorthands&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The rule is simple, the value that appears last wins.&lt;/p&gt;

&lt;p&gt;Straight forward, right? Not so fast. This means each change we make is potentially affected by all other selectors with the same specificity. Your &lt;code&gt;.nav .button&lt;/code&gt; could be affected by &lt;code&gt;.header .button&lt;/code&gt;. In fact, you need to be aware of the intersection of all sets of elements matched by each selector with the same specificity score as the one you are working on. I can't even keep the entire DOM in my head at once, never mind the subset matched by all stylesheets. It's easy to see how this is a significant cognitive load that grows with project size.&lt;/p&gt;

&lt;p&gt;Source order is an even bigger problem in large projects where multiple stylesheets are included per page – either plain CSS or via preprocessor imports. Assume you are changing the color of the span in the following BEM-based DOM structure to green:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"widget"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"widget__content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"media-box"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"media-box__label"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Change Me&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;           
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the CSS files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* widget.css */&lt;/span&gt;
&lt;span class="nc"&gt;.widget&lt;/span&gt; &lt;span class="nc"&gt;.widget__content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* media.css */&lt;/span&gt;
&lt;span class="nc"&gt;.media&lt;/span&gt; &lt;span class="nc"&gt;.media__label&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&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;If you have no guarantees on the order of the stylesheet imports, which file do you change? This is a clear case of unknown unknowns, and it grows linearly with project file size.&lt;/p&gt;

&lt;p&gt;Do you change both 'just to be safe' and thus engage in change amplification? Or do you write &lt;code&gt;.widget .widget__content .media-box&lt;/code&gt; and engage in specificity escalation?&lt;/p&gt;

&lt;h3&gt;
  
  
  Inheritance
&lt;/h3&gt;

&lt;p&gt;CSS inheritance governs how certain CSS properties, when not specified, inherit values from their parent elements. Some common properties that inherit include &lt;code&gt;color&lt;/code&gt;, &lt;code&gt;font-size&lt;/code&gt;, and &lt;code&gt;line-height&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Inheritance is not as problematic as the other issues covered so far. It's a layer of abstraction that has little impact on change amplification and does not produce unknown unknowns. What it does is lead to additional cognitive load, even if the issues are mostly discovered via the browser – can you picture what "hello world" in the below example look like?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"d"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello World&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;14px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;letter-spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.b&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;800&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;letter-spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.c&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;teal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'Serif'&lt;/span&gt;   
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.d&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;18px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'arial'&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Word
&lt;/h2&gt;

&lt;p&gt;I hope I've convinced you that CSS is inherently complex, and its complexity grows superlinearly with the size of your project.&lt;/p&gt;

&lt;p&gt;Next time you get frustrated with a design change that seems to take much longer than it should, know it's probably caused by the project's CSS complexity.&lt;/p&gt;

&lt;p&gt;Next time you see a long selector in a code review – call it out and nip specificity escalation in the bud.&lt;/p&gt;

&lt;p&gt;And if you are starting a new project, I hope this post has further convinced you to adopt a tried and true CSS methodology and enforce it – really enforce it. No need to make CSS more complex than it has to be.&lt;/p&gt;

&lt;p&gt;Next week, I'll go over some historically successful patterns for combating CSS complexity, their tradeoffs, and the methodologies that use them.&lt;/p&gt;

&lt;p&gt;If you found this post helpful, please share it with others. You can also follow me &lt;a class="mentioned-user" href="https://dev.to/itstrueintheory"&gt;@itstrueintheory&lt;/a&gt; or on Twitter &lt;a href="https://twitter.com/ItsTrueInTheory"&gt;@itstrueintheory&lt;/a&gt; to get the latest blog updates.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>3 Interview Questions to Spot "Fake Agile" Software Engineering Teams</title>
      <dc:creator>Shimin Zhang</dc:creator>
      <pubDate>Fri, 15 Apr 2022 15:29:24 +0000</pubDate>
      <link>https://dev.to/itstrueintheory/3-interview-questions-to-spot-fake-agile-software-engineering-teams-22h9</link>
      <guid>https://dev.to/itstrueintheory/3-interview-questions-to-spot-fake-agile-software-engineering-teams-22h9</guid>
      <description>&lt;p&gt;Last week, I wrote about how software companies can claim to "do the Agile" &lt;a href="https://blog.shimin.io/3-patterns-of-agile-software-development/"&gt;while implementing waterfall or spiral models of software development.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If "fake agile" is the norm, asking a hiring team "do you do real agile?" is pointless. Nor is it helpful to ask about various agile-related ceremonies. No team is going to tell you 'Yeah, we waste about an hour every morning going over trivial issues during standup' – especially not in an interview setting.&lt;/p&gt;

&lt;p&gt;When I interview, I want to find out if the team follows the &lt;a href="https://agilemanifesto.org/"&gt;Agile Manifesto&lt;/a&gt; and its &lt;a href="https://agilemanifesto.org/principles.html"&gt;Principles&lt;/a&gt;. If the core is rotten, the rest (SAFe/Lean/XP/Crystal/TDD) are just lipstick on a pig.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: I am not advocating that Agile is the end all be all way to create software. Waterfall, spiral, and other SDLC methods have their uses. I happen to usually look for web development roles and like an agile environment.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here are 3 questions to help you find out if the company you are interviewing with is doing AgileFail – ask a developer you'll be working with:&lt;/p&gt;

&lt;h2&gt;
  
  
  "Tell me about the last time you refactored a module."
&lt;/h2&gt;

&lt;p&gt;Follow up to get an answer on when it last happened, how large was the refactor, what caused it, and if management was involved.&lt;/p&gt;

&lt;p&gt;A waterfall development process usually refactors at the beginning of a project, or when the project can no longer bear the weight of technical debt and outdated design decisions. This leads to large and long refactor periods, often after spending much time convincing management and multiple missed deadlines.&lt;/p&gt;

&lt;p&gt;A spiral model team has built-in refactor opportunities, after milestones or batches of customer feedback, leading to medium-to-large-sized refactors.&lt;/p&gt;

&lt;p&gt;An agile team has a refactoring as you go mentality. Only a handful of modules are touched at most and require little to no management wrangling.&lt;/p&gt;

&lt;p&gt;An agile answer would sound something like: &lt;em&gt;'I abstracted out the shipping calculation last week while adding DHL shipment support, it was the right opportunity to separate the UPS specific logic from common carrier abstraction.'&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Related Agile Principles:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Continuous attention to technical excellence&lt;br&gt;&lt;br&gt;
and good design enhances agility.  &lt;/p&gt;

&lt;p&gt;The best architectures, requirements, and designs&lt;br&gt;&lt;br&gt;
emerge from self-organizing teams.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  "Tell me about the last piece of user feedback that became a feature."
&lt;/h2&gt;

&lt;p&gt;Follow up with questions on how user feedback is gathered, how frequently that communication occurs, and how involved devs are in the feature design process.&lt;/p&gt;

&lt;p&gt;A ScrumFail team often would blank on this question, features are decided on and designed by individuals with no interaction with the development team. Or the product owner decides to add a feature to meet a KPI and the requirements are handed down at the beginning of a months-long planning period.&lt;/p&gt;

&lt;p&gt;A spiral development team gets these periodically – such as during milestone deliverable reviews – and spend a chunk of time incorporating those new feedback into the existing software.&lt;/p&gt;

&lt;p&gt;An agile team gets user feedback in the form of direct user interactions and usage data, developers are involved early and often in new feature development.&lt;/p&gt;

&lt;p&gt;Here's a hypothetical answer that I would love: &lt;em&gt;"The product owner told us users reported the shipping calculation selector was confusing, so I worked with our UX designer on a few alternative designs. They are currently being A/B tested".&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Agile Principles involved:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Business people and developers must work&lt;br&gt;&lt;br&gt;
together daily throughout the project.&lt;/p&gt;

&lt;p&gt;Individuals and interactions over processes and tools&lt;br&gt;&lt;br&gt;
Customer collaboration over contract negotiation&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  "Tell me about the last feature of yours that got dropped."
&lt;/h2&gt;

&lt;p&gt;This one is simple, I want to confirm that features get dropped, period. Bonus points if the feature is dropped due to user feedback or otherwise gets bumped by a higher priority item.&lt;/p&gt;

&lt;p&gt;Waterfall teams have a deadline for each piece of work – coerced or otherwise – and simply do not drop features. Of course, unexpected high-priority tickets keep flying in. So developers are constantly sprinting forward while dodging incoming P0s. This road leads to misery and burnout.&lt;/p&gt;

&lt;p&gt;Spiral process teams check in on a predetermined schedule and may decide to cut out-of-scope or infeasible features.&lt;/p&gt;

&lt;p&gt;An agile team tries to plan things out, but they also know that plans do not survive first contact with the enemy. And if you are responsive to change, you have to frequently drop outdated plans to make room for new ones. Features may start as a research spike or proof of concept, but they are validated via user feedback and they get dropped if priorities change.&lt;/p&gt;

&lt;p&gt;A good answer here would look like this: &lt;em&gt;"Last month I was working with the designer on a new checkout workflow, but we got a spike of complaints about shipping options after we expanded services to Europe so the checkout flow work got dropped to a later date"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Agile Principles involved:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Responding to change over following a plan&lt;br&gt;&lt;br&gt;
Agile processes promote sustainable development.&lt;/p&gt;

&lt;p&gt;The sponsors, developers, and users should be able&lt;br&gt;&lt;br&gt;
to maintain a constant pace indefinitely.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Take-Aways
&lt;/h2&gt;

&lt;p&gt;Why these questions and not &lt;em&gt;"how do you decide on a new feature?"&lt;/em&gt; or &lt;em&gt;"How often do you refactor?"&lt;/em&gt;? Because the alternatives invite calorie-free answers like "user feedback is the most important guide for our product roadmap" and "we write the highest quality code that gets the job done".&lt;/p&gt;

&lt;p&gt;I want concrete examples from the past, not hopeful future fluff.  So if you are on the job market looking for a team that cares more about being agile than going through the motions to look agile, ask these questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;em&gt;"Tell me about the last time you refactored a module or class."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;"Tell me about the last piece of user feedback that became a feature."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;"Tell me about the last feature of yours that got dropped."&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you find this post helpful, you may also be interested in learning more about &lt;a href="https://blog.shimin.io/3-patterns-of-agile-software-development/"&gt;how fake agile is done&lt;/a&gt;, or &lt;a href="https://blog.shimin.io/deal-with-pushback-from-code-review-comments/"&gt;how a comment hierarchy can improve your code review process&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>career</category>
      <category>startup</category>
    </item>
  </channel>
</rss>
