While there is an inordinate amount of wonderful content to be consumed on the internet (my addiction is
          HackerNews), every once in a while I get to read a legendary post that simply allows me to level up as a
          person. This is a curated list of such articles (soft limit 100):
        
        
          
            
            - 
              Visual design rules you can safely follow every time,
              tldr:
              
                - Use near-black and near-white instead of pure black and white.
 
                - Saturate your neutrals, e.g. very light red instead of grey.
 
                - Use high contrast for important elements: e.g. buttons should be high contrast whereas a divider does not.
 
                - Everything in your design should be deliberate: whitespace, alignment, shadows.
 
                - Optical alignment is often better than mathematical alignment.
 
                - Lower letter spacing and line height with larger text. Raise them with smaller text.
 
                - Container borders should contrast with both the container and the background.
 
                - Everything should be aligned with something else.
 
                - Colours in a palette should have distinct brightness values.
 
                - If you saturate your neutrals you should use warm or cool colours, not both, e.g. warm background with a cool foreground.
 
                - Measurements should be mathematically related.
 
                - Elements should go in order of visual weight.
 
                - If you use a horizontal grid, use 12 columns.
 
                - Spacing should go between points of high contrast.
 
                - Closer elements should be lighter.
 
                - Make drop shadow blur values double their distance values.
 
                - Put simple on complex or complex on simple.
 
                - Keep container colours within brightness limits.
 
                - Keep container colours within brightness limits.
 
                - Make outer padding the same or more than inner padding.
 
                - Keep body text at 16px or above.
 
                - Use a line length around 70 characters.
 
                - Make horizontal padding twice the vertical padding in buttons.
 
                - Use two typefaces at most.
 
              
             
            - 
              What's in a Good Error Message?,
              tldr:
              
                - Context: What led to the error? What was the code trying to do when it failed?
 
                - The error itself: What exactly failed?
 
                - Mitigation: What needs to be done in order to overcome the error?
 
              
             
            - 
              B+ trees
                and why they make for excellent data structures in databases, due to the fact that disk I/O is a
              significant factor for db performance and the fact that both HDDs and SSDs have hardware constraints that
              make the smallest I/O a block, laying out all the keys so that they fit within a 
block
              results in the best db performance. This can be achieved with slotted pages, separator key truncation and
              sibling pointers.
              
             
            - 
              Why bitcoin sucks:
              high transaction costs and extremely energy inefficient. Moreover, the pseudonymity of it all is
              being compromised by blockchain analysis.
            
 
            - 
              Centering in CSS,
              
                - 
                  Great for macro layouts containing paragraphs and headlines, prototypes, or generally things that
                  need legible centering:
                  
.content-center {
  display: grid;
  place-content: center;
  gap: 1ch;
}
                 
                - 
                  Great for micro and macro layouts:
                  
.gentle-flex {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1ch;
}
                 
                - 
                  Good for phrase-centric centering, tags, pills, buttons, chips, and more:
                  
.fluffy-center {
  padding: 10ch;
}
                 
              
             
            - 
              Write code, not to
                much, mostly functions, self explanatory.
            
 
            - 
              Forcing Functions
                in Software Development, to find issues with your app/project before you are forced to deal with
              them, do the following:
              
                - Use old hardware to run your app, performance issues will become obvious.
 
                - 
                  Delete project from your machine and set it up again, gaps in the setup documentation will be
                  exposed.
                
 
                - Add support for a different database, leaky db abstrations will be exposed.
 
                - Add support for a different platform and plaform agnostic abstrations will be exposed.
 
                - Release frequently to find issues with the release process.
 
                - 
                  Let users use your product without knowing anything about it and gaps in UX will immediately show
                  up!
                
 
              
             
            - 
              What do executives do, anyway?, the job of an executive
              is: to define and enforce culture and values for their whole organization, and to ratify good decisions.
              Values are not merely platitudes but something tangible like "tell the truth, even when it
              hurts." or "deliver the software on schedule, even if there are bugs."
            
 
            - 
              Network
                Protocols, a deep dive into the current networking stack including looking at the electronics behind
              the current
              ethernet frame size of 1500 bytes!
            
 
            - 
              Ownership,
              References &
                Borrowing
              and Lifetimes in Rust:
              
                - 
                  Rust ensures that there is exactly one binding to any given resource. This is important as object
                  handles which refer to the same object in memory could potentially be out of sync due to multiple
                  threads operating on it. Such move sematics also apply to objects passed via functions.
                
 
                - 
                  In order to operate on data via functions, Rust provides references which are immutable and allow
                  only reading data. Rust also provides a mutable reference but there can only be 1 mutable reference
                  to any particular object or 1 (or more) immutable references to it. This is in order to prevent race
                  conditions where 2 threads can write to a single resource. Moreover, any reference may not outlast
                  the scope of the original object. Again, this is in order to prevent any dangling references.
                
 
                - 
                  Rust provides a way to explicitly declare the lifetime of a reference so that it can never lead to
                  invalid behaviour like in the case when a reference to a resource is lent out but then deallocated,
                  leading to the 3rd party holding an illegal reference of which they are not aware.
                
 
              
             
            - 
              3 tribes of Computer Science, a great article that puts
              programmers into 3 camps:
              
                - 
                  Programmers who think in terms of mathematics and keeping code short and beautiful. Examples include
                  language wonks and functional programming champions.
                
 
                - 
                  Programmers who write code as close to the machine as possible for maximum efficiency. Examples
                  include hardware hackers and non-gc language proponents.
                
 
                - 
                  Programmers who just want to create solutions for others to use. This includes the majority of the
                  profession.
                
 
              
             
            - 
              How to build good software, an
              amazing article that identifies root causes of poorly produced software and illustrates some key steps
              in getting it right. Finally, the article also expounds on 10x engineers and how they simple make better
              decisions and automate things which enable other members along with freeing up mental resources for
              higher order problems. 
              On software issues:
              
                - Reusing good software is easy; it is what allows you to build good things quickly;
 
                - 
                  Software is limited not by the amount of resources put into building it, but by how complex it can
                  get before it breaks down; and
                
 
                - 
                  The main value in software is not the code produced, but the knowledge accumulated by the people who
                  produced it.
                
 
              
              On getting it done right:
              
                - Start as simple as possible;
 
                - Seek out problems and iterate; and
 
                - Hire the best engineers you can.
 
              
             
            - 
              Operating a
                high-scale distributed system, A great overview of experience gained in operating a distributed
              sytem. Covers monitoring, on-call
              and anomaly detection, outages, postmortems, failover drills, SLAs. Includes tips on blameless
              postmortems and asking questions to dig down to the root cause of the issue, e.g. a bug appeared in the
              code because it could not be unit tested due to the fact that the system does not support test accounts.
              Also, a very important point is never try to fix code in production - always rollback and go through the
              normal review process.
            
 
            - 
              A
                primer on how concurrency safety is handled in different languages, a look at functional languages
              and immutability, Rust's borrow checker, behaviours in Pony and the
              actor model used in Dart/Erlang.
            
 
            - 
              Technical debt is
                not a debt, but an unhedged call option, as long as you acknowledge that you are taking on debt, it
              may make sense to take it on, e.g.
              shipping a product earlier with debt laden code will lead to a better ROI with which one could hire more
              resources to "repay" the debt. Note that this needs to be a very conscious decision with a fixed plan.
              Also, something to keep in mind - "If it ain't broke, don't fix it".
            
 
            - 
              System design - job scheduler, a very
              neat article on how to design an event processing engine in a high fault environment. Use a write heavy
              database to segment jobs and a co-ordinating service to execute the jobs. The database itself consists
              of simple 
job and job_state_transition tables.
             
            - 
              What is functional
                programming all about, the core of Functional Programming is thinking about data-flow rather than
              control-flow.
            
 
            - 
              Web design in 4 minutes, a very very basic css
              styling walkthrough!
            
 
            - 
              React
                16 migration engineering, brilliant take on migration engineering, illustrates the use of:
              
                - feature toggles to reduce merge conflicts
 
                - TDD for api coverage
 
                - regression logging for faster feedback loop
 
                - coverage chart for motivation
 
                - staggered rollout and A/B testing with an eye on product metrics for migration issues
 
              
             
            - 
              The Earth is flat, the
              scientific method has been tremendously successful in explaining the workings of our world. It led to
              exponential expansion of science and technology that started in the 19th century and continues to this
              day. We are so used to its successes that we are betting the future of humanity on it. Usually when
              somebody attacks the scientific method, they are coming from the background of obscurantism. Such
              attacks are easily rebuffed or dismissed. What I’m arguing is that science is not a property of the
              Universe, but rather a construct of our limited brains. We have developed some very sophisticated tools
              to create models of the Universe based on the principle of composition. Mathematics is the study of
              various ways of composing things and physics is applied composition. There is no guarantee, however,
              that the Universe is decomposable. Assuming that would be tantamount to postulating that its structure
              revolves around human brains, just like we used to believe that the Universe revolves around Earth.
            
 
            - 
              Love your bugs, some really interesting
              bugs and the attitude + mindset required for effective bugfixing.
            
 
            - 
              Why don't software
                development methodologies work?, Essentially, the secret to a team's success is a shared vision and
              effective communication.
              Methodologies are rather pointless if the previous does not hold true.
            
 
            - 
              Things you should
                never do - Joel Spolsky, never re-write anything from "scratch", code does not rust, you will be
              thowing away a lot domain
              knowledge and bug fixes - try to incrementally refactor the codebase
            
 
            - 
              Strategy Letter V - Joel
                Spolsky, Micro economics 101, try to commoditize your products complement so that the demand for
              your product
              goes up:
              
                - Microsoft makes a free browser so that more people by it's operating system,
 
                - 
                  Google makes software so that more people rely on it to feed it information which it can use for
                  better search results which leads to them getting the lions share of advertising money (this example
                  was added by me)
                
 
                - Note that it is easier for software to commoditize hardware than the other way around
 
              
             
            - 
              Floating point visually
                explained, In the C language, floats are 32 bits container following the IEEE 754 standard. Their
              purpose is to
              store and allow operations on approximation of real numbers. The 32 bits are divided in three sections:
              
                - 1 bit S for the sign
 
                - 8 bits E for the exponent
 
                - 23 bits for the mantissa
 
                - 
                  Instead of Exponent, think of a Window between two consecutive power of two integers. Instead of a
                  Mantissa, think of an Offset within that window. The window tells within which two consecutive
                  power-of-two the number will be: [0.5,1], [1,2], [2,4], [4,8] and so on (up to [21272127,21282128].
                  The offset divides the window in 223=8388608223=8388608 buckets. With the window and the offset you
                  can approximate a number. The window is an excellent mechanism to protect from overflowing. Once you
                  have reached the maximum in a window (e.g [2,4]), you can "float" it right and represent the number
                  within the next window (e.g [4,8]). It only costs a little bit of precision since the window becomes
                  twice as large.
                
 
              
             
            - 
              Laws of UX:
              
                - 
                  The time to acquire a target is a function of the distance to and size of the target -- Paul Fitts.
                  E.g. if a function needs to be accessed often and/or quickly, make the button big
                
 
                - 
                  The time it takes to make a decision increases with the number and complexity of choices -- William
                  Edmund Hick and Ray Hyman. E.g. only provide choices when a good default does not exist.
                
 
                - 
                  Users spend most of their time on other sites. This means that users prefer your site to work the
                  same way as all the other sites they already know -- Jakob Nielsen. E.g. respect the platform’s
                  conventions and interface guidelines.
                
 
                - 
                  People will perceive and interpret ambiguous or complex images as the simplest form possible,
                  because it is the interpretation that requires the least cognitive effort of us -- Law of Prägnanz.
                  E.g. do not stuff too much detail into a small space.
                
 
                - 
                  Objects that are near, or proximate to each other, tend to be grouped together -- Law of Proximity.
                  E.g. put actions that do similar things together.
                
 
                - 
                  The average person can only keep 7 (plus or minus 2) items in their working memory -- George Miller.
                  E.g. reduce the number of things your users have to remember.
                
 
                - 
                  Any task will inflate until all of the available time is spent -- Cyril Northcote Parkinson. E.g.
                  make tasks short, simple and with set deadlines
                
 
                - 
                  Users have a propensity to best remember the first and last items in a series -- Serial Position
                  Effect. E.g. put the important things at the beginning or at the end.
                
 
                - 
                  Tesler’s Law, also known as The Law of Conservation of Complexity, states that for any system there
                  is a certain amount of complexity which cannot be reduced. E.g. removing features from your product
                  may result in users not being able to achieve some goals.
                
 
                - 
                  The Von Restorff effect, also known as The Isolation Effect, predicts that when multiple similar
                  objects are present, the one that differs from the rest is most likely to be remembered. E.g. make
                  the most important thing stand out. Alternatively: If you want to stand out from competition, find a
                  feature which is always the same and make it different.
                
 
              
             
            - 
              The 3 stages of failure in Life and Work:
              
                - 
                  Stage 1 is a Failure of Tactics. These are HOW mistakes. They occur when you fail to build robust
                  systems, forget to measure carefully, and get lazy with the details. A Failure of Tactics is a
                  failure to execute on a good plan and a clear vision. Fixing a failure of tactics involves recording
                  your process, measuring your outcomes (the provided example of measuring your progress at the gym
                  hit home), and finally reviewing and adjusting your tactics.
                
 
                - 
                  Stage 2 is a Failure of Strategy. These are WHAT mistakes. They occur when you follow a strategy
                  that fails to deliver the results you want. You can know why you do the things you do and you can
                  know how to do the work, but still choose the wrong what to make it happen. Fixing a failure of
                  strategy involves launching it quickly, doing it cheaply and revising it rapidly (startup 101).
                
 
                - 
                  Stage 3 is a Failure of Vision. These are WHY mistakes. They occur when you don't set a clear
                  direction for yourself, follow a vision that doesn't fulfill you, or otherwise fail to understand
                  why you do the things you do. Most importantly (and also something that resonated with me
                  personally), fixing a failure of vision involves taking stock of your life, determining your
                  non-negotiable and then navigating criticism!
                
 
              
             
            - 
              What every programmer absolutely, positively needs to know
                about encodings and character sets to work with text, an update to the following article by Joel,
              this one goes into details regarding how the code points actually look like in binary:
              
                - 
                  Text is always a sequence of bits which needs to be translated into human readable text using lookup
                  tables. If the wrong lookup table is used, the wrong character is used.
                
 
                - 
                  You're never actually directly dealing with "characters" or "text", you're always dealing with bits as
                  seen through several layers of abstractions. Incorrect results are a sign of one of the abstraction
                  layers failing.
                
 
                - 
                  If two systems are talking to each other, they always need to specify what encoding they want to talk
                  to each other in. The simplest example of this is this website telling your browser that it's encoded
                  in UTF-8.
                
 
                - 
                  In this day and age, the standard encoding is UTF-8 since it can encode virtually any character of
                  interest, is backwards compatible with the de-facto baseline ASCII and is relatively space efficient
                  for the majority of use cases nonetheless.
                
 
                - The days of one byte = one character are over and both programmers and programs need to
                  catch up on this.
 
              
             
            - 
              The
                absolute minimum every software developer must know about unicode and character sets - Joel
                Spolsky, long story short there is no such thing as plain text. Unicode is a standard that defines
              characters
              as code points. Initially, there were less than 65,536 characters so it was possible to store each
              character using 2 bytes (16 bits). However, once the standard grew, there evolved multiple character
              encoding schemes: UTF-8 (where every code point from 0-127 is stored in a single byte. Only code points
              128 and above are stored using 2, 3, in fact, up to 6 bytes), UTF-16, UTF-7, UTF-32, Windows-1252 (the
              Windows 9x standard for Western European languages), ISO-8859-1, aka Latin-1 (also useful for any
              Western European language). Note that the UTF encodings can also potentially have a Byte Order Mark
              (BOM) at the start of the string which indicates their endianess. Finally, it really only makes sense to
              use UTF-8 as it is the most efficient with higest compatibility :)
            
 
            - 
              Advanced web security
                topics
            
 
          
         
        Classic
        
          The following is snippets of useful information (condensed from articles similar to the above which didn't
          make the cut):
        
        
          
            - 
              That XOR trick, Use XOR to remove duplicates and/or
              swap. HN discussion is also very relevant.
            
 
            - 
              Simpson's paradox, Trends which
              appear in groups of data may disappear or reverse when the groups are combined.
            
 
            - 
              DevOps and SQL databases, using an SQL
              database is no excuse for not following good DevOps practices - either manage schema versions in code
              with auto upgrade and rollback or decouple code from the database so that schema changes can be made
              independent of code deployments. Also interesting to note the 5 phases of a live schema change:
              
                - 
                  The running code reads and writes the old schema, selecting just the fields that it needs from the
                  table or view. This is the original state.
                
 
                - 
                  Expand: The schema is modified by adding any new fields but not removing any old ones. No code
                  changes are made. If a rollback is needed, it's painless because the new fields are not being used.
                
 
                - 
                  Code is modified to use the new schema fields and pushed into production. If a rollback is needed,
                  it just reverts to phase 2. At this time any data conversion can be done while the system is live.
                
 
                - 
                  Contract: Code that references the old, now unused, fields is removed and pushed into production. If
                  a rollback is needed, it just reverts to phase 3.
                
 
                - 
                  Old, now unused, fields are removed from the schema. In the unlikely event that a rollback is needed
                  at this point, the database would simply revert to phase 4.
                
 
              
             
            - 
              The point of
                microservices, is being able to deploy and test independently for rapid iteration. The article
              itself does not cover
              version management however.
            
 
            - 
              A road to Common LISP, an
              excellent resource on getting started with lisp - basically get SBCL and a couple of books :)
            
 
            - 
              "Concurrency is dealing with inevitable timing-related conflicts, parallelism is avoiding unnecessary
              conflicts". A concurrent solution to an event handling problem uses a queue to resolve conflicts whereas
              a parallel solution to a computational problem avoids unnecessary conflicts:
              Vending machine vs. gifts,
              Parallelism and
                concurrency need different tools.
            
 
            - 
              Wealth is not finite - creation of wealth is independent of the money supply. If you make a gift for
              someone using stones arranged in the shape of a heart, you have created something desirable and hence
              you are the more wealthier for it.
            
 
            - 
              "A good scientist, in other words, does not merely ignore conventional wisdom, but makes a special
              effort to break it. Scientists go looking for trouble. This should be the m.o. of any scholar, but
              scientists seem much more willing to look under rocks." - Paul Graham
            
 
            - 
              The
                Log: what every software engineer should know about real-time data's unifying abstraction, use a log
              infrastructure like Apache kafka for distributed data consistency - a bit enterprise heavy
              but some neat insights.
            
 
            - 
              Event-sourcing made
                simple, Event sourcing is like git for data. There are generally four components that make a
              (minimal) Event
              Sourcing system:
              
                - Events: persisted and immutable.
 
                - Aggregates: represent the current state of the application.
 
                - Calculators: read events and update aggregates accordingly.
 
                - 
                  Reactors: react to events as they are created. They trigger side-effects and might create other
                  events in turn.
                
 
              
             
            - 
              Stacked diffs vs.
                Pull-requests, The basic idea of stacked diffs is that you have a local checkout of the repository
              which you can
              mangle to your heart's content. The only thing that the world needs to care about is what you want to
              push out for review. This means you decide what view of your local checkout the reviewers see. You
              present something that can be "landed" on top of master. 
              The typical workflow is to work right on top of master, committing to master as you go. For each of the
              commits, you then use the Phabricator command line tool to create a "Diff" which is the Phabricator
              equivalent of a Pull Request. Unlike Pull Requests, Diffs are usually based on exactly one commit and
              instead of pushing updates as additional commits, you update the single commit in place and then tell
              Phabricator to update the remote view. When a Diff gets reviewed and approaved, you can "land" it onto
              remote master. Your local copy and master don't have to be in perfect sync in order to do this. You can
              think of this as the remote master cherry-picking the specific commit from your git history.
             
            - 
              5 mundane Java
                performance tricks:
              
                - Size HashMaps whenever possible because resizing them is an expensive process
 
                - Don't iterate over Enum.values() because it creates an expensive array on the fly.
 
                - Use enums instead of constant Strings, especially EnumMap as Enums are more performant.
 
                - Use wrappers for composite HashMap keys, or rather do not concatenate String(s) to make a key as
                  String hash computations are expensive.
 
                - Stop using JDK8 as the performance of String is much improved in JDK11 and above.