<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Dmitry Halai]]></title><description><![CDATA[Thoughts, stories and ideas.]]></description><link>https://d-halai.com/</link><image><url>https://d-halai.com/favicon.png</url><title>Dmitry Halai</title><link>https://d-halai.com/</link></image><generator>Ghost 5.32</generator><lastBuildDate>Sun, 19 Apr 2026 20:35:16 GMT</lastBuildDate><atom:link href="https://d-halai.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Quick course review: Distributed Systems by Dr. Martin Kleppmann]]></title><description><![CDATA[A quick review of the related course.]]></description><link>https://d-halai.com/course-review-distributed-systems-kleppmann/</link><guid isPermaLink="false">63e4da80afbde009a96c114a</guid><category><![CDATA[Algorithms]]></category><category><![CDATA[Education]]></category><dc:creator><![CDATA[Dmitry Halai]]></dc:creator><pubDate>Thu, 09 Feb 2023 15:42:00 GMT</pubDate><media:content url="https://d-halai.com/content/images/2023/02/CAP.png" medium="image"/><content:encoded><![CDATA[<img src="https://d-halai.com/content/images/2023/02/CAP.png" alt="Quick course review: Distributed Systems by Dr. Martin Kleppmann"><p><br>I recently finished watching a tremendous free distributed systems course. The lecturer is a famous Dr. Martin Kleppmann who wrote a well-known book with the red wild boar cover &#x1F604;</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/02/book-cover.png" class="kg-image" alt="Quick course review: Distributed Systems by Dr. Martin Kleppmann" loading="lazy" width="748" height="982" srcset="https://d-halai.com/content/images/size/w600/2023/02/book-cover.png 600w, https://d-halai.com/content/images/2023/02/book-cover.png 748w" sizes="(min-width: 720px) 720px"><figcaption>Design Data-Intensive Applications book cover</figcaption></figure><p>This course includes 8 lectures split into 23 videos:</p><ol><li>Introduction</li><li>Models of distributed systems</li><li>Time, clocks, and ordering of events</li><li>Broadcast protocols and logical time</li><li>Replication</li><li>Consensus</li><li>Replica consistency</li><li>Case studies</li></ol><p>Martin made a great introduction to distributed systems. He starts with basic concepts and terms definition. Martin explains why it&apos;s important to understand how these systems work nowadays and where they&apos;re used.<br><br>Then, he switches to the main issues related to distributed systems and describes 2 problems:</p><ul><li>The two generals problem</li><li>The Byzantine generals problem</li></ul><p>Martin also explains what the <em>system mode</em>l is and how it&apos;s related to faults that can occur. The distributed systems algorithms help to deal with it. He came to the conclusion for distributed systems we need to pick one statement from each part:</p><ol><li><strong>Network: </strong>reliable, fair-loss, or arbitrary</li><li><strong>Nodes:</strong> crash-stop, crash-recovery, or Byzantine</li><li><strong>Timing:</strong> synchronous, partially synchronous, or asynchronous</li></ol><hr><p>In the <strong>&quot;Time, clocks, and ordering of events&quot;</strong> lecture, Martin explains the monotonic clocks and the clock synchronization process. He also shows why we cannot rely on the physical clock in distributed systems. &#xA0;</p><hr><p>The <strong>&quot;Broadcast protocols and logical time&quot; </strong>lecture is about the difference between <em>physical</em> and <em><a href="https://en.wikipedia.org/wiki/Logical_clock">logical</a></em> clocks (Lamport and Vector clocks), and broadcast algorithms (FIFO broadcast, Causal broadcast, Total order broadcast, and FIFO-total order broadcast).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/02/Screenshot-2023-02-09-at-16.04.46.png" class="kg-image" alt="Quick course review: Distributed Systems by Dr. Martin Kleppmann" loading="lazy" width="1889" height="1409" srcset="https://d-halai.com/content/images/size/w600/2023/02/Screenshot-2023-02-09-at-16.04.46.png 600w, https://d-halai.com/content/images/size/w1000/2023/02/Screenshot-2023-02-09-at-16.04.46.png 1000w, https://d-halai.com/content/images/size/w1600/2023/02/Screenshot-2023-02-09-at-16.04.46.png 1600w, https://d-halai.com/content/images/2023/02/Screenshot-2023-02-09-at-16.04.46.png 1889w" sizes="(min-width: 720px) 720px"><figcaption>Relationships between broadcast models</figcaption></figure><hr><p>The 5th lecture explains &quot;<strong>Replication</strong>&quot;. Martin shows what <em><a href="https://martinfowler.com/articles/patterns-of-distributed-systems/idempotent-receiver.html">idempotency</a></em> means in distributed systems and how to make the system idempotent. He also describes the <em>quorum</em> and <em>replication</em> mechanism.</p><hr><p>The next part is all about &quot;<strong>Consensus</strong>&quot; and related algorithms.</p><blockquote>The two best-known consensus algorithms are Paxos and Raft. In its original formulation, Paxos provides only consensus on a single value, and the MultiPaxos algorithm is a generalisation of Paxos that provides FIFO-total order broadcast. On the other hand, Raft is designed to provide FIFO-total order broadcast &#x201C;out of the box&#x201D;.</blockquote><hr><p>The &quot;<strong>Replica consistency</strong>&quot; chapter explains the <em>two-phase commit</em> (2PC), <em>linearizability</em>, &#xA0;and <em>eventual consistency</em> model. Martin explains related algorithms and limitations based on the <em><a href="https://en.wikipedia.org/wiki/CAP_theorem">CAP theorem</a>.</em></p><hr><p>The last part (&quot;<strong>Case studies</strong>&quot;) is important because it shows real examples of distributed systems and how they deal with mentioned issues. &#xA0;Martin describes the <em>conflict-free replicated data types</em> (CRDTs) that help to manage the case when several concurrent writes to the same object need to be integrated into a single final state. He also shows the logic that stays behind Google&#x2019;s Spanner database.</p><hr><h2 id="summary">Summary</h2><p>It&apos;s a definitive lore gem. Martin explains everything in detail so everyone can understand the major algorithms and rules that stay behind distributed systems.<br>Of course, it&apos;s not so easy to remember all of these concepts, but after finishing the course you will get a good understanding of distributed systems and how they work. You also can always return back and refresh your knowledge if it&apos;s needed. The great thing is this knowledge (as well as Martin&apos;s most popular book) is fundamental. Thanks, Martin for making it publicly available &#x2764;&#xFE0F;!<br><br>Lecture videos: <a href="https://www.youtube.com/playlist?list=PLeKd45zvjcDFUEv_ohr_HdUFe97RItdiB">https://www.youtube.com/playlist?list=PLeKd45zvjcDFUEv_ohr_HdUFe97RItdiB</a><br>Coursebook: <a href="https://www.cl.cam.ac.uk/teaching/2122/ConcDisSys/dist-sys-notes.pdf">https://www.cl.cam.ac.uk/teaching/2122/ConcDisSys/dist-sys-notes.pdf</a></p><p>P.S. Interestingly Martin recommends reading the &#xA0;&#x201C;Distributed Systems&#x201D; book by van Steen &amp; Tanenbaum. That&apos;s something I&apos;m currently <a href="https://d-halai.com/my-2023-reading-list/">into</a>. I started participating in a &quot;<a href="https://t.me/its_reading_club">Code of Architecture</a>&quot; book reading class organized by an architecture team of one of the biggest tech banks. They run a weekly call with some guests or internal architects where they discuss a particular chapter from the book they&apos;re currently reading. Alexander Polomodov (Director of their digital ecosystem development department) also has a <a href="https://apolomodov.medium.com/">tech blog</a> on Medium where he publishes his book reviews. As for me, it&apos;s a great format that helps me to keep reading pace and to be a motivated learner. It also allows me to understand better the book material based on real examples and discussions.</p>]]></content:encoded></item><item><title><![CDATA[Book review – Fundamentals of Software Architecture: An Engineering Approach]]></title><description><![CDATA[Review of the Fundamentals of Software Architecture: An Engineering Approach book.]]></description><link>https://d-halai.com/review-fundamentals-of-software-architecture/</link><guid isPermaLink="false">63dbd4e7afbde009a96c0c09</guid><category><![CDATA[Books]]></category><dc:creator><![CDATA[Dmitry Halai]]></dc:creator><pubDate>Sat, 04 Feb 2023 20:44:00 GMT</pubDate><media:content url="https://d-halai.com/content/images/2023/02/Fundamentals-of-Software-Architecture.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://d-halai.com/content/images/2023/02/Fundamentals-of-Software-Architecture.jpg" alt="Book review &#x2013; Fundamentals of Software Architecture: An Engineering Approach"><p>I recently finished reading the book I&apos;ve heard a lot of. Both authors are well-known Software Architects with dozen years of experience. Mark Richards, for example, runs great bi-weekly <strong>Software Architecture Monday </strong><a href="https://www.developertoarchitect.com/lessons/">lessons</a><strong>.</strong><br>I want to share my opinion about this book, save some notes I made, and explain why I think it is worth to be read.</p><p>The book is well-structured and it has 3 main parts:</p><ol><li><strong>Foundations</strong></li><li><strong>Architecture Styles</strong></li><li><strong>Techniques and Soft Skills</strong></li></ol><h2 id="foundations">Foundations</h2><p>Authors start with the definition of software architecture and Architecture role. They says the architecture consists of several things:</p><ol><li>Structure</li><li>Architecture Characteristics</li><li>Architecture Decisions</li><li>Design Priciples &#xA0;</li></ol><p>The <strong>architecture</strong> <strong>structure</strong> describes the system based on the used architecture styles.<br><br>The <strong>architecture</strong> <strong>characteristics</strong> of the system are the same as the nonfunctional requirements. Architects can use them for describing architecture structures and being able to compare different design decisions and approaches.<br>Here&apos;s the list of some architecture characteristics.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/02/Architecture-characteristics-min.jpg" class="kg-image" alt="Book review &#x2013; Fundamentals of Software Architecture: An Engineering Approach" loading="lazy" width="1066" height="937" srcset="https://d-halai.com/content/images/size/w600/2023/02/Architecture-characteristics-min.jpg 600w, https://d-halai.com/content/images/size/w1000/2023/02/Architecture-characteristics-min.jpg 1000w, https://d-halai.com/content/images/2023/02/Architecture-characteristics-min.jpg 1066w" sizes="(min-width: 720px) 720px"><figcaption><strong>Some of architecture</strong> <strong>characteristics</strong></figcaption></figure><p>The <strong>architecture decisions </strong>define the rules for how a system should be constructed. It&apos;s based on architecture characteristics the system should provide.</p><p>The <strong>design principles </strong>behave like a guideline. They are more recommendations than strict rules engineers should follow in order to build the desired system.</p><p>Authors also define the expectations of an architect. They highlight and describe 8 core expectations:</p><ol><li>Make architecture decisions</li><li>Continually analyze the architecture</li><li>Keep current with the latest trends</li><li>Ensure compliance with decisions</li><li>Diverse exposure and experience</li><li>Have business domain knowledge</li><li>Possess interpersonal skills</li><li>Understand and navigate politics </li></ol><p>Two important software architecture statements are mentioned:</p><blockquote>Everything in software architecture is a trade-off.<br>&#x2013; First Law of Software Architecture</blockquote><blockquote><em><strong>Why</strong></em> is more important than <em><strong>how.</strong></em><br>&#x2013; Second Law of Software Architecture</blockquote><p>A good software architect should also have architectural thinking (thanks captain obvious &#x1F642;). So authors say it&apos;s based on <strong>analyzing trade-offs </strong>and <strong>understanding business drivers</strong> skills. <br><br>Then, they focus on <em><a href="https://en.wikipedia.org/wiki/Modular_programming">modularity</a></em><strong>. </strong>It&apos;s mentioned how to measure <em>modularity</em> by using <em><a href="https://en.wikipedia.org/wiki/Cohesion_(computer_science)">cohesion</a></em>, <em><a href="https://en.wikipedia.org/wiki/Coupling_(computer_programming)">coupling</a></em>, and <em><a href="https://en.wikipedia.org/wiki/Connascence">connascence</a></em>. Authors use specific formulas that help to calculate these metrics.</p><p>Several next chapters are related to architecture characteristics:</p><ul><li><strong>definition</strong> of architecture characteristics: operational, structural, and cross-cutting;</li><li><strong>identification</strong> of architecture characteristics: explicit and implicit;</li><li><strong>measuring and governing</strong> architecture characteristics: operational and structural measures + fitnes functions;</li><li><strong>scope</strong> of architecture characteristics.</li></ul><p>All this information is extended by architecture katas and decisions based on architecture characteristics. It&apos;s useful to see how the theoretical information can be applied to real-world examples.<br><br>When we understand architecture characteristics it is time to return back to the modularity and discuss the component-based thinking.</p><p>Components can be presented as:</p><ol><li>Libraries: wrappers, that communicate via language function call mechanism.</li><li>Services: run in its own address space, communicate via different protocols (HTTP, TCP/IP, etc..), and form standalone units.</li></ol><p>Components can be grouped by using 2 approaches:</p><ol><li>Technical partitioning (layered architecture).</li><li>Domain partitioning (service architecture).</li></ol><p>Authors describe how to identify components, analyze their roles and characteristics. <br><br>There&apos;re 3 main components discovering approaches:</p><ul><li>Actor/Actions approach: map requirements to components (what they can do and perform).</li><li><a href="https://www.eventstorming.com/">Event storming</a>: comes from DDD and based on an assumption the system will use messages/events as a communication channel.</li><li>Workflow approach: it&apos;s similar to the event storming approach but without the constraints to use the message-based channel.</li></ul><p>When the foundation is covered, it&apos;s time to understand architecture styles that exist nowadays.</p><h2 id="architecture-styles">Architecture Styles</h2><p>This part authors start with the differences between monolithic (single deployment unit of all code) and distributed (multiple deployment units connected through remote access protocols) systems. </p><p><strong>Monolithic</strong> architectures can be:</p><ol><li>Layered</li><li>Pipeline</li><li>Microkernel</li></ol><p><strong>Distributed </strong>architectures include:</p><ol><li>Sevice-based</li><li>Event-driven</li><li>Space-based</li><li>Service-oriented </li><li>Microservices</li></ol><p>It&apos;s said that distributed architecture styles have multiple advantages but they also have plenty of difficulties or <em>fallacies</em>. <br>Here&apos;s the image of the list of <a href="https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing">8 fallacies of distributed systems</a> I took from a <a href="https://blog.bytebytego.com/">great technical blog</a>. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/02/Fallacies-of-distributed-computing.jpg" class="kg-image" alt="Book review &#x2013; Fundamentals of Software Architecture: An Engineering Approach" loading="lazy" width="2000" height="1773" srcset="https://d-halai.com/content/images/size/w600/2023/02/Fallacies-of-distributed-computing.jpg 600w, https://d-halai.com/content/images/size/w1000/2023/02/Fallacies-of-distributed-computing.jpg 1000w, https://d-halai.com/content/images/size/w1600/2023/02/Fallacies-of-distributed-computing.jpg 1600w, https://d-halai.com/content/images/size/w2400/2023/02/Fallacies-of-distributed-computing.jpg 2400w" sizes="(min-width: 720px) 720px"><figcaption>Fallacies of distributed systems: bytebytego.com</figcaption></figure><p>All of these fallacies are quite obvious but engineers often don&apos;t take them into account when they build distributed systems.</p><p>Then authors describe 8 architecture styles with the topology, diagrams, and good examples:</p><ol><li><strong>Layered architecture</strong>: a style with several isolation levels, e.g. presentation layer, business layer, services layer, persistence layer, database layer.<br>Examples: a standard frontend, backend, and database isolation inside a single monolith.</li><li><strong>Pipeline architecture</strong>: it came from Unix systems where functionality is split into discrete parts that can communicate with each other via pipes.<br>Examples: ETL tools, Apache Camel.</li><li><strong>Microkernel architecture</strong>: it includes a core system and <em>plug-in </em>components.<br>Examples: Eclipse IDE, Jira, Jenkins.</li><li><strong>Service-Based architecture</strong>: independent applications that are deployed separately but usually have a single database.</li><li><strong>Event-Driven architecture</strong>: it&apos;s made up of decoupled event processing components that asynchronously receive and process events. There are 2 topology types: <em>mediator </em>(a single node that is responsible for all communications between other nodes) and <em>broker</em> (there&apos;s no central place that manages all the messages).</li><li><strong>Space-based architecture</strong>: it&apos;s based on processing units that can have a shared database but should also include replicated local storages (caches).</li><li><strong>Orchestration-Driven Service Oriented architecture</strong>: it uses shared resources and communication buses across multiple services. It sounds more like an enterprise legacy.</li><li><strong>Microservices architecture</strong>: it includes multiple services for each bounded context. Each service is independant and include its own persistance layer (database). The communication between services can use the <em>choreography</em> or the <em>orchestration</em> approach (similar to the Event-Driver architecture style).</li></ol><p>When the main architecture styles are described, it&apos;s time to see how to choose the correct one for a particular system. Authors mention the evaluation approach that allows architecture to build systems based on:</p><ul><li>Observations from the past</li><li>Changes in the ecosystem</li><li>New capabilities</li><li>Acceleration</li><li>Domain changes</li><li>Technology changes</li><li>External factors</li></ul><p>In order to compare these styles, authors use a set of architecture characteristics. I created a summary table with all the described architecture styles.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/02/Architecture-sytles-comparison.jpg" class="kg-image" alt="Book review &#x2013; Fundamentals of Software Architecture: An Engineering Approach" loading="lazy" width="1038" height="963" srcset="https://d-halai.com/content/images/size/w600/2023/02/Architecture-sytles-comparison.jpg 600w, https://d-halai.com/content/images/size/w1000/2023/02/Architecture-sytles-comparison.jpg 1000w, https://d-halai.com/content/images/2023/02/Architecture-sytles-comparison.jpg 1038w" sizes="(min-width: 720px) 720px"><figcaption>Comparison of Architecture Styles</figcaption></figure><p>The main point here is (again):</p><blockquote><em>Everything is a trade-off.</em></blockquote><p>However, knowing all these styles doesn&apos;t automatically make you an architect. You also need...</p><h2 id="techniques-and-soft-skills">Techniques and Soft Skills</h2><p>In the last part of this book authors cover other important topics:</p><ul><li>decision justification;</li><li>documentation;</li><li>communication.</li></ul><p>They describe the architecture decision anti-patterns:</p><ol><li><strong>Covering your assets</strong>: avoiding making the decision out of fear of making the wrong choice. &#xA0;<br>Solution: wait until the last responsible moment</li><li><strong>Groundhog day</strong>: it happens when people don&apos;t understand why this decision has been made and constantly asking about the reasons.<br>Solution: provide clear technical and business justifications.</li><li><strong>Email-drivern architecture</strong>: it happens when there is no central place where the architecture decisions are stored.<br>Solution: keep architecture decision records (ADR) in a single point of truth, e.g. git repo.</li></ol><p>Then, authors explain the structure of architecture decision records (<a href="https://github.com/joelparkerhenderson/architecture-decision-record">ADR</a>) and request for comments (<a href="https://ru.wikipedia.org/wiki/RFC">RFC</a>).</p><p>Possible ADR&apos;s structure:</p><ul><li>title;</li><li>status;</li><li>context;</li><li>decision;</li><li>consequences;</li><li>compliance;</li><li>notes.</li></ul><p>The interesting chapter in this part is related to the architecture risk analyze.<br>It&apos;s shown how to use the <em>risk matrix</em> and <em>risk assessment.</em></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/02/Risk-Matrix.jpg" class="kg-image" alt="Book review &#x2013; Fundamentals of Software Architecture: An Engineering Approach" loading="lazy" width="1298" height="769" srcset="https://d-halai.com/content/images/size/w600/2023/02/Risk-Matrix.jpg 600w, https://d-halai.com/content/images/size/w1000/2023/02/Risk-Matrix.jpg 1000w, https://d-halai.com/content/images/2023/02/Risk-Matrix.jpg 1298w" sizes="(min-width: 720px) 720px"><figcaption>Architecture risk matrix</figcaption></figure><blockquote>When leveraging the risk matrix to qualify the risk, consider the impact dimension first and the likelihood dimension second.</blockquote><p>For example, what is the impact if one of the services goes down and becomes unavailable? Let&apos;s say, it&apos;ll be an issue and the system won&apos;t be able to work without this service. So, the impact is high (3). However, let&apos;s assume, this service is situated in a highly available server or there&apos;s a cluster of these services. In that case, the potential risk is low(1). It gives us an overall risk rating of 3 (medium).</p><p>A risk assessment is a summarized report of the overall risk. It&apos;s based on analysis of every system element and its risk criteria by using the risk matrix.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/02/Risk-assesment-example.jpg" class="kg-image" alt="Book review &#x2013; Fundamentals of Software Architecture: An Engineering Approach" loading="lazy" width="1129" height="885" srcset="https://d-halai.com/content/images/size/w600/2023/02/Risk-assesment-example.jpg 600w, https://d-halai.com/content/images/size/w1000/2023/02/Risk-assesment-example.jpg 1000w, https://d-halai.com/content/images/2023/02/Risk-assesment-example.jpg 1129w" sizes="(min-width: 720px) 720px"><figcaption>Risk assessment example</figcaption></figure><p>The authors also say it&apos;s better to include as many senior engineers, team leaders, and architects in this analysis. This procedure is called <em>risk storming</em> (don&apos;t mess it with the event storming).</p><p>Then authors make a quick note about the tools, standards, and techniques that can be used for diagramming and making presentations: <a href="https://en.wikipedia.org/wiki/Unified_Modeling_Language#:~:text=The%20Unified%20Modeling%20Language%20(UML,the%20design%20of%20a%20system.">UML</a>, <a href="https://c4model.com/">C4</a>, <a href="https://en.wikipedia.org/wiki/ArchiMate">ArchiMate</a>.</p><p>The effective architect should also apply the correct level of control and understand plenty of external factors: </p><ul><li>team size;</li><li>team familiarity;</li><li>team experience;</li><li>project complexity;</li><li>project duration.</li></ul><p>And last but not least, soft skills play a huge role in an architect&apos;s career. Negotiation skills are important as well as the <em>4 C&apos;s of architecture</em>: Communication, Conciseness, Collaboration, and Clarity.</p><p>Architects should know so many things and constantly track new technologies. But how to do that in our busy lives? The authors propose to use the 20-minutes rule: spend this time learning something new every morning just before starting your job routine. One possible way is to build the personal <a href="https://www.thoughtworks.com/radar">technology radar</a>.</p><h2 id="summary">Summary</h2><p>The book is well-structured and gives a high-level overview of modern software architecture design practices and styles. I&apos;d recommend it to any Engineer who wants to better understand the responsibilities of the Software Architecture role as well as the main difficulties Architects need to deal with.<br><br>I&apos;ll definitely keep this book on my bookshelf and return to it from time to time. It tells a lot to me &#x1F44D;.</p><p>That&apos;s it! Theoretical knowledge is good but don&apos;t forget that:</p><blockquote class="kg-blockquote-alt">Practice is the proven way to build skills and become better at anything in life...including architecture.<br>&#x2013; Mark Richards &amp; Neal Ford</blockquote><p>P.S. The newest book of these authors &#xA0;&quot;<strong><strong>Software Architecture: The Hard Parts</strong>&quot; </strong>is already on <a href="https://d-halai.com/my-2023-reading-list/">my reading list</a> for 2023 and I can&apos;t wait to start learning it.</p>]]></content:encoded></item><item><title><![CDATA[My 2023 Reading List]]></title><description><![CDATA[<h2 id="motivation-and-selection">Motivation and Selection<br></h2><p>2022 was a really tough year so I read only 11 books &#x1F61E; <br><br>This year (2023) I decided to create a reading plan in advance and track my progress every week.<br><br>This list includes nonfiction, sci-fi, classics, and tech books. All of them were recommended by my</p>]]></description><link>https://d-halai.com/my-2023-reading-list/</link><guid isPermaLink="false">63da9eaeafbde009a96c0a8c</guid><category><![CDATA[Books]]></category><dc:creator><![CDATA[Dmitry Halai]]></dc:creator><pubDate>Wed, 01 Feb 2023 19:34:24 GMT</pubDate><media:content url="https://d-halai.com/content/images/2023/02/GettyImages-577674005_492115_zfpgiw-1.jpg" medium="image"/><content:encoded><![CDATA[<h2 id="motivation-and-selection">Motivation and Selection<br></h2><img src="https://d-halai.com/content/images/2023/02/GettyImages-577674005_492115_zfpgiw-1.jpg" alt="My 2023 Reading List"><p>2022 was a really tough year so I read only 11 books &#x1F61E; <br><br>This year (2023) I decided to create a reading plan in advance and track my progress every week.<br><br>This list includes nonfiction, sci-fi, classics, and tech books. All of them were recommended by my friends or other great people. Some of these books I&apos;ve already read but I want to re-read them for better understanding concepts and ideas that stay behind them. </p><p>It is a dynamic and unsorted list. It can be changed during the year but it should help me to keep the reading pace at least (or I hope so &#x1F604;).</p><h2 id="reading-list">Reading list<br></h2><p><strong>Building Evolutionary Architectures </strong>by Neal Ford, Rebecca Parsons, Patrick Kua, Pramod Sadalage</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/1-3.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="486"></figure><hr><p><strong>Software Architecture: The Hard Parts</strong> by Neal Ford, Mark Richards, Pramod Sadalage, Zhamak Dehghani</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/2-1.jpg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="446"></figure><hr><p><strong>Distributed systems for fun and profit </strong>by<strong> </strong>Mikito Takada</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/3-1.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="446"></figure><p></p><hr><p><strong>Distributed Systems </strong>by M. van Steen and A.S. Tanenbaum</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/4-1.png" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="419"></figure><p></p><hr><p><strong>Cryptonomicon </strong>by Neal Stephenson</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/5-1.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="547"></figure><p></p><hr><p><strong>A Man Called Ove </strong>by Fredrik Backman</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/6-1.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="480"></figure><p></p><hr><p><strong>The Inner Game of Tennis: The Classic Guide to the Mental Side of Peak Performance</strong> by W. Timothy Gallwey</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/7-1.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="516"></figure><p></p><hr><p><strong>Life 3.0: Being Human in the Age of Artificial Intelligence </strong>by Max Tegmark</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/8-1.jpg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="513"></figure><p></p><hr><p><strong>Entertaining Greece. Stories of Ancient Greek Culture</strong> by Mikhail Gasparov</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/9.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="439"></figure><p></p><hr><p><strong>The Millionaire Next Door: The Surprising Secrets of America&apos;s Wealthy </strong>by Thomas J. Stanley and William D. Danko</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/10-1.jpg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="500"></figure><p></p><hr><p><strong>The Empire Must Die: Russia&apos;s Revolutionary Collapse, 1900-1917 </strong>by<strong> </strong>Mikhail Zygar</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/11-1.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="526"></figure><p></p><hr><p><strong>A Brief History of Everything</strong> by<strong> </strong>Ken Wilber</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/12-1.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="509"></figure><p></p><hr><p><strong>The Beginning of Infinity: Explanations That Transform the World </strong>by David Deutsch</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/13-1.jpg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="527"></figure><p></p><hr><p><strong>How To Be A Stoic: Ancient Wisdom for Modern Living </strong>by Massimo Pigliucci</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/14-1.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="538"></figure><p></p><hr><p><strong>Behave: The bestselling exploration of why humans behave as they do </strong>by Robert M Sapolsky</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/15.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="522"></figure><hr><p><strong>12 Rules for Life: An Antidote to Chaos </strong>by Jordan B. Peterson</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/16.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="511"></figure><hr><p><strong>How the World Really Works: The Science Behind How We Got Here and Where We&apos;re Going </strong>by Vaclav Smil</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/17.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="513"></figure><hr><p><strong>The Intelligent Asset Allocator: How to Build Your Portfolio to Maximize Returns and Minimize Risk </strong>by William J. J. Bernstein</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/18.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="523"></figure><hr><p><strong>The Fabric of Reality </strong>by David Deutsch</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/19.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="531"></figure><hr><p><strong>The Psychology of Money: Timeless lessons on wealth, greed, and happiness </strong>by Morgan Housel</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/20.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="525"></figure><hr><p><strong>The Longevity Diet: Slow Aging, Fight Disease, Optimize Weight </strong>by Valter Longo</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/21.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="511"></figure><hr><p><strong>Thinking, Fast and Slow </strong>by Daniel Kahneman</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/02/22.jpeg" class="kg-image" alt="My 2023 Reading List" loading="lazy" width="340" height="522"></figure>]]></content:encoded></item><item><title><![CDATA[Hello, world! 👋]]></title><description><![CDATA[<p>I&apos;m Dmitry, a Software Engineer with an entrepreneurial mindset.<br>I&apos;m going to share here my thoughts, plans, ideas, and everything I&apos;ll find interesting.<br><br>Stay tuned!</p>]]></description><link>https://d-halai.com/coming-soon/</link><guid isPermaLink="false">63d3d629c1629713a27b738f</guid><category><![CDATA[News]]></category><dc:creator><![CDATA[Dmitry Halai]]></dc:creator><pubDate>Fri, 27 Jan 2023 13:48:25 GMT</pubDate><media:content url="https://d-halai.com/content/images/2023/01/hellodark13.png" medium="image"/><content:encoded><![CDATA[<img src="https://d-halai.com/content/images/2023/01/hellodark13.png" alt="Hello, world! &#x1F44B;"><p>I&apos;m Dmitry, a Software Engineer with an entrepreneurial mindset.<br>I&apos;m going to share here my thoughts, plans, ideas, and everything I&apos;ll find interesting.<br><br>Stay tuned!</p>]]></content:encoded></item><item><title><![CDATA[Asymptotic notation of algorithms: memo]]></title><description><![CDATA[<!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Algorithm complexity</th>
<th>Definition</th>
<th>The growth rate</th>
</tr>
</thead>
<tbody>
<tr>
<td>big O</td>
<td>T(x)=O(g(x))</td>
<td>The growth rate of f(x) is asymptotically <strong>less than or equal to</strong> (&lt;=) the growth rate of g(x)</td>
</tr>
<tr>
<td>little o</td>
<td>T(x)=o(g(x))</td>
<td>The growth rate of f(x) is asymptotically <strong>less than</strong></td></tr></tbody></table>]]></description><link>https://d-halai.com/asymptotic-notation-of-algorithms-memo/</link><guid isPermaLink="false">63d7c181afbde009a96c073a</guid><category><![CDATA[Algorithms]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Dmitry Halai]]></dc:creator><pubDate>Wed, 07 Dec 2016 23:00:00 GMT</pubDate><media:content url="https://d-halai.com/content/images/2023/01/4996.1513922020.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Algorithm complexity</th>
<th>Definition</th>
<th>The growth rate</th>
</tr>
</thead>
<tbody>
<tr>
<td>big O</td>
<td>T(x)=O(g(x))</td>
<td>The growth rate of f(x) is asymptotically <strong>less than or equal to</strong> (&lt;=) the growth rate of g(x)</td>
</tr>
<tr>
<td>little o</td>
<td>T(x)=o(g(x))</td>
<td>The growth rate of f(x) is asymptotically <strong>less than</strong> (&lt;) the growth rate of g(x)</td>
</tr>
<tr>
<td>big omega</td>
<td>T(x)=&#x3A9;(g(x))</td>
<td>The growth rate of f(x) is asymptotically <strong>greater than or equal to</strong> (&gt;=) the growth rate of g(x)</td>
</tr>
<tr>
<td>small omega</td>
<td>T(x)=&#x3C9;(g(x))</td>
<td>The growth rate of f(x) is asymptotically <strong>greater than</strong> (&gt;) the growth rate of g(x)</td>
</tr>
<tr>
<td>theta</td>
<td>T(x)=&#x398;(g(x))</td>
<td>The growth rate of f(x) is asymptotically <strong>equal to</strong> (=) the growth rate of g(x)</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><img src="https://d-halai.com/content/images/2023/01/4996.1513922020.jpg" alt="Asymptotic notation of algorithms: memo"><p><a href="http://bigocheatsheet.com/" rel="nofollow">Here</a> is an excellent resource with the Big-O cheat sheet.</p>]]></content:encoded></item><item><title><![CDATA[Sorting Algorithms]]></title><description><![CDATA[<p>Hi! As I mentioned <a href="https://d-halai.com/union-find-algorithms/">earlier</a>, I decided to recall some fundamental knowledge.<br>In this article, I&apos;d like to share with you the difference between sorting algorithms. I know, that it can be very simple, but how many times do you think about it? We all use it very</p>]]></description><link>https://d-halai.com/sorting-algorithms/</link><guid isPermaLink="false">63d7dbacafbde009a96c0919</guid><category><![CDATA[Algorithms]]></category><dc:creator><![CDATA[Dmitry Halai]]></dc:creator><pubDate>Sun, 28 Feb 2016 23:00:00 GMT</pubDate><media:content url="https://d-halai.com/content/images/2023/01/delish-m-ms-1531661960.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://d-halai.com/content/images/2023/01/delish-m-ms-1531661960.jpg" alt="Sorting Algorithms"><p>Hi! As I mentioned <a href="https://d-halai.com/union-find-algorithms/">earlier</a>, I decided to recall some fundamental knowledge.<br>In this article, I&apos;d like to share with you the difference between sorting algorithms. I know, that it can be very simple, but how many times do you think about it? We all use it very often (for example, the <code>sort</code> method in ruby), but not everyone takes a look under the hood.<br><br>So, here I want to describe the most popular sorting algorithms (again &#x1F642;).</p><h2 id="selection-sort">Selection Sort</h2><p>Selection sort is an algorithm that is based on scanning an array from left to right.<br>It means:</p><p>a) None entries situated on the right part of the sorted data are smaller than any entries from the left part<br>b) The left-side entries of the sorted data part are in ascending order</p><p>So, we start from the first element of the data with the index <code>i</code> and go through the data from left to right. If we find the smaller element, we need to change it with an element with an index <code>i</code>. In the next iteration, we move the pointer (index <code>i</code>) to the right by 1 and repeat searching smaller elements from the right part of the data.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/01/selection-sort.gif" class="kg-image" alt="Sorting Algorithms" loading="lazy" width="86" height="86"><figcaption>http://www.sorting-algorithms.com/selection-sort</figcaption></figure><p>The time complexity of the algorithm is <code>O(n2)</code>.</p><h2 id="insertion-sort">Insertion Sort</h2><p>Insertion sort is another simple sorting algorithm.<br>The main steps are:</p><p>a) Split the data into 2 parts: sorted and unsorted<br>b) Start from the first element of the data with the index <code>i</code> and put it into the sorted part<br>c) Increment the index <code>i</code> by 1, and select the next element<br>d) Find a new index for the selected element. Go through the sorted part of the data from right to left unless a smaller element is found<br>e) Insert the selected element into the sorted part of the data using a new index<br>f) Go to <code>c</code> until the data is sorted</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/01/insertion-sort.gif" class="kg-image" alt="Sorting Algorithms" loading="lazy" width="86" height="86"><figcaption>http://www.sorting-algorithms.com/insertion-sort</figcaption></figure><p>The time complexity of this algorithm is the same as for the selection sort: <code>O(n2)</code></p><h2 id="shellsort">Shellsort</h2><p><br>The <code>shellsort</code> &#xA0;algorithm is an improved version of the insertion sort.<br>This method is based on sorting pairs of elements that are situated far apart from each other.<br>Shellsort splits data into some parts using an <code>interval</code>. This <code>interval</code> is calculated by the formula that was introduced by Shell:<br><br>d = f l o o r ( g a p / 2 )<br>where the <code>gap</code> &#x2014; is an <code>interval</code> with the initial value <code>N</code> (count of elements).</p><p>The main steps of this algorithm are:</p><p>a) Initialize the value of <code>d</code><br>b) Divide the list into smaller sublists using an interval <code>h</code><br>c) Sort these sublists using the insertion sort algorithm<br>d) Repeat until the complete list is sorted</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/01/shell-sort.gif" class="kg-image" alt="Sorting Algorithms" loading="lazy" width="86" height="86"><figcaption>http://www.sorting-algorithms.com/shell-sort</figcaption></figure><p>The time complexity of the algorithm depends on the interval <code>d</code>.<br>In the worst case: <code>O(n2)</code>.<br>In the best case: <code>O(n&#x2217;log(n))</code>.</p><h2 id="mergesort">Mergesort</h2><p>Mergesort is one of the <code>divide-and-conquer</code> algorithms which is built on top of recursion.<br>Conceptually, the merge sort works as follows:</p><p>a) Divide the unsorted list into <code>n</code> sublists, each containing 1 element (a list of 1 element is considered as a sorted one).<br>b) Repeatedly merge sublists to produce new sorted sublists until there is only 1 remaining sublist. This will be the sorted list.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/01/merge-sort.gif" class="kg-image" alt="Sorting Algorithms" loading="lazy" width="86" height="86"><figcaption>http://www.sorting-algorithms.com/merge-sort</figcaption></figure><p>The time complexity of the algorithm in the worst case is <code>O(n&#x2217;log(n))</code>.</p><h2 id="quicksort">Quicksort</h2><p>The quick sort algorithm is a highly efficient algorithm that is also recursion-based.</p><p>The steps of the algorithm are:</p><p>a) Pick an element (<code>pivot</code>) from the initial array.<br>b) Partitioning: reorder the array so all elements with values <strong>less</strong> than the <code>pivot</code> will be placed before the <code>pivot</code>, while all the elements with values <strong>greater</strong> than the <code>pivot</code> will be placed after it (equal values can go either way).<br>After this partitioning, the <code>pivot</code> is in its final position. This is called the <code>partition operation</code>.<br>c) Recursively apply the above steps to the sub-array of elements with smaller values and to the sub-array of elements with greater values.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/01/quick-sort.gif" class="kg-image" alt="Sorting Algorithms" loading="lazy" width="86" height="86"><figcaption>http://www.sorting-algorithms.com/quick-sort</figcaption></figure><p>The quicksort&#x2019;s <code>divide-and-conquer</code> &#xA0;technique makes this algorithm a great parallel execution candidate.</p><p>The time complexity of the algorithm depends on <code>pivot</code> element and can be:</p><p>In the worst case: <code>O(n2)</code><br>In the best case: <code>O(n&#x2217;log(n))</code></p><h2 id="summary">Summary</h2><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Algorithm</th>
<th>Complexity (the worst case)</th>
<th>Complexity (the best case)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Selection Sort</td>
<td><code>O(n2)</code></td>
<td><code>O(n2)</code></td>
</tr>
<tr>
<td>Insertion Sort</td>
<td><code>O(n2)</code></td>
<td><code>O(n2)</code></td>
</tr>
<tr>
<td>Shellsort</td>
<td><code>O(n2)</code></td>
<td><code>O(n&#x2217;log(n))</code></td>
</tr>
<tr>
<td>Mergesort</td>
<td><code>O(n&#x2217;log(n))</code></td>
<td><code>O(n&#x2217;log(n))</code></td>
</tr>
<tr>
<td>Quicksort</td>
<td><code>O(n2)</code></td>
<td><code>O(n&#x2217;log(n))</code></td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>For small data sets, it is better to use the <code>selection sort</code> or <code>insertion sort</code> algorithms.<br>For other cases, it is better to prefer <code>O(n&#x2217;log(n))</code>algorithms.</p><p>Bonus: here is a great data structures and algorithms <a href="https://www.tutorialspoint.com/data_structures_algorithms/data_structures_algorithms_tutorial.pdf">tutorial</a>.</p>]]></content:encoded></item><item><title><![CDATA[Union-Find algorithms in Ruby]]></title><description><![CDATA[<p>It&#x2019;s always interesting to learn something new, especially if it&#x2019;s fundamental knowledge. </p><p>Recently I have found a very interesting course about <a href="https://www.coursera.org/course/algs4partI">algorithms</a>. Lectures are meaningful and practical. I recommend them to everyone who wants to understand basic algorithms.<br>All algorithms are implemented in Java, but I</p>]]></description><link>https://d-halai.com/union-find-algorithms/</link><guid isPermaLink="false">63d7c4b3afbde009a96c0793</guid><category><![CDATA[Algorithms]]></category><dc:creator><![CDATA[Dmitry Halai]]></dc:creator><pubDate>Fri, 05 Feb 2016 23:00:00 GMT</pubDate><media:content url="https://d-halai.com/content/images/2023/01/union_find.png" medium="image"/><content:encoded><![CDATA[<img src="https://d-halai.com/content/images/2023/01/union_find.png" alt="Union-Find algorithms in Ruby"><p>It&#x2019;s always interesting to learn something new, especially if it&#x2019;s fundamental knowledge. </p><p>Recently I have found a very interesting course about <a href="https://www.coursera.org/course/algs4partI">algorithms</a>. Lectures are meaningful and practical. I recommend them to everyone who wants to understand basic algorithms.<br>All algorithms are implemented in Java, but I decided to write them in Ruby too. In my view, it doesn&#x2019;t matter what language you choose in this case. The main goal is to better understand these algorithms.<br>So, in this post, I want to tell you about Union-Find (UF) algorithms.</p><h2 id="dynamic-connectivity">Dynamic connectivity</h2><p>Firstly, we should understand the reason of this type of algorithm. Just have a look at the picture:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/01/dynamic_connectivity.png" class="kg-image" alt="Union-Find algorithms in Ruby" loading="lazy" width="527" height="408"><figcaption>Dynamic connectivity</figcaption></figure><p>As you can see, there are 2 points: <code>p</code> and <code>q</code>. Question: is there a path between <code>p</code> and <code>q</code>? <br>Not so easy to answer, right? &#x1F642;<br><br>This type of problem is called the <code>connectivity</code> problem. <a href="https://en.wikipedia.org/wiki/Dynamic_connectivity">Wikipedia</a> says:</p><blockquote>In computing and graph theory, a dynamic connectivity structure is a data structure that dynamically maintains information about the connected components of a graph.</blockquote><p>So, <code>dynamic connectivity</code> is a data structure, which can be used for describing a graph. But, what does it mean? How can we use it for answering the question?<br>It means, we can describe the way from <code>p</code> to <code>q</code> through the graph of elements. Each element is a point, which can be connected with another one. For example, let&#x2019;s say we have 10 objects and they are separated initially (they are independent components):</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/01/initial_state.png" class="kg-image" alt="Union-Find algorithms in Ruby" loading="lazy" width="129" height="46"></figure><p>We can connect and check if some of them are already connected. The connection action is called <code>union</code>. The<code>Find</code> is an operation that checks if two objects are in the same component. So, we can <code>union</code> 4 with 3:</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/01/union_4_3.png" class="kg-image" alt="Union-Find algorithms in Ruby" loading="lazy" width="127" height="38"></figure><p>Here are more connectivity examples:</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/01/dynamic-connectivity-tiny.png" class="kg-image" alt="Union-Find algorithms in Ruby" loading="lazy" width="206" height="372"></figure><p>Now, we know what is the <code>dynamic connectivity</code>, but how can we implement it? There are some algorithms to do Union-Find operations.</p><h2 id="quick-find">Quick-Find</h2><p>The Quick Find is the easiest UF algorithm.</p><p></p><pre><code class="language-ruby">class QuickFind
  def initialize(size)
    @ids = (0..size-1).to_a
  end

  def find(index)
    @ids[index]
  end

  def connected?(p, q)
    find(p) == find(q)
  end

  def union(p, q)
    return if connected?(p, q)

    old = @ids[p]
    new = @ids[q]

    @ids.map! { |val| val = (val == old)? new : val }
  end

  def count
    @ids.uniq.size
  end
end</code></pre><p>The <code>find</code> operation just checks whether <code>p</code> and <code>q</code> are in the same component (have the same value). The <code>union</code> operation changes all entries with <code>@ids[p]</code> to <code>@ids[q]</code></p><h2 id="quick-union">Quick-Union</h2><p>The <code>Quick-Union</code> is a more complex algorithm.</p><p></p><pre><code class="language-ruby">class QuickUnion
  attr_reader :count

  def initialize(size)
    @ids = (0..size-1).to_a
    @count = size
  end

  def find(index)
    @ids[index] == index ? index : find(@ids[index])
  end

  def connected?(p, q)
    find(p) == find(q)
  end

  def union(p, q)
    return if connected?(p, q)

    @ids[find(p)] = find(q)
    @count -= 1
  end
end</code></pre><p>The <code>find</code> operation checks if <code>p</code> and <code>q</code> have the same root. The <code>union</code> operation changes the id of <code>p</code>&#x2019;s root to the id of <code>q</code>&#x2019;s root.</p><p>In that case, the <code>find</code> operation is more complicated, then the <code>union</code> one. Finding the root means passing all paths through the graph from a particular element to its root. A tree of components can be very deep in that case. In other words, we can <code>union</code> very tall trees, which require a lot of <code>find</code> operations. That is why this algorithm can be improved by checking the order of the joined objects.</p><h2 id="weighted-quick-union">Weighted Quick-Union</h2><p>It&#x2019;s an improved version of the <code>Quick-Union</code> algorithm.</p><p></p><pre><code class="language-ruby">class WeightedQuickUnion
  attr_reader :count

  def initialize(size)
    @ids = (0..size-1).to_a
    @size = Array.new(size, 1)
    @count = size
  end

  def find(index)
    @ids[index] == index ? index : find(@ids[index])
  end

  def connected?(p, q)
    find(p) == find(q)
  end

  def union(p, q)
    return if connected?(p, q)

    root_p, root_q = find(p), find(q)
    bigger?(root_p, root_q) ? join(root_q, root_p) : join(root_p, root_q)

    @count -= 1
  end

  private

  def bigger?(root_1, root_2)
    @size[root_1] &gt; @size[root_2]
  end

  def join(root_1, root_2)
    @ids[root_1] = root_2
    @size[root_2] += @size[root_1]
  end
end</code></pre><p><br>As you can see, we have an array (<code>@size</code>), which includes the sizes of all components. The <code>union</code> method checks the size of components and joins smaller ones with bigger ones. It means fewer <code>find</code> operations are required. Thus, the order is important. <br><br>However, we can make it even better! </p><h2 id="weighted-quick-union-with-path-compression">Weighted Quick-Union With Path Compression</h2><p>Every time when we go through the tree (after computing the root of <code>p</code>), we can make the id of each examined node point to that root. <br>For example, we have the tree:</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/01/wquwpc_before.png" class="kg-image" alt="Union-Find algorithms in Ruby" loading="lazy" width="350" height="341"></figure><p>After running the <code>find</code> operation, the tree will be changed to:</p><figure class="kg-card kg-image-card"><img src="https://d-halai.com/content/images/2023/01/wquwpc_after.png" class="kg-image" alt="Union-Find algorithms in Ruby" loading="lazy" width="545" height="270"></figure><p>All we need is just change a few lines of our <code>find</code> method.</p><p></p><pre><code class="language-ruby">def find(index)
  return index if @ids[index] == index

  @ids[index] = @ids[@ids[index]]
  find(@ids[index])
end</code></pre><p><br>Well, it is time to test it!</p><h2 id="tests">Tests</h2><p><br>I &#xA0;found some data sets. One of them includes <a href="http://algs4.cs.princeton.edu/15uf/tinyUF.txt">11</a> union operations, and another one <a href="http://algs4.cs.princeton.edu/15uf/mediumUF.txt">900</a>.</p><p></p><pre><code class="language-ruby">class Benchmarks
  def tiny
    test File.read(&apos;./tiny_UF.txt&apos;)
  end

  def medium
    test File.read(&apos;./medium_UF.txt&apos;)
  end

  private
  def test(str)
    data = str.split(&quot;\n&quot;)
    size, pairs = data.shift, data

    Benchmark.bm(20) do |bm|
      %w(QuickFind QuickUnion WeightedQuickUnion WeightedQuickUnionPC).each do |uf_class|
        bm.report(uf_class) do
          uf = Object.const_get(uf_class).new size.to_i
          union(uf, pairs)
        end
      end
    end
  end

  def union(uf, pairs)
    pairs.each do |pair|
      p, q = pair.split(&apos; &apos;)
      uf.union(p.to_i, q.to_i)
    end
  end
end</code></pre><pre><code># tiny data set
  user       system     total     real
QuickFind
  0.000000   0.000000   0.000000 (0.002838)
QuickUnion
  0.000000   0.000000   0.000000 (0.000091)
WeightedQuickUnion
  0.000000   0.000000   0.000000 (0.000078)
WeightedQuickUnionPC
  0.000000   0.000000   0.000000 (0.000056)

# medium data set
  user       system     total     real
QuickFind
  0.060000   0.010000   0.070000 (0.051383)
QuickUnion
  0.010000   0.000000   0.010000 (0.002796)
WeightedQuickUnion
  0.000000   0.000000   0.000000 (0.001658)
WeightedQuickUnionPC
  0.010000   0.000000   0.010000 (0.001589)</code></pre><p>As you can see, everything works as we expected and <code>Weighted Quick-Union With Path Compression</code> is the quickest algorithm.</p><p>Here&apos;s the <code>Union-Find</code> algorithms performance comparison:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://d-halai.com/content/images/2023/01/uf-performance.png" class="kg-image" alt="Union-Find algorithms in Ruby" loading="lazy" width="548" height="224"><figcaption><code>Union-Find</code> algorithms performance comparison</figcaption></figure><h2 id="conclusion">Conclusion</h2><p><code>Union-Find</code> algorithms are widely used. We can see them in different applications:</p><ul><li>Dynamic connectivity</li><li>Games (Go)</li><li>Percolation</li><li>Least common ancestor</li><li>Equivalence of finite state automata</li><li>etc..</li></ul><p><br>Thanks, Coursera for the amazing course and thank you for reading it &#x1F61B;.</p><p>PS. More information about UF algorithms can be found in <a href="https://algs4.cs.princeton.edu/15uf/">the course-related book&apos;s chapter</a>.</p><p><br></p>]]></content:encoded></item><item><title><![CDATA[Five programming problems every Software Engineer should be able to solve in less than 1 hour]]></title><description><![CDATA[<p><br>I have found an <a href="https://linepole.wordpress.com/2015/06/02/five-programming-problems-every-software-engineer-should-be-able-to-solve-in-less-than-1-hour/">interesting post</a> about interviewing recently.</p><p>Actually, I don&#x2019;t really like this categorical approach. But there are my solutions have been written in Ruby.</p><h2 id="problem-1">Problem 1</h2><p><br>Write three functions that compute the sum of the numbers in a given list using a for-loop, a while-loop,</p>]]></description><link>https://d-halai.com/five-programming-problems-every-software-engineer-should-be-able-to-solve-in-less-than-1-hour/</link><guid isPermaLink="false">63d7b884afbde009a96c06ce</guid><category><![CDATA[Interview]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Dmitry Halai]]></dc:creator><pubDate>Sat, 18 Jul 2015 22:00:00 GMT</pubDate><media:content url="https://d-halai.com/content/images/2023/01/ProgrammingIllustration.png" medium="image"/><content:encoded><![CDATA[<img src="https://d-halai.com/content/images/2023/01/ProgrammingIllustration.png" alt="Five programming problems every Software Engineer should be able to solve in less than 1 hour"><p><br>I have found an <a href="https://linepole.wordpress.com/2015/06/02/five-programming-problems-every-software-engineer-should-be-able-to-solve-in-less-than-1-hour/">interesting post</a> about interviewing recently.</p><p>Actually, I don&#x2019;t really like this categorical approach. But there are my solutions have been written in Ruby.</p><h2 id="problem-1">Problem 1</h2><p><br>Write three functions that compute the sum of the numbers in a given list using a for-loop, a while-loop, and recursion.</p><h3 id="solution">Solution</h3><pre><code class="language-Ruby">def sum_1(list)
  sum = 0
  for n in list do
    sum += n
  end
  sum
end

def sum_2(list)
  j, sum = 0, 0
  size = list.size
  while j &lt; size do
    sum += list[j]
    j += 1
  end
  sum
end

def sum_3(list, sum = 0)
  return sum if list.empty?
  sum += list.pop
  sum_3(list, sum)
end</code></pre><hr><h2 id="problem-2">Problem 2</h2><p><br>Write a function that combines two lists by alternatingly taking elements. For example: given the two lists [a, b, c] and [1, 2, 3], the function should return [a, 1, b, 2, c, 3].</p><h3 id="solution-1">Solution</h3><pre><code class="language-ruby">def zip(l1, l2)
  (l1.zip l2).flatten!
end</code></pre><hr><h2 id="problem-3">Problem 3</h2><p><br>Write a function that computes the list of the first 100 Fibonacci numbers. By definition, the first two numbers in the Fibonacci sequence are 0 and 1, and each subsequent number is the sum of the previous two. As an example, here are the first 10 Fibonnaci numbers: 0, 1, 1, 2, 3, 5, 8, 13, 21, and 34.</p><h3 id="solution-2">Solution</h3><pre><code class="language-ruby">def fib(n)
  (2..n).inject([0, 1]) { |a| a &lt;&lt; (a[a.size - 2] + a[a.size - 1]); a }
end</code></pre><hr><h2 id="problem-4">Problem 4</h2><p><br>Write a function that given a list of non negative integers, arranges them such that they form the largest possible number. For example, given [50, 2, 1, 9], the largest formed number is 95021.</p><h3 id="solution-3">Solution</h3><pre><code class="language-ruby">def max(list)
  list.permutation.to_a.map(&amp;:join).map(&amp;:to_i).sort.last
end</code></pre><hr><h2 id="problem-5">Problem 5</h2><p><br>Write a program that outputs all possibilities to put + or - or nothing between the numbers 1, 2, &#x2026;, 9 (in this order) such that the result is always 100. For example: 1 + 2 + 34 &#x2013; 5 + 67 &#x2013; 8 + 9 = 100.</p><h3 id="solution-4">Solution</h3><pre><code class="language-ruby">def solutions(n, result)
  numbers = (1..n).to_a
  permutations = [&quot;+&quot;, &quot;-&quot;, &quot;&quot;].repeated_permutation(n-1).to_a

  sequence = permutations.inject([]) do |a, o|
    a &lt;&lt; numbers.zip(o).flatten.compact!.join()
  end

  sequence.select { |v| eval(v) == result }
end

solutions(9, 100)

# or just one line solution:
[&quot;+&quot;, &quot;-&quot;, &quot;&quot;].repeated_permutation(8).to_a.map{|c| (1..9).to_a.zip(c).flatten.compact!.join() }.select { |v| eval(v) == 100 }</code></pre>]]></content:encoded></item></channel></rss>