<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>sglavoie.com – Tag: Design</title><link>https://www.sglavoie.com/tags/design/</link><description>Posts and writings by Sébastien Lavoie. Customization setups and articles on productivity for developers who like minimalism.</description><language>en</language><atom:link href="https://www.sglavoie.com/tags/design/feed.xml" rel="self" type="application/rss+xml"/><lastBuildDate>Sun, 30 Mar 2025 11:18:00 -0600</lastBuildDate><item><title>Reading notes: A Philosophy of Software Design, 2nd Edition</title><link>https://www.sglavoie.com/posts/book-summary-philosophy-software-design-2nd-edition/</link><description>A Philosophy of Software Design, 2nd Edition by John Osterhout beautifully covers the nature of complexity in software. It provides clear strategies to keep complexity as low as possible while giving real-world examples along the way from his own work (e.g., RAMCloud or the Tcl programming language). He also gathered, for instance, interesting sources of various designs for a GUI text editor from his students, highlighting essential points to keep in mind while designing software.</description><content:encoded>&lt;hr&gt;
&lt;h2 id="nature-of-complexity"&gt;Nature of complexity&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Change amplification: The first symptom of complexity is that a seemingly simple change requires code modifications in many different places.&amp;rdquo;&lt;/em&gt; (e.g., refactoring a project to inject dependencies in tests, because the system was hard to test in the first place)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Cognitive load: The second symptom of complexity is cognitive load, which refers to how much a developer needs to know in order to complete a task.&amp;rdquo;&lt;/em&gt; (e.g., close a file where it is opened whenever possible, instead of leaking context and pushing the responsibility onto the caller)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Unknown unknowns: The third symptom of complexity is that it is not obvious which pieces of code must be modified to complete a task, or what information a developer must have to carry out the task successfully.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;One of the most important goals of good design is for a system to be obvious.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="strategic-vs-tactical-programming"&gt;Strategic vs. tactical programming&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;it&amp;rsquo;s worth taking a little extra time to find a simple design for each new class; rather than implementing the first idea that comes to mind, try a couple of alternative designs and pick the cleanest one. Try to imagine a few ways in which the system might need to be changed in the future and make sure that will be easy with your design&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="modules-should-be-deep"&gt;Modules should be deep&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Modular design
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;In general, if a developer needs to know a particular piece of information in order to use a module, then that information is part of the module&amp;rsquo;s interface.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Abstractions
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;The key to designing abstractions is to understand what is important, and to look for designs that minimize the amount of information that is important&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A deep module is one in which the interface is small and the implementation is large.
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Deep modules such as Unix I/O and garbage collectors provide powerful abstractions because they are easy to use, yet they hide significant implementation complexity.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Shallow modules
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;A shallow module is one whose interface is complicated relative to the functionality it provides.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="information-hiding"&gt;Information hiding&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;If a piece of information is hidden, there are no dependencies on that information outside the module containing the information, so a design change related to that information will affect only the one module&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Information leakage
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;If the affected classes are relatively small and closely tied to the leaked information, it may make sense to merge them into a single class.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;When designing modules, focus on the knowledge that&amp;rsquo;s needed to perform each task, not the order in which tasks occur.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;it&amp;rsquo;s important to avoid exposing internal data structures as much as possible&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;The best features are the ones you get without even knowing they exist.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;As a software designer, your goal should be to minimize the amount of information needed outside a module; for example, if a module can automatically adjust its configuration, that is better than exposing configuration parameters&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;think about the different pieces of knowledge that are needed to carry out the tasks of your application, and design each module to encapsulate one or a few of those pieces of knowledge. This will produce a clean and simple design with deep modules.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="general-purpose-modules-are-deeper"&gt;General-Purpose Modules are Deeper&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;specialization leads to complexity&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Generality leads to better information hiding&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Eliminate special cases in code&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="different-layer-different-abstraction"&gt;Different Layer, Different Abstraction&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;A pass-through method is one that does nothing except pass its arguments to another method, usually with the same API as the pass-through method. This typically indicates that there is not a clean division of responsibility between the classes.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="pull-complexity-downwards"&gt;Pull Complexity Downwards&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Figure out complexity in the library instead of pushing it up to the user.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;quot;[&amp;hellip;] you should avoid configuration parameters as much as possible. Before exporting a configuration parameter, ask yourself: will users (or higher-level modules) be able to determine a better value than we can determine here?&amp;quot;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="better-together-or-better-apart"&gt;Better Together Or Better Apart?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Bring together if information is shared&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Bring together if it will simplify the interface&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Bring together to eliminate duplication&amp;rdquo;&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;goto&lt;/code&gt; to exit nested code blocks early as long as it&amp;rsquo;s not too complex.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;On Splitting long methods: &lt;em&gt;&amp;ldquo;If you make a split of this form and then find yourself flipping back and forth between the parent and child to understand how they work together, that is a red flag (&amp;ldquo;Conjoined Methods&amp;rdquo;) indicating that the split was probably a bad idea.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;If the caller has to invoke each of the separate methods, passing state back and forth between them, then splitting is not a good idea.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="define-errors-out-of-existence"&gt;Define Errors Out Of Existence&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;The key overall lesson from this chapter is to &lt;strong&gt;reduce the number of places where exceptions must be handled&lt;/strong&gt;; in some cases the semantics of operations can be modified so that the normal behavior handles all situations and there is no exceptional condition to report [&amp;hellip;].&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;The best way to eliminate exception handling complexity is to &lt;strong&gt;define your APIs so that there are no exceptions to handle&lt;/strong&gt;: define errors out of existence&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;E.g., the Java &lt;code&gt;substring&lt;/code&gt; method could remove its &lt;code&gt;IndexOutOfBoundsException&lt;/code&gt; by automatically rounding the index to the nearest valid value.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;quot;&lt;strong&gt;Exception masking&lt;/strong&gt; doesn&amp;rsquo;t work in all situations, but it is a powerful tool in the situations where it works. It results in deeper classes, since it reduces the class&amp;rsquo;s interface (fewer exceptions for users to be aware of) and adds functionality in the form of the code that masks the exception. Exception masking is an example of pulling complexity downward.&amp;quot;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;The idea behind exception aggregation is to handle many exceptions with a single piece of code; rather than writing distinct handlers for many individual exceptions, handle them all in one place with a single handler.&amp;rdquo;&lt;/em&gt; (e.g., a web server dispatching different types of requests and catching all sorts of errors).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;In most applications there will be certain errors that are not worth trying to handle. Typically, these errors are difficult or impossible to handle and don&amp;rsquo;t occur very often. The simplest thing to do in response to these errors is to print diagnostic information and then abort the application.&amp;rdquo;&lt;/em&gt; (e.g., out-of-memory errors).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="design-it-twice"&gt;Design it Twice&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;The initial design experiments will probably result in a significantly better design, which will more than pay for the time spent designing it twice&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;The process of devising and comparing multiple approaches will teach you about the factors that make designs better or worse. Over time, this will make it easier for you to rule out bad designs and hone in on really great ones.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-write-comments-the-four-excuses"&gt;Why Write Comments? The Four Excuses&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Good code is self-documenting.&lt;/em&gt; Comments serve as precisions on abstractions.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;I don&amp;rsquo;t have time to write comments.&lt;/em&gt; The benefits of having documentation quickly offset the cost of writing it.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Comments get out of date and become misleading.&lt;/em&gt; Keep the documentation close to where it needs to be, so you update it.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;All the comments I have seen are worthless.&lt;/em&gt; Be the change you want to see.&lt;/li&gt;
&lt;li&gt;Benefits of well-written comments
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;The overall idea behind comments is to capture information that was in the mind of the designer but couldn&amp;rsquo;t be represented in the code.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;One of the purposes of comments is to make it it unnecessary to read the code.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="comments-should-describe-things-that-arent-obvious-from-the-code"&gt;Comments Should Describe Things that Aren&amp;rsquo;t Obvious from the Code&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Don&amp;rsquo;t repeat the code&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Lower-level comments add precision&amp;rdquo;&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;Focus on what the variable represents, not how it is modified (the latter is explained by the code).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Higher-level comments enhance intuition&amp;rdquo;&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;What is the simplest thing you can say that explains everything in the code? What is the most important thing about this code?&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Interface documentation&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Implementation comments: what and why, not how&amp;rdquo;&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;Describe at a more abstract level to help understand what is happening and why. The code tells the how.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cross-module design decisions
&lt;ul&gt;
&lt;li&gt;One possible solution is to use a &lt;code&gt;designNotes.md&lt;/code&gt; file or similar to jot down all major decisions, and point to it from the code (e.g., &lt;em&gt;See &lt;code&gt;topic&lt;/code&gt; in designNotes&lt;/em&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="choosing-names"&gt;Choosing names&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Great names are &lt;em&gt;&amp;ldquo;precise, unambiguous, and intuitive.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Use names consistently: make it so that a concept is expressed in the same words regardless of the context in which it is found if it makes sense to do so.&lt;/li&gt;
&lt;li&gt;Avoid extra words: no more Hungarian Notation with modern IDEs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="use-comments-as-part-of-the-design-process"&gt;Use comments as part of the design process&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Delayed comments are bad comments
&lt;ul&gt;
&lt;li&gt;You won&amp;rsquo;t remember exactly what you had in mind and why you did things if you delay writing documentation: design decisions will get lost.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Write the comments first
&lt;ul&gt;
&lt;li&gt;No backlog of unwritten comments.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;it produces better comments.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Comments are a design tool
&lt;ul&gt;
&lt;li&gt;Writing them at the beginning &lt;em&gt;&amp;ldquo;improves the system design.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;If a method or variable requires a long comment, it is a red flag that you don&amp;rsquo;t have a good abstraction.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Early comments are fun comments
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;If you are programming strategically, where your main goal is a great design rather than just writing code that works, then writing comments should be fun, since that&amp;rsquo;s how you identify the best designs.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;I&amp;rsquo;m looking for the design that can be expressed completely and clearly in the fewest words. The simpler the comments, the better I feel about my design.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Are early comments expensive?
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Writing the comments first will mean that the abstractions will be more stable before you start writing code.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;In contrast, if you write the code first, the abstractions will probably evolve as you code, which will require more code revisions than the comments-first approach.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="modifying-existing-code"&gt;Modifying existing code&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Whenever you modify any code, try to find a way to improve the system design at least a little bit in the process. If you&amp;rsquo;re not making the design better, you are probably making it worse.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Maintaining comments: keep the comments near the code
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;The farther a comment is from its associated code, the less likely it is that it will be updated properly.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;In general, the farther a comment is from the code it describes, the more abstract it should be (this reduces the likelihood that the comment will be invalidated by code changes).&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Comments belong in the code, not the commit log
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;An example is a commit message describing a subtle problem that motivated a code change. If this isn&amp;rsquo;t documented in the code, then a developer might come along later and undo the change without realizing that they have re-created a bug.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Maintaining comments: avoid duplication&lt;/li&gt;
&lt;li&gt;Maintaining comments: check the diffs
&lt;ul&gt;
&lt;li&gt;Review changes during the pre-commit phase to make sure documentation stays up-to-date with the code changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Higher-level comments are easier to maintain
&lt;ul&gt;
&lt;li&gt;Most helpful comments do not repeat the code, they provide an abstraction that can&amp;rsquo;t be expressed easily by the code alone.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="consistency"&gt;Consistency&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Similar things are done in a similar way.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Consistency creates cognitive leverage: once you have learned how something is done in one place, you can use that knowledge to immediately understand other places that use the same approach.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Ensuring consistency
&lt;ul&gt;
&lt;li&gt;Document most important conventions.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;the value of consistency over inconsistency is almost always greater than the value of one approach over another.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="code-should-be-obvious"&gt;Code should be obvious&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;the best way to determine the obviousness of code is through code reviews&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;If someone reading your code says it&amp;rsquo;s not obvious, then it&amp;rsquo;s not obvious, no matter how clear it may seem to you&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Things that make code more obvious
&lt;ul&gt;
&lt;li&gt;Good names&lt;/li&gt;
&lt;li&gt;Consistency&lt;/li&gt;
&lt;li&gt;Judicious use of white space&lt;/li&gt;
&lt;li&gt;Blank lines&lt;/li&gt;
&lt;li&gt;Comments&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Things that make code less obvious
&lt;ul&gt;
&lt;li&gt;Event-driven programming&lt;/li&gt;
&lt;li&gt;Generic containers&lt;/li&gt;
&lt;li&gt;Different types for declaration and allocation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="software-trends"&gt;Software trends&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Object-oriented programming and inheritance
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;In order for an interface to have many implementations, it must capture the essential features of all the underlying implementations while steering clear of the details that differ between the implementations; this notion is at the heart of abstraction.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Class hierarchies that use implementation inheritance extensively tend to have high complexity.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Before using implementation inheritance, consider whether an approach based on composition can provide the same benefits.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Agile development
&lt;ul&gt;
&lt;li&gt;May encourage a more tactical approach to programming. Balance is required.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Test-driven development
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;it focuses attention on getting specific features working, rather than finding the best design&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;One place where it makes sense to write the tests first is when fixing bugs. Before fixing a bug, write a unit test that fails because of the bug.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Design patterns
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;As with many ideas in software design, the notion that design patterns are good doesn’t necessarily mean that more design patterns are better.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Getters and setters
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;It’s better to avoid getters and setters (or any exposure of implementation data) as much as possible.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="designing-for-performance"&gt;Designing for performance&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;How to think about performance
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;The key is to develop an awareness of which operations are fundamentally expensive.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Measure before (and after) modifying
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;the goal is to identify a small number of very specific places where the system is currently spending a lot of time, and where you have ideas for improvement.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;If the changes didn’t make a measurable difference in performance, then back them out (unless they made the system simpler).&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Design around the critical path
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;When redesigning for performance, try to minimize the number of special cases you must check.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Complicated code tends to be slow because it does extraneous or redundant work.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="decide-what-matters"&gt;Decide what matters&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Minimize what matters&lt;/li&gt;
&lt;li&gt;How to emphasize things that matter
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;important things should appear in places where they are more likely to be seen, such as interface documentation, names, or parameters to heavily used methods.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;repetition: key ideas appear over and over again.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;The things that matter the most should be at the heart of the system, where they determine the structure of things around them.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Mistakes
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;treat too many things as important. When this happens, unimportant things clutter up the design, adding complexity and increasing cognitive load.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;fail to recognize that something is important. This mistake leads to situations where important information is hidden, or important functionality is not available so developers must continually recreate it.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Thinking more broadly
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;the best way to make a document easy to read is to identify a few key concepts at the beginning and structure the remainder of the document around them. When discussing the details of a system, it helps to tie them back to the overall concepts.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Focusing on what is important is also a great life philosophy: identify a few things that matter most to you, and try to spend as much of your energy as possible on those things.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;The reward for being a good designer is that you get to spend a larger fraction of your time in the design phase, which is fun. Poor designers spend most of their time chasing bugs in complicated and brittle code.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Sun, 30 Mar 2025 11:18:00 -0600</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/book-summary-philosophy-software-design-2nd-edition/</guid><category>learnings</category><category>books</category><category>design</category><category>software</category><category>skimming-notes</category></item><item><title>Book summary: Refactoring UI</title><link>https://www.sglavoie.com/posts/book-summary-refactoring-ui/</link><description>Refactoring UI provides guidance for non-designers on how to create polished, professional visual interfaces without formal graphic design skills.</description><content:encoded>&lt;hr&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;It covers core principles like establishing consistent systems for recurring elements such as spacing and typography.&lt;/li&gt;
&lt;li&gt;It advises generous use of white space and thoughtful visual hierarchy.&lt;/li&gt;
&lt;li&gt;Steps for adding depth through lighting, shadows, and layers are outlined.&lt;/li&gt;
&lt;li&gt;Recommendations are provided for working with images and illustrations effectively.&lt;/li&gt;
&lt;li&gt;Tips on elevating default elements and breaking conventions to avoid typical, cookie-cutter designs are included.&lt;/li&gt;
&lt;li&gt;Studying other designers&amp;rsquo; work and unintuitive decisions is encouraged to expand one&amp;rsquo;s skills.&lt;/li&gt;
&lt;li&gt;The goal is to equip readers with knowledge to thoughtfully craft interfaces that appear purposefully designed without simply mimicking common graphical tropes.&lt;/li&gt;
&lt;li&gt;By learning fundamental visual design concepts tailored to user interfaces, anyone can create clean, functional, and visually engaging digital experiences.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="starting-from-scratch"&gt;Starting from scratch&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Start with a feature, not a layout&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Design the shell and navigation later once you know what features you need.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Detail comes later&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Design with a big sharpie.&lt;/li&gt;
&lt;li&gt;Design in grayscale to use spacing, contrast and size to do the heavy lifting.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don&amp;rsquo;t over-invest&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Go with low-fidelity sketches and wireframes first to move fast. Don&amp;rsquo;t get bogged down with details like fonts and colors early on.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don&amp;rsquo;t design too much&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Work in cycles&lt;/strong&gt;: design a feature simply, build it, fix errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Be a pessimist&lt;/strong&gt;: expect it to be hard to build, and postpone building it (e.g., commenting system without attachments at first).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="choose-a-personality"&gt;Choose a personality&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Font choice
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Elegant/classic&lt;/em&gt;: serif&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Playful&lt;/em&gt;: Sans-serif&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Plain&lt;/em&gt;: neutral sans-serif&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Color
&lt;ul&gt;
&lt;li&gt;Blue: safe and familiar, good overall pick.&lt;/li&gt;
&lt;li&gt;Gold: expensive, sophisticated.&lt;/li&gt;
&lt;li&gt;Pink: more fun, less serious.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Border radius
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Small&lt;/em&gt; &amp;ndash; neutral, not much personality.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Large&lt;/em&gt; &amp;ndash; more playful.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;None&lt;/em&gt; &amp;ndash; more serious/formal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stay consistent&lt;/strong&gt; &amp;ndash; either rounded or not, same everywhere.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Language
&lt;ul&gt;
&lt;li&gt;Choose the right words for the desired tone.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Decide what you actually want
&lt;ul&gt;
&lt;li&gt;Look at the websites your expected customers use? Serious, then that&amp;rsquo;s the feel. Playful? Then that.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="limit-your-choices"&gt;Limit your choices&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Define systems in advance&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Have a working palette color and limit yourself to it.&lt;/li&gt;
&lt;li&gt;Use a type scale to avoid picking specific font sizes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Designing by process of elimination.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Systematize&lt;/strong&gt; as much as possible to avoid repetitive low-level decisions.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="hierarchy"&gt;Hierarchy&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Visual hierarchy refers to how elements appear in importance relative to one another.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t let HTML semantics dictate visual styling &amp;ndash; style based on visual hierarchy.&lt;/li&gt;
&lt;li&gt;Size isn&amp;rsquo;t everything. Bold font communicates importance. &lt;em&gt;De-emphasize&lt;/em&gt; secondary/tertiary information to highlight the most important elements.&lt;/li&gt;
&lt;li&gt;Rely on &lt;em&gt;font weight&lt;/em&gt; and &lt;em&gt;color&lt;/em&gt;, not just font size, to create hierarchy.&lt;/li&gt;
&lt;li&gt;Limit yourself to &lt;em&gt;2-3 colors&lt;/em&gt; and font weights to define hierarchy.&lt;/li&gt;
&lt;li&gt;On colored backgrounds, pick a color with similar hue but lower saturation/lightness rather than just making text gray.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avoid label&lt;/strong&gt;: value formats &amp;ndash; use formats, context, and combined labels/values for clarity without labels.&lt;/li&gt;
&lt;li&gt;Treat labels as secondary content when needed &amp;ndash; smaller, lower contrast, lighter weight.&lt;/li&gt;
&lt;li&gt;De-emphasize competing elements instead of just emphasizing the key element.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Combine labels and values&lt;/em&gt;: e.g., instead of &amp;ldquo;&lt;em&gt;In stock: 12&lt;/em&gt;&amp;rdquo;, use &amp;ldquo;&lt;em&gt;12 left in stock&lt;/em&gt;&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Treat labels as supporting content.&lt;/li&gt;
&lt;li&gt;Design buttons based on hierarchy, not just semantics. Primary/destructive actions don&amp;rsquo;t always need prominence.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="layout-and-spacing"&gt;Layout and spacing&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Start with too much white space&lt;/strong&gt;, then remove until happy &amp;ndash; often ends up being &amp;ldquo;just enough&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Compact layouts have their place but should be a deliberate choice, not the default.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Establish a spacing and sizing system&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;A linear scale won&amp;rsquo;t work&lt;/li&gt;
&lt;li&gt;Create a constrained spacing/sizing system based on a base unit (like &lt;code&gt;16px&lt;/code&gt;) to work faster with more consistency.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Don&amp;rsquo;t feel the need to fill the whole screen&lt;/em&gt; &amp;ndash; give elements only the space they need.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grids are overrated&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Not all elements should be fluid&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t shrink an element until you need to.&lt;/li&gt;
&lt;li&gt;Grids can bring order but don&amp;rsquo;t have to dictate every layout decision.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Balance layouts in columns&lt;/em&gt; instead of just making things wider.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Relative sizing doesn&amp;rsquo;t scale&lt;/em&gt;.
&lt;ul&gt;
&lt;li&gt;Fix element widths when flexibility isn&amp;rsquo;t needed.&lt;/li&gt;
&lt;li&gt;Scale elements independently &amp;ndash; don&amp;rsquo;t rely on relative units like &lt;code&gt;em&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avoid ambiguous spacing&lt;/strong&gt;: increase spacing between groups and reduce spacing within groups to show relationships.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="text"&gt;Text&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Establish a constrained type scale&lt;/strong&gt; to speed up font size decisions and add consistency. Avoid strict modular scales.&lt;/li&gt;
&lt;li&gt;Use &lt;em&gt;pixel&lt;/em&gt; or &lt;code&gt;rem&lt;/code&gt; units &amp;ndash; not &lt;code&gt;em&lt;/code&gt; &amp;ndash; to guarantee sizes match the scale.&lt;/li&gt;
&lt;li&gt;For UI design, &lt;em&gt;pick scale values by hand&lt;/em&gt; instead of using a mathematical ratio.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use high quality fonts&lt;/strong&gt; &amp;ndash; safe bets are neutral sans-serifs and system fonts.&lt;/li&gt;
&lt;li&gt;Use the system stack if not sure: &lt;code&gt;-apple-system, Segoe UI, Roboto, Noto Sans, Ubuntu, Cantarell, Helvetica Neue;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Favor fonts with &lt;em&gt;5+ weights&lt;/em&gt; and optimized for legibility.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep line length between 45-75 characters&lt;/strong&gt; (20-35 &lt;code&gt;em&lt;/code&gt;) for optimal readability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Align mixed font sizes by their baselines&lt;/strong&gt;, not centers.&lt;/li&gt;
&lt;li&gt;Use taller line-heights for small text and shorter line-heights for large text.&lt;/li&gt;
&lt;li&gt;Subtly emphasize links in UIs, no need for high contrast colors.&lt;/li&gt;
&lt;li&gt;Left align most text, right align numbers in tables. Justify only with hyphenation.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t center long form text.&lt;/li&gt;
&lt;li&gt;Tighten letter-spacing for headlines set in text faces. Loosen letter-spacing for all-caps.&lt;/li&gt;
&lt;li&gt;Not all links need to be emphasized boldly, especially in UIs where there is plenty of interactivity.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="colors"&gt;Colors&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HSL&lt;/strong&gt; (&lt;em&gt;hue&lt;/em&gt;, &lt;em&gt;saturation&lt;/em&gt;, &lt;em&gt;lightness&lt;/em&gt;) is more intuitive to the human eye: use it instead of &lt;strong&gt;HEX&lt;/strong&gt; and &lt;strong&gt;RGB&lt;/strong&gt;.
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Hue&lt;/em&gt; is the color position on the color wheel. 0° is red, 120° is green, and 240° is blue.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Saturation&lt;/em&gt; represents the vividness. 0% is grey while 100% is vibrant and intense.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Lightness&lt;/em&gt; measures how close a closer is to black (0%) or white (100%), where 50% is the pure color.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HSL&lt;/strong&gt; is not the same as &lt;strong&gt;HSB&lt;/strong&gt; (&lt;code&gt;lightness != brightness&lt;/code&gt;). In &lt;strong&gt;HSB&lt;/strong&gt;, 0% brightness is always black but 100% brightness is white when saturation is set to 0%.
&lt;ul&gt;
&lt;li&gt;With 100% saturation in both HSL and HSB, 100% brightness is equivalent to 50% lightness (pure color).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Don&amp;rsquo;t rely solely on color to convey information&lt;/em&gt; - support it with other indicators.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="a-good-color-palette"&gt;A good color palette&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;You need more colors than you think - aim for &lt;em&gt;10+ shades&lt;/em&gt; of &lt;em&gt;greys&lt;/em&gt;, &lt;em&gt;primary colors&lt;/em&gt;, and &lt;em&gt;accent colors&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Grey&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;There is a lot of grey in UIs: between &lt;em&gt;8-10 shades of grey&lt;/em&gt; is a good array of options to pick from. Use very dark grey instead of true black so it looks more natural.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Primary colors&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;1 or 2 is great, with 5-10 different shades&lt;/em&gt; (e.g., Facebook is basically blue). A very light shade is good for a tinted background (e.g., alerts), darker shades work great for text.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Accent colors&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Use sparingly&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Needed to bring &lt;em&gt;semantic meaning&lt;/em&gt;, such as red for danger, yellow for warnings and green for positive trends.&lt;/li&gt;
&lt;li&gt;For a complex UI, can be as many as 10 different colors, each with 5-10 shades.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="building-a-color-palette"&gt;Building a color palette&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Define color shades upfront instead of generating on the fly. Pick base, darkest, lightest, then fill in gaps.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t rely purely on math to generate shades - trust your eyes and tweak if needed.&lt;/li&gt;
&lt;li&gt;Choose the base color first. This is the color in the middle that light and dark shades are derived from.&lt;/li&gt;
&lt;li&gt;Center: pick a shade that would work well as a button background.&lt;/li&gt;
&lt;li&gt;Extremes: pick the lightness color to work as a background and the darkest to work on top as text to get enough contrast.&lt;/li&gt;
&lt;li&gt;Repeat the process to pick the remaining colors in between. &lt;em&gt;9 shades is a good sweet spot as it divides cleanly&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;For grays, the base color doesn&amp;rsquo;t matter nearly as much: same process.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="perceived-brightness"&gt;Perceived brightness&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;In the HSL system, the further away a color is from 50% lightness, the more saturated it should be so it doesn&amp;rsquo;t look washed out.&lt;/li&gt;
&lt;li&gt;The perceived brightness of a color to the human eye can be calculated as follows:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;brightness = √(0.299·r² + 0.587·g² + 0.114·b²) / 255&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Green is perceived as more bright than red, which in turn is perceived as more bright than blue. With this data point, we can tweak the perceived brightness of a color by rotating the color wheel towards the desired perceived brightness.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Grays aren&amp;rsquo;t usually totally desaturated&lt;/em&gt;.
&lt;ul&gt;
&lt;li&gt;To make them feel &amp;ldquo;&lt;em&gt;cool&lt;/em&gt;&amp;rdquo; saturate them with some blue.&lt;/li&gt;
&lt;li&gt;To make them feel &amp;ldquo;&lt;em&gt;warm&lt;/em&gt;&amp;rdquo;, saturate them with yellow or orange.&lt;/li&gt;
&lt;li&gt;The same &amp;ldquo;&lt;em&gt;saturation curve&lt;/em&gt;&amp;rdquo; applies to grays: the further away from 50% brightness, the more they should be saturated to avoid looking washed out.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="a-word-on-accessibility"&gt;A word on accessibility&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Instead of having elements like dark-colored pills with a white foreground color, flip the contrast by having light-colored pills with a dark version of the color in the foreground so they won&amp;rsquo;t grab too much attention.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rotate the hue to make the color pop more&lt;/strong&gt;. For instance, instead of cranking up the lightness to meet ideal contrast ratios, rotate the hue and possibly keep the saturation high for a vibrant contrast.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don&amp;rsquo;t rely on color alone&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Add visual cues (like arrows for upward/downward trends). Designing in grayscale first will help spot these kinds of issues.&lt;/li&gt;
&lt;li&gt;For things like a graph, playing with contrast will produce clearer results.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="depth"&gt;Depth&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Mimic how light works in the real world.
&lt;ul&gt;
&lt;li&gt;Emulate a light source coming from above to make elements appear raised or inset.&lt;/li&gt;
&lt;li&gt;For instance, with a button, if light comes from above, then the top should be lighter (e.g., &lt;code&gt;box-shadow inset&lt;/code&gt;) than the bottom (&lt;code&gt;box-shadow&lt;/code&gt;, casting shadow only below).&lt;/li&gt;
&lt;li&gt;For elements that are &amp;ldquo;inset&amp;rdquo; (I.e., more depth in the center), the opposite effect should happen: more light reaches the bottom part (vertical &lt;code&gt;box-shadow&lt;/code&gt;, going up) than the top part (&lt;code&gt;box-shadow inset&lt;/code&gt; such that it casts some shadow towards the bottom).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Don&amp;rsquo;t overdo it&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="shadows"&gt;Shadows&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Use shadows to convey elevation&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;When something appears to be raised from the background (e.g., bigger &lt;code&gt;drop-shadow&lt;/code&gt;), &lt;em&gt;it attracts the user&amp;rsquo;s focus&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Small shadows&lt;/em&gt; are useful to attract attention to the primary action to be performed.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Medium shadows&lt;/em&gt; are useful for things like a dropdown so it looks separate from the background.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Large shadows&lt;/em&gt; are great for modals.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;5 options&lt;/em&gt; is usually plenty.&lt;/li&gt;
&lt;li&gt;Can be used for interactivity, like when dragging a row from a table.&lt;/li&gt;
&lt;li&gt;A button can feel like it&amp;rsquo;s being &amp;ldquo;pressed&amp;rdquo; by reducing its shadow on click (i.e., it gets closer to the page or farther away from the user).&lt;/li&gt;
&lt;li&gt;Casting shadows
&lt;ul&gt;
&lt;li&gt;To simulate a shadow cast by &lt;em&gt;direct light&lt;/em&gt; (e.g., a long shadow behind a plant getting some sunlight), use a larger, more diffuse and subtle shadow.&lt;/li&gt;
&lt;li&gt;To simulate a shadow cast by &lt;em&gt;ambient light&lt;/em&gt; (e.g., the shadow right below the plant&amp;rsquo;s pot where light can&amp;rsquo;t hardly reach), use a narrow and darker shadow.&lt;/li&gt;
&lt;li&gt;Apply both types of shadow casting at once to create visually compelling effects.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Define a fixed set of shadows as an elevation system for consistency.&lt;/li&gt;
&lt;li&gt;Even flat designs can have depth
&lt;ul&gt;
&lt;li&gt;Flat design does not convey depth with shadows and gradients.&lt;/li&gt;
&lt;li&gt;Create depth with color: lighter colors feel closer.&lt;/li&gt;
&lt;li&gt;Can use short, offset shadows with no blur at all.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Overlap elements to create layers
&lt;ul&gt;
&lt;li&gt;E.g., position a block with a negative margin so it appears on top of two different sections.&lt;/li&gt;
&lt;li&gt;For smaller elements like avatars, an invisible border around it can make it pop better.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="images-and-contrast"&gt;Images and contrast&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Images
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Use high quality photos&lt;/em&gt; - hire a pro or use stock sites for generics. Don&amp;rsquo;t expect good results from phone pics.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text needs consistent contrast&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Add an overlay to background images to get readable headlines.&lt;/li&gt;
&lt;li&gt;Lower the image contrast. Adjust the brightness to compensate.&lt;/li&gt;
&lt;li&gt;Colorize the image with a single color.&lt;/li&gt;
&lt;li&gt;Use text shadows instead of overlays to preserve image dynamics.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="scale"&gt;Scale&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Don&amp;rsquo;t scale up icons&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Even for SVGs, they will lack detail if they were designed correctly at a smaller scale: use a more detailed icon instead.&lt;/li&gt;
&lt;li&gt;If updating the icon is not an option, enclose it inside another shape (e.g., a circle with a background color) to occupy more space.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don&amp;rsquo;t scale down screenshots&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Details will be distorted and hard to read.&lt;/li&gt;
&lt;li&gt;Either use a presentation from a smaller device (e.g., the tablet version on a desktop) or take a partial screenshot (e.g., &amp;ldquo;zoom in&amp;rdquo; effect with a circle or simply crop the original image).&lt;/li&gt;
&lt;li&gt;If a more complex UI needs to be presented, simplify the original image so the user doesn&amp;rsquo;t try to read a 4px font size but instead sees simpler shapes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don&amp;rsquo;t scale down icons&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;E.g. for a favicon, redraw a simplified version instead: details will look fuzzy at a small size.&lt;/li&gt;
&lt;li&gt;User-submitted content (e.g., Instagram feed)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Control the size and shape&lt;/em&gt;: crop images to keep the aspect ratio of containers so they don&amp;rsquo;t disturb layout (e.g., background-size: cover).&lt;/li&gt;
&lt;li&gt;Add inner shadows or borders to user images to prevent background bleed.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="finishing-touches"&gt;Finishing touches&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Use icons instead of bullets in a bulleted list.&lt;/li&gt;
&lt;li&gt;Play with size and colors. E.g., you can have huge quotes around the block of text representing a testimonial.&lt;/li&gt;
&lt;li&gt;Links deserve special styling.&lt;/li&gt;
&lt;li&gt;Use custom checkboxes and radio buttons in forms: integrate the brand&amp;rsquo;s primary color(s).&lt;/li&gt;
&lt;li&gt;Add color with accent borders, e.g. across the top of a card element, when highlighting active elements in the UI or to the left of alert messages.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Decorate backgrounds&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;Change the background color. Works great for different page sections.&lt;/li&gt;
&lt;li&gt;Can use gradients: use two hues that are within 30˚ of each other.&lt;/li&gt;
&lt;li&gt;Use repeating patterns.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consider the empty state carefully&lt;/strong&gt;, especially when the user is meant to fill the UI with data.
&lt;ul&gt;
&lt;li&gt;Prioritize empty states with illustrations and clear calls to action.&lt;/li&gt;
&lt;li&gt;I.e., a contact page with no contacts should feel welcoming, with some icon and button to add a contact instead of a blank page with an error-like statement.&lt;/li&gt;
&lt;li&gt;Similarly, things like dashboard may present a bunch of options that won&amp;rsquo;t apply until there is something to show: simplify the user experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use less borders&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Use box shadows, spacing, and color instead of borders to distinguish elements.&lt;/li&gt;
&lt;li&gt;Have two background colors for containers (e.g., darker footer that looks separate from the main content).&lt;/li&gt;
&lt;li&gt;Replace borders with additional spacing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Make components more exciting&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;E.g., a table may not need all its columns if a particular column does not need to be sorted and could instead be part of another one (e.g., combining a dollar amount with a plan type or a person&amp;rsquo;s name with its title).&lt;/li&gt;
&lt;li&gt;Radio buttons could be cards instead if they are an important part of the UI.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="next-level"&gt;Next level&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Look for unintuitive decisions in designs you admire to find new ideas.&lt;/li&gt;
&lt;li&gt;Rebuild interfaces you love to discover small details that make them exceptional.&lt;/li&gt;
&lt;li&gt;Study others to build a solid foundation.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The concepts covered in this book demonstrate that effective visual design does not require innate artistic talent or formal training. By approaching interfaces methodically, establishing constraints through systems for recurring elements, and learning to strategically apply principles like visual hierarchy, white space, and depth cues, anyone can create designs that appear polished and purposeful. While internalizing these fundamentals does take practice, the ideas presented remove much of the subjective, nuanced expertise needed for things like picking complementary colors or balancing composition in illustrations.&lt;/p&gt;
&lt;p&gt;By focusing on interfaces rather than free-form graphical work, the required skills become more structured and intentional choices drive outcomes. While studying formally can provide more breadth, the core principles in this text are enough to equip non-designers with the ability to build clean, intuitive, and aesthetically pleasing digital products. By implementing the recommendations covered, engineers and others new to design can gain confidence in their interface design skills. A great, concise read!&lt;/p&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Sat, 09 Sep 2023 17:56:00 -0600</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/book-summary-refactoring-ui/</guid><category>learnings</category><category>best practices</category><category>books</category><category>design</category><category>refactoring</category><category>skimming-notes</category><category>ui</category></item></channel></rss>