<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Victor Hazbun</title>
    <description>The latest articles on DEV Community by Victor Hazbun (@victorhazbun).</description>
    <link>https://dev.to/victorhazbun</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F184433%2F3fb97df6-9c4d-43c7-8a18-1a0333867d45.jpg</url>
      <title>DEV Community: Victor Hazbun</title>
      <link>https://dev.to/victorhazbun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/victorhazbun"/>
    <language>en</language>
    <item>
      <title>Indexing Best Practices</title>
      <dc:creator>Victor Hazbun</dc:creator>
      <pubDate>Sat, 09 Mar 2024 04:32:31 +0000</pubDate>
      <link>https://dev.to/victorhazbun/indexing-best-practices-23ml</link>
      <guid>https://dev.to/victorhazbun/indexing-best-practices-23ml</guid>
      <description>&lt;h2&gt;
  
  
  Determine Our Needs
&lt;/h2&gt;

&lt;p&gt;Before creating any indexes, we need to have a clear understanding of the application's requirements. This involves a thorough analysis of the application’s workload. Identify the most common queries and understand how frequently they are used. In addition, determine the application's read-to-write ratio. Indexing improves read performance but can slow down write performance. If the application performs more writes than reads, too many indexes could adversely affect overall performance. Similarly, if the application is read-heavy, appropriate indexing can significantly enhance efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose the Right Columns for Indexing
&lt;/h2&gt;

&lt;p&gt;The decision of which columns to index should be based on their usage in queries. Indexes should ideally be created on columns that are frequently used in WHERE clauses, ORDER BY clauses, JOIN conditions, or used for sorting and grouping data.&lt;/p&gt;

&lt;p&gt;Columns with a high degree of uniqueness are ideal candidates for indexing. Indexes on such columns allow the database engine to quickly filter out a majority of the data. It leads to faster query results. Avoid indexing columns with many null values or those that have a lot of similar values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Weigh the Cost of Updates to Indexed Columns
&lt;/h2&gt;

&lt;p&gt;While indexes speed up data retrieval, they slow down data modification. This is because each time data is added, deleted, or modified, the corresponding indexes need to be updated as well. If a column is frequently updated, the overhead of updating the index might negate the performance benefits gained during data retrieval. If the index update time outweighs the time saved during data retrieval, it might not be worth it to maintain the index.&lt;/p&gt;

&lt;h2&gt;
  
  
   Limit the Number of Indexes
&lt;/h2&gt;

&lt;p&gt;While indexes are beneficial for query performance, having too many can negatively impact the performance of write operations and consume more disk space. Each time data is inserted or updated, every index on the table must be updated. The cost of maintaining the index might outweigh the performance benefits it provides. It is important to maintain a healthy balance and limit the number of indexes based on the nature of the workload. Utilize monitoring tools provided by the database system to identify if the update time on the indexes is increasing disproportionately.&lt;/p&gt;

&lt;h2&gt;
  
  
   Use Composite Indexes Effectively
&lt;/h2&gt;

&lt;p&gt;Composite indexes, which are made up of two or more columns, can be very beneficial for complex queries that involve multiple columns in the WHERE clause. The order of the columns in the composite index is critical. As a general rule of thumb, it should be based on the cardinality of the columns, with the column having the highest number of distinct values appearing first in the index. This order allows the database engine to efficiently filter out unneeded data.  For example, if we are creating a composite index on "CustomerName" and "Country" columns in a 'Orders' table, and there are fewer distinct countries than customer names, the index should be (Country, CustomerName).&lt;/p&gt;

&lt;p&gt;It is important to note that this guideline is a general rule of thumb, and it is not always correct. Verify with the optimizer that it indeed uses the composite index as intended.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leverage Covering Indexes
&lt;/h2&gt;

&lt;p&gt;A covering index includes all the columns that a query needs, both in the WHERE clause and the SELECT list. This means that the database engine can locate all the required data within the index itself, without having to perform additional lookups in the main table. This results in a significant performance boost because accessing an index is typically faster than accessing the table data. Consider using covering indexes for frequently used, read-intensive queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regularly Monitor and Optimize the Indexes
&lt;/h2&gt;

&lt;p&gt;Indexes are not a set-it-and-forget-it part of the database. As the data grows and changes, the indexes need to be monitored and optimized. Over time, as data is added, updated, and deleted, indexes can become fragmented, which can negatively impact their performance. Regularly performing index maintenance tasks, such as rebuilding or reorganizing fragmented indexes, can help ensure that they continue to provide optimal performance. Database tools such as SQL Server's Database Engine Tuning Advisor or MySQL's OPTIMIZE TABLE command are some examples of tools to use. Monitoring logs like MySQL’s slow query log is also important in detecting issues early.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drop Unused Indexes
&lt;/h2&gt;

&lt;p&gt;Not all indexes end up being used as intended. Some may be rarely used, or not at all. Such indexes impose unnecessary overhead on write operations and waste storage space. Use the database's built-in tools to monitor index usage, and do not hesitate to drop indexes that are no longer serving their purpose. In PostgreSQL, for instance, we can use the pg_stat_user_indexes view to track index usage.&lt;/p&gt;

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

&lt;p&gt;Database indexing is a critical part in optimizing database efficiency. It's a key component in the balancing act between speed of data retrieval and the performance of write operations.&lt;/p&gt;

&lt;p&gt;However, indexing is not a one-size-fits-all solution. Careful design, regular monitoring and maintenance are vital components in maximizing the benefits of the indexing strategies. Recognizing the indexing techniques specific to different databases can significantly improve the data operations.&lt;/p&gt;

&lt;p&gt;A well-implemented indexing strategy is fundamental to a high-performing database. Mastering the art of database indexing is an indispensable skill for anyone building large-scale data-driven applications.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>mysql</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Best practices for DB modifications MySQL</title>
      <dc:creator>Victor Hazbun</dc:creator>
      <pubDate>Sat, 09 Mar 2024 04:27:36 +0000</pubDate>
      <link>https://dev.to/victorhazbun/best-practices-for-db-modifications-mysql-22gl</link>
      <guid>https://dev.to/victorhazbun/best-practices-for-db-modifications-mysql-22gl</guid>
      <description>&lt;p&gt;Databases are the lifeblood of our applications, storing the crucial information that fuels their operation. But just like sculpting clay, modifying database tables requires careful precision and meticulous planning. A single misguided change can ripple through data integrity, functionality, and user experience.&lt;/p&gt;

&lt;p&gt;Fear not, intrepid data architects and developers! This document serves as your guide to navigating the delicate dance of database modifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  SQL transactions best practices
&lt;/h2&gt;

&lt;p&gt;Transactions are the bulwark of relational database consistency. All or nothing, that’s the transaction motto. Transactions ensure that every command of a set is executed. If anything fails along the way, all of the commands are rolled back as if they never happened.&lt;/p&gt;

&lt;p&gt;MySQL transactions follow ACID compliance, which stands for:    &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Atomic&lt;/strong&gt; (either all operations succeed or none do)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consistent&lt;/strong&gt; (the data will always be in a good state and never in an inconsistent state)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Isolated&lt;/strong&gt; (transactions don’t interfere with one another)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Durable&lt;/strong&gt; (a committed transaction is safe, even after a server crash)&lt;/p&gt;

&lt;h3&gt;
  
  
  Transactions use cases
&lt;/h3&gt;

&lt;p&gt;For the following examples, let’s pretend we have a &lt;code&gt;wallets&lt;/code&gt; table with columns &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;balance&lt;/code&gt; , &lt;code&gt;updated_at&lt;/code&gt; and &lt;code&gt;owner_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0rf20mp5pv372mk7dq92.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0rf20mp5pv372mk7dq92.png" alt="Image description" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best practice: Use transactions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can wrap any transaction within a START TRANSACTION block. To verify atomicity, we'll kill the transaction with the ROLLBACK command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;START&lt;/span&gt; &lt;span class="n"&gt;TRANSACTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;wallets&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;owner_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, no account will be updated thanks to the ROLLBACK command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb3kpqk1r5z2iaw7p8by7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb3kpqk1r5z2iaw7p8by7.png" alt="Image description" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, the output will tell you how many rows the query would affect if you decide not to use ROLLBACK.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best practice: Use savepoint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's good practice to use the &lt;code&gt;SAVEPOINT&lt;/code&gt; statement within a transaction to set save points. This makes it possible for you to rollback to a specific point in the transaction, rather than rolling back the entire transaction.&lt;/p&gt;

&lt;p&gt;Here is an example of how you might use the &lt;code&gt;SAVEPOINT&lt;/code&gt; statement within the previous example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;START&lt;/span&gt; &lt;span class="n"&gt;TRANSACTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;wallets&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;owner_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;SAVEPOINT&lt;/span&gt; &lt;span class="n"&gt;save_point_update_owner_1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- Create a savepoint&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;wallets&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;owner_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;wallets&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
  &lt;span class="k"&gt;ROLLBACK&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;save_point_update_owner_1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- Rollback to the savepoint&lt;/span&gt;
&lt;span class="k"&gt;ELSE&lt;/span&gt;
  &lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- Commit the entire transaction&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s see this example step by step:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;START TRANSACTION;&lt;/code&gt;: Begins a transaction, ensuring changes are grouped together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First Update:&lt;/strong&gt; Updates the balance for &lt;code&gt;owner_id = 1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SAVEPOINT save_point_update_owner_1;&lt;/code&gt;: Creates a savepoint named &lt;code&gt;save_point_update_owner_1&lt;/code&gt;, marking a point to potentially revert to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second Update:&lt;/strong&gt; Updates the balance for &lt;code&gt;owner_id = 2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conditional Check:&lt;/strong&gt; Checks if any balances have become negative.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ROLLBACK TO save_point_update_owner_1;&lt;/code&gt;: If negative balances exist, rolls back to the savepoint, undoing only the second update.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;COMMIT;&lt;/code&gt;: If no negative balances exist, commits the entire transaction, including both updates.&lt;/p&gt;

&lt;p&gt;Key points:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flexibility:&lt;/strong&gt; Savepoints allow selective rollbacks within a transaction, providing more control over changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nesting:&lt;/strong&gt; You can create multiple savepoints within a transaction for finer-grained control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rollback Scope:&lt;/strong&gt; Rollback to a savepoint only undoes changes made after that savepoint, not the entire transaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transaction Continuation:&lt;/strong&gt; After rolling back to a savepoint, you can continue with the transaction and make further modifications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Release:&lt;/strong&gt; Savepoints are automatically released when a transaction is committed or rolled back entirely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best practice: Set timestamps for updated records
&lt;/h3&gt;

&lt;p&gt;In the realm of data management, tracking changes to records is crucial for maintaining data integrity, version control, and auditing purposes. By setting timestamps for updated records, you gain valuable insights into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;When data was modified:&lt;/strong&gt; Identify when specific changes occurred, enabling you to track data evolution and pinpoint potential errors or inconsistencies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Frequency of updates:&lt;/strong&gt; Analyze how often records are modified, aiding in understanding data usage patterns and identifying potential areas for optimization.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an example of how you might want to set &lt;code&gt;updated_at&lt;/code&gt; for an updated wallet:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F193e3me0myicmxtt4p1u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F193e3me0myicmxtt4p1u.png" alt="Image description" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;NOW()&lt;/code&gt; function returns the current date and time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The date and time is returned as "YYYY-MM-DD HH-MM-SS" (string) or as YYYYMMDDHHMMSS.uuuuuu (numeric).&lt;/p&gt;

&lt;h3&gt;
  
  
  Deleting records
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Best practice: Soft delete
&lt;/h4&gt;

&lt;p&gt;Soft delete in MySQL refers to the technique of marking records as deleted without physically removing them from the database. This allows for potential recovery or access to historical data while still maintaining data integrity and consistency.&lt;/p&gt;

&lt;p&gt;Here's how it typically works:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add a Deleted Flag:&lt;/strong&gt; A new column, often named is_deleted or deleted_at, is added to the table to store a deletion indicator.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update the Flag:&lt;/strong&gt; When a record is "deleted," instead of using the DELETE statement, you update the flag column to a value like 1 or a timestamp indicating deletion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query Adjustments:&lt;/strong&gt; All subsequent queries that retrieve data must filter out the "deleted" records using a WHERE clause that checks the flag column (e.g., WHERE is_deleted = 0).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits of Soft Delete in MySQL:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recoverability:&lt;/strong&gt; Accidentally deleted records can be restored by simply resetting the flag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auditing:&lt;/strong&gt; You can track the history of deleted records for compliance or analysis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Preservation:&lt;/strong&gt; Maintains historical data for potential future use, even if it's not actively displayed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referential Integrity:&lt;/strong&gt; Soft deletes help preserve referential integrity in related tables by avoiding broken foreign key relationships.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please be mindful of legislation, if unsure, consult the company legal department. In some cases and in some localities the law requires us to actually delete the data, and in those cases the delete flag, while technically the safest solution, will not satisfy the law, the data needs to actually be physically destroyed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Implementation Considerations:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consistency:&lt;/strong&gt; Ensure all queries account for the flag column to avoid displaying "deleted" records unintentionally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance:&lt;/strong&gt; Regularly purging truly unnecessary "deleted" records can improve performance and reduce storage overhead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Indexing:&lt;/strong&gt; Create appropriate indexes on the flag column to optimize query performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application Logic:&lt;/strong&gt; Adapt application code to handle soft deletes consistently, including both data retrieval and deletion operations.&lt;/p&gt;

&lt;h4&gt;
  
  
   Hard delete considerations
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Confirm Before Deletion:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;SELECT&lt;/code&gt; queries to preview the data to be deleted and ensure accuracy.&lt;/li&gt;
&lt;li&gt;Implement user prompts or warnings before execution to prevent accidental deletions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Transactional Control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enclose &lt;code&gt;DELETE&lt;/code&gt; statements within &lt;code&gt;START&lt;/code&gt; and &lt;code&gt;COMMIT&lt;/code&gt; transactions for atomicity and rollback if needed.&lt;/li&gt;
&lt;li&gt;Use savepoints to create checkpoints for partial rollbacks if necessary.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Filtering and Targeting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use precise &lt;code&gt;WHERE&lt;/code&gt; clauses to target specific records for deletion.Use savepoints to create checkpoints for partial rollbacks if necessary.&lt;/li&gt;
&lt;li&gt;Avoid overly broad &lt;code&gt;DELETE&lt;/code&gt; statements without conditions to prevent unintended data loss.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Optimize for Performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Batch Deletions: Group multiple &lt;code&gt;DELETE&lt;/code&gt; statements into a single transaction for efficiency, especially for large datasets.&lt;/li&gt;
&lt;li&gt;Indexing: Ensure appropriate indexes exist on columns used in WHERE clauses to speed up deletion operations.&lt;/li&gt;
&lt;li&gt;Partitioning: Consider partitioning tables by date or other criteria for targeted deletions and improved performance.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Logging and Auditing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable MySQL's general query log or binary log to track &lt;code&gt;DELETE&lt;/code&gt; statements for auditing purposes.&lt;/li&gt;
&lt;li&gt;Create custom triggers to log additional details about deletions, such as timestamps, user information, and affected data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Security and Permissions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grant &lt;code&gt;DELETE&lt;/code&gt; privileges only to authorized users or roles to prevent unauthorized data removal.&lt;/li&gt;
&lt;li&gt;Consider using stored procedures with permission checks for controlled deletion access.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Backups and Recovery:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintain regular database backups to recover from accidental deletions or system failures.&lt;/li&gt;
&lt;li&gt;Practice restoring backups to ensure they function correctly in case of need.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pro tip: Export the data you plan to delete using MySQLWorkbench.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F114d30na6iho2arysmhi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F114d30na6iho2arysmhi.png" alt="Image description" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IMPORTANT:&lt;/strong&gt; While this might help to recover the current table it’s not silver bullet, because cascade updates/deletes can occur during deletion of the current table. Hard delete could be difficult to recover, so don’t take this lightly. See &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html"&gt;“Referential Actions” section from MySQL docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ruby on Rails DB best practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Best practice: Altering schema with Rails migrations
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://guides.rubyonrails.org/active_record_migrations.html"&gt;Migrations&lt;/a&gt; are a feature of Active Record that allows you to evolve your database schema over time. Rather than write schema modifications in pure SQL, migrations allow you to use a Ruby DSL to describe changes to your tables.&lt;/p&gt;

&lt;p&gt;Rules of thumb&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NEVER alter existing migrations&lt;/strong&gt;: Instead, you should write a new migration that performs the changes you require. Editing a freshly generated migration that has not yet been committed to source control (or, more generally, which has not been propagated beyond your development machine) is relatively harmless. See &lt;a href="https://guides.rubyonrails.org/active_record_migrations.html#changing-existing-migrations"&gt;https://guides.rubyonrails.org/active_record_migrations.html#changing-existing-migrations&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep It Reversible:&lt;/strong&gt; Ensure that your migrations are reversible. This means defining both up and down methods. This is crucial for rolling back changes if needed. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;One Change per Migration:&lt;/strong&gt; Each migration should represent a single logical change to the database schema. This makes it easier to manage and understand the evolution of your database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Change Method Wisely:&lt;/strong&gt; The change method is powerful, but be cautious when using it. Ensure that the changes made are reversible and won't cause issues during rollback.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test Migrations:&lt;/strong&gt; Test your migrations on a staging environment before applying them to production. This helps catch potential issues early on.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Best practice: Altering data with rake tasks
&lt;/h3&gt;

&lt;p&gt;Rake tasks offer a powerful way to automate data manipulation in Rails applications. But when wielding this tool for altering data, it's essential to prioritize both effectiveness and cleanliness. Here are some best practices to make your data-altering Rake tasks shine:&lt;/p&gt;

&lt;p&gt;Custom rake tasks have a &lt;code&gt;.rake&lt;/code&gt; extension and are placed in &lt;code&gt;Rails.root/lib/tasks&lt;/code&gt;. You can create these custom rake tasks with the &lt;code&gt;bin/rails generate task&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;If you need to interact with your application models, perform database queries, and so on, your task should depend on the environment task, which will load your application code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;task_that_requires_app_code: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:environment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create!&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like migrations, rake tasks have some shared best practices like “Keep It Reversible“.&lt;/p&gt;

&lt;p&gt;Let’s see an example of the “Keep it Reversible“ rule.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib/tasks/user_name_updates.rake&lt;/span&gt;

&lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:users&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Update user names with a specified prefix and store original names in backup.csv"&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:update_names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:prefix&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:prefix&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"Please provide a prefix"&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt;

    &lt;span class="c1"&gt;# Store original names in CSV for rollback&lt;/span&gt;
    &lt;span class="no"&gt;CSV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"backup.csv"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"w"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;csv&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"original_name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;csv&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"User names updated successfully! Original names saved in backup.csv"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Revert user name updates using data from backup.csv"&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;revert_names: :environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exist?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"backup.csv"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;original_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;CSV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"backup.csv"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;headers: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;original_names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
          &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"original_name"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"backup.csv"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Remove CSV after successful revert&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"User names reverted successfully! Backup file removed."&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Error: Backup file (backup.csv) not found."&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To execute the tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update names: &lt;code&gt;rails users:update_names[prefix_to_add]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Revert names: &lt;code&gt;rails users:revert_names&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Best practice: Rails sandbox mode
&lt;/h3&gt;

&lt;p&gt;If you wish to test out some code without changing any data, you can do that by invoking rails console &lt;code&gt;--sandbox&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrcy5bman2q2vtxihy7v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrcy5bman2q2vtxihy7v.png" alt="Image description" width="633" height="119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IMPORTANT:&lt;/strong&gt; In sandbox mode, database rows are fully locked, which in real time prevents your live production services from modifying them. It’s much more recommended to use sandbox mode in non-production environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rails DB transactions
&lt;/h3&gt;

&lt;p&gt;This &lt;a href="https://www.honeybadger.io/blog/database-transactions-rails-activerecord/"&gt;article&lt;/a&gt; from &lt;a href="https://www.honeybadger.io/"&gt;HoneyBadger&lt;/a&gt; explains most relevant topics about Rails DB transactions.&lt;/p&gt;




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

&lt;p&gt;To complement this article and keep your data safe, here are some key takeaways.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Backups are Indispensable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protect against data loss from hardware failures, human errors, or malicious attacks.&lt;/li&gt;
&lt;li&gt;Enable recovery to a known good state.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Backups Demand Verification:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regularly test restore processes to ensure backups are valid and usable.&lt;/li&gt;
&lt;li&gt;Prevent surprises when recovery is critical.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Testing in Non-Production Environments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mitigates risks of unanticipated issues in production.&lt;/li&gt;
&lt;li&gt;Catches errors and unintended consequences early.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Code Reviews for Destructive Queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prevent accidental data loss or corruption.&lt;/li&gt;
&lt;li&gt;Ensure code aligns with intended actions.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Referential Actions Enforce Integrity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintain consistency and prevent orphaned records.&lt;/li&gt;
&lt;li&gt;Define how database operations cascade across related tables.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Recovery Strategies Provide Options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full restore for complete database recovery.&lt;/li&gt;
&lt;li&gt;Point-in-time for restoring to a specific time.&lt;/li&gt;
&lt;li&gt;Transaction log for restoring individual transactions.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Change Data Capture (CDC) Enhances Data Protection and Insights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tracks changes in real-time, enabling:&lt;/li&gt;
&lt;li&gt;Data replication for real-time analytics or disaster recovery.&lt;/li&gt;
&lt;li&gt;Audit trails for compliance and security.&lt;/li&gt;
&lt;li&gt;Efficient incremental updates.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By embracing these practices, you'll establish a resilient foundation for safeguarding your valuable data and maintaining business continuity in the face of unexpected challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.freecodecamp.org/news/how-to-use-mysql-transactions/"&gt;https://www.freecodecamp.org/news/how-to-use-mysql-transactions/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/commit.html"&gt;https://dev.mysql.com/doc/refman/8.0/en/commit.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/savepoint.html"&gt;https://dev.mysql.com/doc/refman/8.0/en/savepoint.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_now"&gt;https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_now&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html"&gt;https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/azure-sql/database/change-data-capture-overview?view=azuresql"&gt;https://learn.microsoft.com/en-us/azure/azure-sql/database/change-data-capture-overview?view=azuresql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jhawthorn/discard"&gt;https://github.com/jhawthorn/discard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://guides.rubyonrails.org/command_line.html#bin-rails-console"&gt;https://guides.rubyonrails.org/command_line.html#bin-rails-console&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html"&gt;https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://edgeguides.rubyonrails.org/active_record_migrations.html"&gt;https://edgeguides.rubyonrails.org/active_record_migrations.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mysql</category>
      <category>rails</category>
    </item>
    <item>
      <title>SQL antipatterns: Diplomatic Immunity</title>
      <dc:creator>Victor Hazbun</dc:creator>
      <pubDate>Tue, 13 Feb 2024 04:25:43 +0000</pubDate>
      <link>https://dev.to/victorhazbun/sql-antipatterns-diplomatic-immunity-5308</link>
      <guid>https://dev.to/victorhazbun/sql-antipatterns-diplomatic-immunity-5308</guid>
      <description>&lt;p&gt;You might find projects with nearly no written documentation or tests, and never used version control systems for their code or even comments. Code could reside in a single directory, a mix of live systems code and development code and also un-used code.&lt;/p&gt;

&lt;p&gt;These high technical debt is the consequence of using shortcuts instead of best practices. Technical debt causes risk and extra work in a project until you pay it off by refactoring, testing and documenting. It's basically like lending your soul to the devil.&lt;/p&gt;

&lt;p&gt;You can only gain trust in your systems once you pay this debt, which allows you to make changes easily and safely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Objective: Employ Best Practices
&lt;/h3&gt;

&lt;p&gt;Professional programmers strive to use good software engineering habits in their projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Git or Subversion.&lt;/li&gt;
&lt;li&gt;Write automated unit tests and/or functional tests.&lt;/li&gt;
&lt;li&gt;Writing code with documentation, specifications, comments, and consistent code style, implementation strategies, operation, and maintenance of an application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't think of best practices as slowing you down - They're an investment in efficiency. Spending time upfront on version control, testing, and documentation saves countless hours later fixing bugs, debugging cryptic code, and deciphering undocumented logic. Trust us, seasoned developers know that cutting corners on these practices leads to long-term pain, not swift gains.&lt;/p&gt;




&lt;h3&gt;
  
  
  Antipattern: Make SQL a Second-Class Citizen
&lt;/h3&gt;

&lt;p&gt;Developers often neglect best practices for database code ("Diplomatic Immunity"). Reasons include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Separate roles: DBAs seen as separate from development teams, not subject to same rules.&lt;/li&gt;
&lt;li&gt;Different language: SQL seen as separate from app languages, like a guest with different rules.&lt;/li&gt;
&lt;li&gt;Less advanced tools: Database development tools lack the ease of use and support for best practices compared to app code editors.&lt;/li&gt;
&lt;li&gt;Centralized knowledge: DBAs hold exclusive knowledge and control, seen as a replacement for best practices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; Poor quality database code can undermine the entire application and lead to scrapped projects. Treat database code with the same rigor as application code to ensure a solid foundation.&lt;/p&gt;




&lt;h3&gt;
  
  
  Cutting corners in software development: red flags
&lt;/h3&gt;

&lt;p&gt;Even though you might not actively implement something, neglecting certain practices shows carelessness. Here are some warning signs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Lightweight" processes: Mentioning a "lightweight" version of a process often means skipping crucial steps.&lt;/li&gt;
&lt;li&gt;Excluded training: Leaving team members out of training for essential tools ensures they won't use them.&lt;/li&gt;
&lt;li&gt;Poor data tracking: Lack of documentation on sensitive data forces treating all data as sensitive, increasing costs and complexity.&lt;/li&gt;
&lt;li&gt;Manual schema comparison: Not having a proper process for managing schema changes leads to inconsistencies and difficulty reconciling them.&lt;/li&gt;
&lt;li&gt;"Self-documenting" code: This excuse rarely holds true; good documentation and comments are still essential.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Beyond Testing: Embracing Quality Assurance in Database Development
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Forget "testing equals quality."&lt;/strong&gt; True quality assurance (QA) encompasses more, covering the entire software life cycle. It involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clear Requirements:&lt;/strong&gt; Define what the system needs to do in written, detailed specifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution Design and Development:&lt;/strong&gt; Build a system that fulfills the established requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation and Testing:&lt;/strong&gt; Ensure the finished system actually meets the initial requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While the order may vary depending on the methodology, all three are crucial for proper QA.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For database development, achieving solid QA boils down to three key practices:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive Documentation:&lt;/strong&gt; Document everything clearly, from schema details to data definitions and processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source Code Version Control:&lt;/strong&gt; Use tools like Git to track changes, maintain history, and facilitate collaboration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rigorous Testing:&lt;/strong&gt; Implement various testing approaches (unit, functional, performance) to catch issues early and ensure data integrity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By embracing these practices, you move beyond mere testing and ensure a truly high-quality foundation for your software.&lt;/p&gt;

&lt;h3&gt;
  
  
  Importance of Database Documentation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Ditch the myth of self-documenting code!&lt;/strong&gt; Even skilled programmers need clear documentation to understand databases effectively. Here's why and how to document effectively:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Document?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code can't explain everything:&lt;/strong&gt; It doesn't reveal missing features, unsolved problems, or the intent behind decisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency:&lt;/strong&gt; Proper documentation saves time and effort for everyone involved, reducing the need for laborious code analysis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge transfer:&lt;/strong&gt; Documentation facilitates smooth transitions between developers, ensuring everyone is on the same page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What to Document:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entity-relationship diagram (ERD):&lt;/strong&gt; Visually represent tables and relationships. Consider using diagramming tools for easier creation and maintenance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tables, columns, and views:&lt;/strong&gt; Describe each element clearly, including purpose, usage, expected data, and constraints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relationships:&lt;/strong&gt; Explain the meaning and intent behind referential integrity constraints and implicit relationships.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Triggers and stored procedures:&lt;/strong&gt; Document their purpose, business rules implemented, input/output parameters, and security considerations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQL Security:&lt;/strong&gt; Detail database users, access privileges, roles, and security measures like SSL and password protection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database infrastructure:&lt;/strong&gt; Provide relevant information for IT staff and developers, including RDBMS details, server information, network configuration, and backup policies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object-relational mapping (ORM):&lt;/strong&gt; Document any ORM-based code used for database handling, including implemented business rules and functionalities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Remember:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Even experienced developers prioritize database documentation.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clear and concise documentation saves time, effort, and potential headaches in the long run.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these guidelines, you can ensure your database is well-understood and maintainable, promoting efficient development and collaboration.&lt;/p&gt;




&lt;h3&gt;
  
  
  Version Control for Database Development
&lt;/h3&gt;

&lt;p&gt;Imagine losing your database server! How would you rebuild it? Track complex upgrades? Undo a change?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Just like your application code, manage your database code with version control.&lt;/strong&gt; This offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Disaster recovery:&lt;/strong&gt; Rebuild the database from version control if needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Change tracking:&lt;/strong&gt; Understand modifications and easily revert to previous versions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaboration:&lt;/strong&gt; Share and collaborate on database changes securely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What to version control:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data definition scripts:&lt;/strong&gt; All commands (CREATE TABLE, etc.) defining database objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Triggers and stored procedures:&lt;/strong&gt; Routines stored in the database, essential for your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bootstrap data:&lt;/strong&gt; Initial data for lookup tables, useful for recreating the database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ER diagrams and documentation:&lt;/strong&gt; Files describing database design, requirements, and integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DBA scripts:&lt;/strong&gt; Scripts for tasks like import/export, backups, and testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key points:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Associate database code with its corresponding application code for easy integration.&lt;/li&gt;
&lt;li&gt;Use the same repository for both application and database code for convenience.&lt;/li&gt;
&lt;li&gt;Leverage version control benefits to ensure a robust and maintainable database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By adopting these practices, you can safeguard your database against unforeseen events and streamline development processes.&lt;/p&gt;




&lt;h3&gt;
  
  
  Managing Database Schema Changes: The Power of Migrations
&lt;/h3&gt;

&lt;p&gt;While you diligently version control your code, does your database schema enjoy the same care? Ruby on Rails' migrations offer a solution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are migrations?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Migrations automate synchronizing your database schema with the latest code, just like version control does for code itself. Essentially, they are scripted changes applied to your database step-by-step, ensuring smooth upgrades.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do migrations work?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You write a script based on Rails' tools, specifying the desired schema change (upgrade).&lt;/li&gt;
&lt;li&gt;Crucially, you also include a "downgrade" function that undoes the changes in case you need to revert.&lt;/li&gt;
&lt;li&gt;With migrations in place, upgrading your database becomes as simple as running specific scripts corresponding to code revisions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefits of migrations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Safe and controlled schema changes:&lt;/strong&gt; No more risky manual interventions, reducing errors and data integrity issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollback capability:&lt;/strong&gt; Easily undo changes if needed, providing a safety net for experimentation and fixes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version control integration:&lt;/strong&gt; Seamlessly integrates with your existing version control system, ensuring complete project tracking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By adopting migrations, you can manage your database schema with the same precision and control as your application code, leading to a more robust and maintainable development environment.&lt;/p&gt;

&lt;p&gt;You're absolutely right! Automating migrations during deployment is crucial for several reasons, and I appreciate you pointing it out. Here's an updated section incorporating your suggestion:&lt;/p&gt;

&lt;h3&gt;
  
  
  Running Migrations Seamlessly: Automation is Key
&lt;/h3&gt;

&lt;p&gt;While understanding the manual process of running migrations is valuable, &lt;strong&gt;true power lies in automation&lt;/strong&gt;. Integrating migrations into your deployment pipeline ensures they always get executed, saving time, preventing errors, and maintaining database consistency across environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why automate migrations?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency:&lt;/strong&gt; No more manual intervention. Deployments become streamlined, allowing you to focus on other tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; Migrations run the same way every time, regardless of who deploys, minimizing human error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability:&lt;/strong&gt; You're less likely to forget or skip migrations, reducing the risk of inconsistencies and potential issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollback potential:&lt;/strong&gt; Most automation tools allow easy rollback if something goes wrong during deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How to automate migrations?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The specific method depends on your chosen framework and deployment tools. However, many frameworks offer built-in support or readily available libraries for automating migrations as part of the deployment process.&lt;/p&gt;

&lt;p&gt;Here are some common approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD pipelines:&lt;/strong&gt; Integrate migration execution into your continuous integration and continuous delivery (CI/CD) pipeline. This ensures migrations run automatically after code changes are built and tested.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment scripts:&lt;/strong&gt; Scripting tools like bash, PowerShell, or Ansible can be used to execute migration commands as part of your deployment script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Containerization tools:&lt;/strong&gt; Platforms like Docker offer mechanisms to run migrations within containers before the application starts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Remember:&lt;/strong&gt; Always test your automated migration process thoroughly in a staging environment before deploying to production.&lt;/p&gt;

&lt;p&gt;By automating migrations, you ensure &lt;strong&gt;database health and application stability&lt;/strong&gt; become an inherent part of your deployment process, not a manual afterthought. This leads to smoother deployments, fewer headaches, and a more robust development environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChangeProductsPrice&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;7.2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;up&lt;/span&gt;
    &lt;span class="n"&gt;change_table&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;change&lt;/span&gt; &lt;span class="ss"&gt;:price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;down&lt;/span&gt;
    &lt;span class="n"&gt;change_table&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;change&lt;/span&gt; &lt;span class="ss"&gt;:price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:integer&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember that version control for code isn't enough! Ensure your database schema evolves safely and seamlessly using migrations.&lt;/p&gt;

&lt;p&gt;Key points:&lt;/p&gt;

&lt;p&gt;Migrations are scripts that automate controlled schema changes, like version control for your database.&lt;br&gt;
Each migration upgrades (or downgrades) the schema one step, with clear rollback functionality.&lt;br&gt;
Rails includes a tool to run migrations and track applied revisions.&lt;br&gt;
Similar tools exist for other frameworks like Java, PHP, Python, and .NET.&lt;br&gt;
Benefits:&lt;/p&gt;

&lt;p&gt;Safe and controlled: Reduces errors and data integrity issues.&lt;br&gt;
Rollback capability: Allows easy undo of changes.&lt;br&gt;
Version control integration: Ensures seamless project tracking.&lt;/p&gt;


&lt;h3&gt;
  
  
  Testing Your Database: Beyond Application Code
&lt;/h3&gt;

&lt;p&gt;While you excel at testing your application code, remember: database functionality needs validation too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extend the power of testing to your database:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leverage isolation testing principles, validating database structure and behavior independently from your application code.&lt;/li&gt;
&lt;li&gt;Employ database-specific tools and frameworks for comprehensive testing.&lt;/li&gt;
&lt;li&gt;Cover various aspects: unit tests for individual procedures, integration tests for interactions, and system tests for overall functionalities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example (Python Unit Test Script):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;unnitest&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mysql.connector&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unittest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cxn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;scott&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cxn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_table_bugs_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt;SELECT trie FROM Bugs Limit 1&lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_table_bugs_column_bugid_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt;SELECT bug_id FROM Bugs LIMIT 1&lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# the issue_id column was removed, so this should fail
&lt;/span&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_table_bugs_column_issueid_not_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertRaises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProgrammingError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt;SELECT issue_id FROM Bugs LIMIT 1&lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;
      &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefits of Database Testing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Early detection of issues:&lt;/strong&gt; Catch errors before they impact your application, saving time and effort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved data integrity:&lt;/strong&gt; Ensure data remains consistent and reliable under various conditions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confidence in functionality:&lt;/strong&gt; Validate that your database performs as intended, boosting overall system reliability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Validate your database functionality with these key tests:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tables, Views, Columns:&lt;/strong&gt; Confirm existence and absence based on project revisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constraints:&lt;/strong&gt; Use negative testing to verify enforcement of constraints (not-null, unique, foreign keys).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Triggers:&lt;/strong&gt; Test trigger execution, cascading effects, value transformations, and logging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stored Procedures:&lt;/strong&gt; Test input validation, logic execution paths, result sets, and side effects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bootstrap Data:&lt;/strong&gt; Ensure expected initial data is present in lookup tables and other relevant areas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queries:&lt;/strong&gt; Validate syntax and results (column names, data types) of application code-related queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ORM Classes:&lt;/strong&gt; Test logic within your ORM-based code, including input validation and expected actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Remember:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Testing environment:&lt;/strong&gt; Double-check you're testing on the correct database instance (staging, production, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema synchronization:&lt;/strong&gt; If tests fail due to schema changes, use migration scripts to align the database with your application's expectations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By implementing these tests, you can catch database issues early, improve data integrity, and boost overall system reliability. Invest in a well-tested database foundation for a robust and maintainable application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion: Building a Solid Foundation - Embracing Quality Database Practices
&lt;/h2&gt;

&lt;p&gt;Developing high-quality software goes beyond just application code. The often-neglected database plays a crucial role, and neglecting its quality can lead to instability, security vulnerabilities, and wasted effort. This text has explored key practices to ensure your database is a strong and reliable foundation for your applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shifting the Mindset: Beyond "Self-Documenting" Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We dispelled the myth of self-documenting code, emphasizing the importance of clear and comprehensive documentation for databases. From entity-relationship diagrams and table descriptions to procedure explanations and security measures, documentation serves as a roadmap for developers and ensures everyone is on the same page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Version Control: Your Database Deserves It Too&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Just like your application code, your database schema and related elements benefit greatly from version control. Tools like migrations automate schema changes, providing safe and controlled evolution with rollback capabilities. This promotes collaboration, simplifies disaster recovery, and integrates seamlessly with existing version control systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing: Don't Leave the Database Out&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Testing isn't just for application code. Extend your testing practices to your database, employing isolation principles and dedicated frameworks. Validate tables, constraints, triggers, procedures, and queries to catch issues early, maintain data integrity, and boost overall system confidence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remember the Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By embracing these quality assurance practices for your database, you reap numerous benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reduced errors and risks:&lt;/strong&gt; Early detection and prevention of issues save time, effort, and potential security vulnerabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved data integrity:&lt;/strong&gt; Consistent and reliable data is essential for accurate results and informed decision-making.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced collaboration and maintainability:&lt;/strong&gt; Clear documentation and version control facilitate collaboration and make future maintenance easier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confidence and peace of mind:&lt;/strong&gt; Knowing your database is well-tested and documented provides peace of mind and fosters a more robust development environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Investing in a solid database foundation through these practices not only improves the quality of your software but also empowers you to build more reliable, maintainable, and secure applications.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>antipatterns</category>
      <category>bestpractices</category>
    </item>
    <item>
      <title>Elasticsearch presentation</title>
      <dc:creator>Victor Hazbun</dc:creator>
      <pubDate>Sat, 27 Jan 2024 23:42:03 +0000</pubDate>
      <link>https://dev.to/victorhazbun/elasticsearch-presentation-500l</link>
      <guid>https://dev.to/victorhazbun/elasticsearch-presentation-500l</guid>
      <description>&lt;h2&gt;
  
  
  Search supported by a database
&lt;/h2&gt;

&lt;p&gt;Old-fashioned search was mostly based on traditional relational databases. Older search engines were based on layered architectures implemented in multi-tiered applications, as shown in figure 1.1.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fea6spb30y7vcjdpd2ve1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fea6spb30y7vcjdpd2ve1.png" alt="Figure 1.1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;Figure 1.1&lt;/center&gt;

&lt;h3&gt;
  
  
  Figure 1.1 Search based on a traditional database
&lt;/h3&gt;

&lt;p&gt;Queries written in SQL using clauses like where and like provided the foundation for search. These solutions are not necessarily performant and efficient for searching full-text data to provide modern search functionality.&lt;br&gt;
Having said that, some modern databases (Oracle and MySQL, for example) support full-text searching (queries against free text like a blog post, movie review, research article, etc.), but they may struggle to provide efficient searches in near-real time on heavy loads.&lt;br&gt;
The distributed nature of a search engine like Elasticsearch provides instant scalability that most databases are not designed for. A search engine developed with a backing database (with no full-text search capabilities) may not be able to provide relevant search results for queries, let alone cope with volumetric growth and serve results in real time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Full-text searching with databases
&lt;/h3&gt;

&lt;p&gt;Relational databases like Oracle and MySQL support full-text search functionality, albeit with less functionality than a modern full-text search engine like Elasticsearch. They are fundamentally different when it comes to storing and retrieving data, so you must be sure to prototype your requirements before choosing one of them. Usually, if the schemas are not going to change or data loads are low, and you already have a database engine with full-text search capabilities, beginning with full-text search on a database may make sense.&lt;/p&gt;

&lt;h3&gt;
  
  
   Databases vs. search engines
&lt;/h3&gt;

&lt;p&gt;When building a search service on a traditional database, we need to consider and understand whether our requirements can be satisfied by the database efficiently and effectively. Most databases are designed to store large amounts of data but, unfortunately, are not well-suited for use as full-text search engines, for several reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Indexing and search performance —Full-text search requires efficient indexing and performant search and analytical capabilities, which traditional databases are not optimized for. Databases may struggle with indexing large volumes of data and, as a result, may exhibit poor query performance. Search engines like Elasticsearch and Solr are specifically designed to handle large amounts of text data and provide search results in near-real time. Search engines can handle large-scale data, indexing it and searching it much faster than traditional databases, as they are pretty much designed from the ground up for optimized search operations. Unfortunately, relational databases lack advanced search features such as fuzzy logic, stemming, synonyms, and so on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Search —Searching with traditional databases is more or less based on the exact matching of data values. While this is suitable for non-search-related find operations on structured data, it is a definite no-no for natural language queries, which are often complex. User queries are often misspelled, misconstructed grammatically, or incomplete and may contain synonyms and other language structures that databases fail to understand. In natural language queries, users may not use the exact terms they are searching for (spelling mistakes), and unfortunately, traditional databases are not designed to support misspelled user input. This feature is supported by the fuzzy matching search function (words that are similar but not exactly the same) in modern search engines. In traditional databases, data is often normalized, meaning it is spread across multiple tables and columns. This can make it difficult to search for data across multiple fields in a single query. Traditional databases are not designed to handle the types of unstructured and semi-structured data that are common in full-text search scenarios.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text analysis and processing —Search engines must often handle multiple languages and character sets, which traditional databases may not support. Search engines perform text analysis and processing to extract meaning from text, but traditional databases are not designed or optimized for this purpose.&lt;/li&gt;
&lt;li&gt;Scalability and flexibility—Full-text search engines are designed to handle large amounts of data and high query loads. Traditional databases can have scalability problems when dealing with large amounts of text data.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Search engines are designed from scratch to handle unstructured data, while databases are optimized for handling structured data. These limitations make traditional databases less suitable for use as full-text search engines; specialized search engine technologies such as Elasticsearch, Solr, Lucene, etc., are often used to provide advanced search functionality for text data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; Many databases have added text search capabilities to their feature sets. However, they still may not be able to deliver performance, scalability, and functionality on par with specialized full-text search engines.&lt;/p&gt;

&lt;p&gt;Nothing is stopping us from embracing both worlds: in some use cases, a combination of traditional databases and search engines can be employed. For example, a database can be used for transactional purposes and a search engine for search and analytics. But our focus in this document is search engines—and Elasticsearch in particular. In the next section, we review the era of modern search engines before we introduce Elasticsearch.&lt;/p&gt;




&lt;h2&gt;
  
  
   Modern search engines
&lt;/h2&gt;

&lt;p&gt;Modern search engines are trying hard to meet ever-growing business requirements by embracing new and exciting features every day. Cheap hardware combined with the explosion of data is leading to the emergence of these modern search beasts. Let’s consider present-day search engines and the features and functionality they offer. We can summarize what a good modern search engine should provide as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First-class support for full-text (unstructured) and structured data&lt;/li&gt;
&lt;li&gt;Type-ahead suggestions, auto-correction, and “did-you-mean” recommendations&lt;/li&gt;
&lt;li&gt;Forgiveness for users’ spelling mistakes&lt;/li&gt;
&lt;li&gt;Search capabilities on geolocations&lt;/li&gt;
&lt;li&gt;Easy scalability, either up or down, based on fluctuating demand&lt;/li&gt;
&lt;li&gt;Blazing performance: speedy indexing and search capabilities&lt;/li&gt;
&lt;li&gt;Architecture that provides a high-availability, fault-tolerant distributed system&lt;/li&gt;
&lt;li&gt;Support for machine learning functionalities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this section, we briefly discuss the high-level features of a modern search engine. Then the following section introduces a couple of search engines available in the market, including Elasticsearch.&lt;/p&gt;

&lt;h3&gt;
  
  
   Functionality
&lt;/h3&gt;

&lt;p&gt;Modern search engines were developed to satisfy full-text search requirements while also providing other advanced functions. They are designed to provide fast and relevant search results to users by indexing and searching large volumes of text data (going forward, we will drop the word modern when mentioning search engines).&lt;/p&gt;

&lt;p&gt;Search engines can quickly index large amounts of text data and make it searchable. This process typically involves breaking the text data into tokens and building an inverted index, which maps each token to the documents that contain it.&lt;/p&gt;

&lt;p&gt;Search engines are also expected to perform advanced text analysis and processing, such as synonyms, stemming, stop words, and other natural language processing techniques, to extract meaning from text and improve search results. They can process user queries and rank search results based on various factors such as relevance and popularity. They can also handle high query loads and large amounts of data and can scale horizontally by adding more nodes to a cluster.&lt;/p&gt;

&lt;p&gt;Finally, search engines provide advanced analytics capabilities, looking at the data to provide summaries, conclusions, and intelligence for businesses. They also support rich visualizations, near-real-time search, performance monitoring, and machine learning-based insights.&lt;/p&gt;

&lt;h3&gt;
  
  
  Popular search engines
&lt;/h3&gt;

&lt;p&gt;While a handful of search engines are available in the market, I’ll mention just few of them, all of which are built on top of Apache Lucene.&lt;/p&gt;

&lt;h4&gt;
  
  
  Elasticsearch
&lt;/h4&gt;

&lt;p&gt;Shay Banon, founder of Elastic, developed a search product called Compass in early 2000. It was based on an open source search engine library called &lt;a href="https://lucene.apache.org" rel="noopener noreferrer"&gt;Apache Lucene&lt;/a&gt;. Lucene is Doug Cutting’s full-text search library, written in Java. Because it’s a library, we must import it and integrate it with an application using its APIs. Compass and other search engines use Lucene to provide a generalized search engine service so we don’t have to integrate Lucene from scratch into applications. Shay eventually decided to abandon Compass and focus on Elasticsearch because it had more potential.&lt;/p&gt;

&lt;h4&gt;
  
  
   Apache Solr
&lt;/h4&gt;

&lt;p&gt;Apache Solr is an open source search engine that was built on Apache Lucene in 2004. Solr is a strong competitor to Elasticsearch and has a thriving user community, and it is closer to open source than Elasticsearch (Elastic moved from Apache to Elastic License and Server Side Public License ([SSPL] in early 2021). Both Solr and Elasticsearch excel at full-text searching; however, Elasticsearch may have an edge when it comes to analytics.&lt;br&gt;
While both products compete in almost all functionality, Solr is a favorite for large, static datasets working in big data ecosystems. Obviously, we have to run through prototypes and analysis to pick a product; the general trend is for projects that are integrating with a search engine for the first time to consider Elasticsearch due to its top-class documentation, community, and nearly no-hurdle startup. You must make a detailed comparison of your intended use cases for the search engine before adopting and embracing one.&lt;/p&gt;

&lt;h4&gt;
  
  
  Amazon OpenSearch
&lt;/h4&gt;

&lt;p&gt;Elastic changed its licensing policy in 2021. The licensing, which applies to Elasticsearch release versions 7.11 and above, has been moved from open source to a dual license under an Elastic License and SSPL. This license allows the community to use the product for free, as expected, but managed service providers can no longer provide the products as services. There was a spat between Elastic and Amazon Web Services (AWS) when AWS created a forked version of Elasticsearch—called Open Distro for Elasticsearch—and offered it as a managed service. This spat led to the change in the license, which eventually led to OpenSearch’s birth.&lt;/p&gt;

&lt;p&gt;As Elastic moved from the open source licensing model to the SSPL model, a new product called &lt;a href="https://opensearch.org" rel="noopener noreferrer"&gt;OpenSearch&lt;/a&gt; was developed to fill the gaping hole left by the new licensing agreement. The base code for OpenSearch was created from the open source Elasticsearch and Kibana version 7.10.2. The product’s first General Availability version 1.0 was released in July 2021. Watch out for OpenSearch becoming a competitor to Elasticsearch in the search engine space.&lt;/p&gt;

&lt;p&gt;Now that we have a fair understanding of what a modern search engine is and the shape of the search landscape, let’s jump into an overview of Elasticsearch.&lt;/p&gt;




&lt;h2&gt;
  
  
  Elasticsearch overview
&lt;/h2&gt;

&lt;p&gt;Elasticsearch is an open source search and analytics engine. Developed in Java, it is an ultra-fast, highly available search engine built on the popular full-text library Apache Lucene (&lt;a href="https://lucene.apache.org" rel="noopener noreferrer"&gt;https://lucene.apache.org&lt;/a&gt;). Elasticsearch wraps around the powerful functionality of Lucene by providing a distributed system with RESTful interfaces. Lucene is the powerhouse of Elasticsearch, and Kibana is the administrative UI to manage and work with Elasticsearch.&lt;/p&gt;

&lt;p&gt;Full-text searching is where Elasticsearch excels as a modern search engine. It can retrieve relevant documents in response to a user’s search criteria at an awesome speed. We can search for exact terms, too, like keywords, dates, or a range of numbers or dates. Elasticsearch is packed with top-notch features such as relevancy, “did-you-mean” suggestions, auto-completion, fuzzy and geospatial searching, highlighting, and more.&lt;/p&gt;

&lt;p&gt;In addition to being a frontrunner in providing near-real-time search capabilities, Elasticsearch stands tall in statistical aggregations on big data. Of course, we must consider the use case before embracing the product, as Elasticsearch may not be the best fit for every use case. Out of the box, Elasticsearch also boasts commendable features such as application performance monitoring, predictive analytics and outlier detection, and security threat monitoring and detection.&lt;/p&gt;

&lt;p&gt;Elasticsearch focuses on finding a deeper meaning in the data that’s been collected. It can aggregate data, perform statistical calculations, and find intelligence within the data. We can create rich visualizations and dashboards and share them with others using Kibana tooling. Elasticsearch can find averages, sums, means, and modes as well as undertaking complex analytics such as bucketing data in histograms and other analytical functions.&lt;/p&gt;

&lt;p&gt;Furthermore, Elasticsearch runs supervised and unsupervised machine learning algorithms on our data. Models help to detect anomalies, find outliers, and forecast events. In supervised learning mode, we can provide training sets so the model learns and makes predictions.&lt;/p&gt;

&lt;p&gt;Elasticsearch also comes with the capability to observe applications and their health by monitoring performance metrics such as the memory and CPU cycles of the web servers in a network. It lets us sift through millions of web server logs to find or debug application issues. Elasticsearch also invests time and resources in building security solutions: for example, alerting us to security threats, IP filtering, endpoint prevention, and more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core areas
&lt;/h3&gt;

&lt;p&gt;Elastic, the company behind Elasticsearch, has been positioning itself predominantly in three core areas: search, observability, and security, as shown in figure 1.2. Let’s look at each of these areas in turn.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firu1mhxestp9t01231iv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firu1mhxestp9t01231iv.png" alt="Figure 1.2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;Figure 1.2&lt;/center&gt;

&lt;h3&gt;
  
  
  Figure 1.2 Core application areas of Elastic, the company behind Elasticsearch
&lt;/h3&gt;

&lt;h4&gt;
  
  
   Elastic Enterprise Search
&lt;/h4&gt;

&lt;p&gt;Whether letting users search across varied content providers (like Slack, Confluence, Google Drive, and others) or enabling search capabilities for our applications, apps, and websites, the Elastic Enterprise Search suite helps build models and a customized search engine.&lt;/p&gt;

&lt;p&gt;Search can be integrated deep into a multitude of applications in various domains—business, infrastructure, applications, and so on. Users can create a web application backed by Elasticsearch, a mobile app supported by Elasticsearch, or a server-side search “service with Elasticsearch as the spine for search capabilities.&lt;/p&gt;

&lt;h4&gt;
  
  
  Elastic Observability
&lt;/h4&gt;

&lt;p&gt;Applications running on infrastructure produce a lot of metrics that are usually used for application observability and monitoring. We can use Elasticsearch in the observability space: the state of applications, servers, racks, and modules can all be monitored, logged, tracked, and alerted. We can also use the Elastic tools to perform application management and monitoring on a large scale.&lt;/p&gt;

&lt;h4&gt;
  
  
   Elastic Security
&lt;/h4&gt;

&lt;p&gt;Elastic enters the realm of security by enabling threat detection and prevention and providing advanced features such as the capability of removing malware at the source, encryption at rest, and more. As a security information and event management (SIEM) tool, Elastic is positioning itself to protect organizations with its advanced security toolkits.&lt;/p&gt;

&lt;h4&gt;
  
  
  Elastic Stack
&lt;/h4&gt;

&lt;p&gt;Elasticsearch is the core of the search engine, and a handful of Elastic products complement it. The suite of products is called the Elastic Stack and includes Kibana, Logstash, Beats, and Elasticsearch. (It was formally called ELK Stack but was renamed Elastic Stack after Beats was introduced into the product suite.)&lt;/p&gt;

&lt;p&gt;The combination of these four products helps build an enterprise application by integrating, consuming, processing, analyzing, searching, and storing various data sets from disparate sources. As demonstrated in figure 1.3, Beats and Logstash bring the data into Elasticsearch, while Kibana is the visual UI that works on that data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdpaz9vzwk5katbo3r4ql.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdpaz9vzwk5katbo3r4ql.png" alt="Figure 1.3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;Figure 1.3&lt;/center&gt;

&lt;h3&gt;
  
  
  Figure 1.3 The Elastic Stack: Beats, Logstash, Elasticsearch, and Kibana
&lt;/h3&gt;

&lt;p&gt;Before we move on to look at use cases for Elasticsearch, let’s briefly go over these essential moving parts at a high level.&lt;/p&gt;

&lt;h4&gt;
  
  
   BEATS
&lt;/h4&gt;

&lt;p&gt;Beats are single purpose data shippers; they load data from out various external systems and pump it into Elasticsearch. Various types of beats are available out of the box. These include Filebeat, Metricbeat, Heartbeat, etc., and each performs a specific data consumption task. These are single-purpose components: for example, Filebeats are designed for file-based transports and Metricbeats for vital machine and operating system memory and CPU information. The beats’ agents are installed on the servers so they can consume data from their source and send it to their destination.&lt;/p&gt;

&lt;h4&gt;
  
  
   LOGSTASH
&lt;/h4&gt;

&lt;p&gt;Logstash is an open source data-processing engine. It extracts data originating from multiple sources, processes it, and sends it to a variety of target destinations. During the processing of the data, Logstash transforms and enriches the data. It supports a myriad of sources and destinations including files, HTTP, JMS, Kafka, Amazon S3, Twitter, and dozens of others. It promotes a pipeline architecture, and every event that goes through the pipeline is parsed as per the preconfigured rules, thus creating a real-time pipeline for data ingestion.&lt;/p&gt;

&lt;h4&gt;
  
  
   KIBANA
&lt;/h4&gt;

&lt;p&gt;Kibana is a multipurpose web console that provides a host of options such as executing queries; developing dashboards, graphs, and chart visualizations; and creating dropdowns and aggregations. However, we can use any REST client to talk to Elasticsearch to invoke the APIs, not just Kibana. For example, we can invoke APIs using cURL, Postman, or native language clients.&lt;/p&gt;

&lt;h3&gt;
  
  
  Elasticsearch use cases
&lt;/h3&gt;

&lt;p&gt;Pinpointing Elasticsearch for a particular use case or domain is difficult. It is omnipresent in many areas from search to analytics to machine learning jobs. It is widely used across a multitude of industries, including finance, defense, transport, government, retail, cloud, entertainment, space, and more. Let’s take a high-level glance at how Elasticsearch can be used in an organization.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use case: Search engine
&lt;/h4&gt;

&lt;p&gt;Elasticsearch has become the go-to technology for its full-text search capabilities. The product is not limited to full-text searching but can also be used for structured data and geolocation-based searches. Broadly speaking, customers use Elasticsearch in three domains: App Search, Enterprise Search, and Site Search.&lt;/p&gt;

&lt;p&gt;In App Search, Elasticsearch serves as a backbone, providing search and analytical capabilities for applications. A search service backed up by Elasticsearch can be designed as a microservice that serves the application’s search requirements, such as searching for customers, orders, invoices, emails, and so on.&lt;/p&gt;

&lt;p&gt;In most organizations, data is scattered across many data stores, applications, and databases. For example, organizations are often integrated with Confluence, intranet spaces, Slack, email, databases, cloud drives (iCloud drive, Google Drive, etc.), and others. Collating and searching through vast amounts of data with integrations to varied sources is a challenge for these organizations. This is where Elasticsearch can be employed for Enterprise Search and data organization.&lt;/p&gt;

&lt;p&gt;If we have an online business website amassing data, providing search is something of a bare necessity for attracting customers and keeping them happy. Site Search is a software-as-a-service (SaaS) offering from Elastic that, once enabled, crawls through the given site pages, fetching data and building indices backed by Elasticsearch. Once the crawling and indexing are complete, the site can be integrated easily with the search facility. The Site Search module also helps create a search bar and the code snippet related to it. The website administrator can copy the snippet of generated code onto their homepage to enable a search bar instantly, thus making the website fully functional with integrated search.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use case: Business analytics
&lt;/h4&gt;

&lt;p&gt;Organizations capture tons of data from various sources, and that data often holds the key to survival and success. Elasticsearch can help extract trends, statistics, and metrics from data, giving organizations knowledge about their operations, sales, turnover, profits, and many other features for timely management.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use case: Security analytics and threat and fraud detection
&lt;/h4&gt;

&lt;p&gt;Data security and potential breaches of it are nightmares for organizations. Elasticsearch’s security analytics help organizations analyze every bit of information—be it from applications, a network, endpoints, or the cloud. This analysis can provide insights into threats and vulnerabilities and let the organization hunt for malware and ransomware, thus alleviating the risk of falling prey to hackers.&lt;/p&gt;

&lt;h4&gt;
  
  
   Use case: Logging and application monitoring
&lt;/h4&gt;

&lt;p&gt;Applications spit out a lot of data in the form of application logs and metrics. These logs provide insights into the health of the application. With the advent of the cloud and the microservices world, logs are scattered across services, and meaningful analysis is a cumbersome affair. Elasticsearch is our friend here. One of the popular use cases for Elasticsearch is indexing logs and analyzing them for application errors and debugging purposes.&lt;/p&gt;

&lt;p&gt;Elasticsearch is a powerful and flexible search and analytics engine, but it’s not suitable for every use case. Let’s briefly go over the issues we may encounter and use cases for which Elasticsearch is the wrong choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unsuitable Elasticsearch uses
&lt;/h3&gt;

&lt;p&gt;Not every use case can be satisfied by Elasticsearch. It is a powerful and flexible search and analytics engine, but unfortunately, this tool has limitations that we must consider before choosing it for our requirements. Here are a few scenarios where Elasticsearch may be an incorrect or inefficient solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Relational data—Elasticsearch is not the right tool to accommodate search over data that has relationships and needs to perform complex database joins. Elasticsearch is not designed to handle complex relational data structures. If your data is relationship-heavy, a relational database like MySQL or PostgreSQL may be a better fit. Most modern databases (MySQL, PostgreSQL, etc.) also offer full-text search capabilities, although the features are not as advanced as in a modern search engine like Elasticsearch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Transactional data—Elasticsearch is an “eventually consistent” search engine, which makes it unsuitable for applications that require immediate consistency, such as financial transactions. For these types of use cases, consider using a traditional relational database or a NoSQL database like MongoDB.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Geospatial data—While Elasticsearch has built-in support for geospatial data, it may not be the most efficient solution for large-scale geospatial analytics. For these use cases, consider using a dedicated geospatial database like PostGIS or a geospatial analytics platform like ArcGIS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;High-write workloads—Elasticsearch can handle high-read workloads, but it is not optimized for high-write workloads. If you need to index large amounts of data in real time, consider using a dedicated indexing engine like Apache Flume or Apache Kafka.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Online analytical processing (OLAP) data—If you need to perform complex multidimensional analysis on large data sets, a traditional OLAP database like Microsoft Analysis Services or IBM Cognos may be a better fit than Elasticsearch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Large binary data—While Elasticsearch can handle large amounts of text data, it may not be the best solution for indexing and searching large binary data like videos or images. For these use cases, consider using a dedicated binary data store like Hadoop Distributed File System (HDFS), Amazon S3, or Azure Files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Real-time analytics—Elasticsearch is great for performing real-time search and analytics on large data sets, but it may not be the most efficient solution for real-time data processing and analytics. Instead, consider a specialized real-time analytics platform like Apache Spark or Apache Flink.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Latency-sensitive applications—Although Elasticsearch is designed to handle high-volume search and analytical queries, it can still have latency issues when dealing with large amounts of data. For applications that require sub-millisecond response times, a specialized search engine like Apache Solr or a columnar database like Apache Cassandra may be a better fit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Other types—Elasticsearch is not a preferred solution for time-series data, graph data, in-memory data, and various other types of data. If you need to store and analyze time-series data, a specialized time-series database like InfluxDB or TimescaleDB may be a better fit. Similarly, a graph database such as Neo4j may help you tackle graph data.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s important to evaluate your specific use case and requirements before choosing Elasticsearch as your technology and tool. In the next section, we discuss common misconceptions about Elasticsearch as a tool, a technology, and a search solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Misconceptions
&lt;/h3&gt;

&lt;p&gt;A major misconception about Elasticsearch is mistaking it for a traditional relational database. It’s also a common misunderstanding that setting up Elasticsearch is easy, while in reality, many tweaks are required to set up a decent-sized cluster. In addition, Elasticsearch is often thought of as a technology used for text search, when in fact it can be used for a wide range of search and analytics use cases. The following list summarizes some common misconceptions about Elasticsearch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Elasticsearch is easy to set up and manage. While Elasticsearch is relatively straightforward to set up and get started with, it can be challenging to manage and scale as data grows and use cases increase. Although everything works out of the box, making an engineer’s life easy, taking Elasticsearch into the production environment requires effort. We may need to tweak the configuration and fine-tune the memory, manage node failures, or even scale the cluster to handle petabytes of data as our data grows.&lt;/li&gt;
&lt;li&gt;Elasticsearch is a relational database. Elasticsearch is not a relational database and does not support traditional relational database features like transactions, foreign keys, and complex join operations. For example, we can’t enforce referential integrity or perform complex “oin operations. For example, we can’t enforce referential integrity or perform complex join operations in Elasticsearch. If you need these features, a proven relational database like MySQL or PostgreSQL is definitely your solution.&lt;/li&gt;
&lt;li&gt;Elasticsearch can handle all types of data. Elasticsearch is versatile and can handle a wide range of data types, but it is not designed to handle every type of data with equal ease. For example, it may not be the best solution for real-time data processing and analytics or for handling large binary data. If you need to store and process large binary data like videos or images, consider using a dedicated binary data store like HDFS or Amazon S3.&lt;/li&gt;
&lt;li&gt;Elasticsearch is only for text search. While Elasticsearch is great for text search, it can also perform complex analytics on structured and unstructured data. For example, we can use Elasticsearch to perform aggregations, analyze log data, and visualize data using Kibana.&lt;/li&gt;
&lt;li&gt;Elasticsearch can replace all other technologies. Elasticsearch is a powerful and flexible technology, but it is not a one-size-fits-all solution and or the best choice for every use case. It can never replace a traditional relational database, for example.&lt;/li&gt;
&lt;li&gt;Elasticsearch is always faster than other technologies. Elasticsearch is designed for high performance and is expected to perform well under heavy loads. However, there’s only so much Elasticsearch can do, and its performance primarily depends on how well the platform engineers fine-tune it.&lt;/li&gt;
&lt;li&gt;Elasticsearch deals with big data only. Elasticsearch can handle petabytes of data in large data sets, but it is equally performant when dealing with small data sets on the order of a few gigabytes. For example, we can use Elasticsearch to search and analyze data for an organization’s small email database or a startup company without much effort.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are just a few examples of misconceptions about Elasticsearch. As mentioned earlier, you must carefully evaluate your specific requirements and use case before choosing Elasticsearch or any other technology.&lt;/p&gt;

&lt;h3&gt;
  
  
  Popular adoption
&lt;/h3&gt;

&lt;p&gt;A long list of organizations use Elasticsearch for everything from searching to business analysis, log analytics, security alert monitoring, and application management, as well as using it as a document store. Let’s consider some of these organizations and how they put Elasticsearch to use in their operations.&lt;/p&gt;

&lt;p&gt;Uber powers its rider and event prediction using Elasticsearch. It does so by storing millions of events, searching through them, and analyzing the data at a near-real-time rate. Uber predicts demand based on location, time, day, and other variables, including taking past data into consideration. This helps Uber deliver rides pretty.&lt;/p&gt;

&lt;p&gt;Netflix adopted the Elastic Stack to provide customer insights to its internal teams. It also uses Elasticsearch for log event analysis to support debugging, alerting, and managing its internal services. Email campaigns and customer operations are all backed by the Elasticsearch engine. The next time you receive an email from Netflix mentioning a newly added movie or TV series, keep in mind that the campaign analytics behind that simple email were all supported by Elasticsearch.&lt;/p&gt;

&lt;p&gt;PayPal embraced Elasticsearch as a search engine to allow customers to store and search through their transactions. The company has implemented transaction search features along with analytics for use by merchants, end customers, and developers.&lt;/p&gt;

&lt;p&gt;Similarly, the online e-commerce company eBay adopted Elasticsearch to support full-text searching by end users. As users, we are using Elasticsearch directly when searching through eBay’s inventory. The company also uses the Elastic Stack for analytics, log monitoring, and storing transactional data in a document store.&lt;/p&gt;

&lt;p&gt;GitHub, a popular code repository for developers, indexes its 8 million (and counting) code repositories—consisting of over 2 billion documents—with Elasticsearch to enable a powerful search experience for its users. Similarly, Stack Overflow uses Elasticsearch to provide developers with quick and relevant answers, and Medium (a popular blog platform) uses the Elastic Stack to serve reader queries in a near-real-time mode.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generative AI and modern search
&lt;/h3&gt;

&lt;p&gt;Unless you are living in a cave, you have undoubtedly heard about a recent internet revolution: ChatGPT. ChatGPT is a generative AI tool that was developed and released by the OpenAI team in November 2022. Is isn’t often that a technically superior tool lands in the hands of the general public that can help them in unimaginable ways, such as creating a travel itinerary for a summer trip to Athens, summarizing a legal document in layman’s terms, developing a self-help plan for losing weight, analyzing code for security and performance bugs, designing an application’s data models, comparing and contrasting technologies for a specific use case, writing complaint letters to the Twitter CEO and much more.&lt;/p&gt;

&lt;p&gt;ChatGPT (&lt;a href="https://chat.openai.com" rel="noopener noreferrer"&gt;https://chat.openai.com&lt;/a&gt;) is a conversational agent (chatbot) built on a GPT (generative pretrained transformer) architecture, and it is capable of generating human-like text based on user prompts. It is an instance of a large language model (LLM) designed for conversation with a specific goal of generating safe, relevant content while engaging in a meaningful dialogue. The model is fed vast amounts of text data and learns to predict the next word in a sentence. It is trained using a diverse range of internet text, but it can also be fine-tuned with specific datasets for various tasks. Through this process, the model learns parts and parcels of human language text: grammar, punctuation, syntax, facts about the world, and some degree of reasoning ability.&lt;/p&gt;

&lt;p&gt;NOTE LLM is a broad term that refers to any large-scale model trained to understand or generate human-like text. These models are characterized by their vast number of parameters and their ability to handle a wide range of natural language processing tasks. LLMs can be based on various architectures and training methods.&lt;/p&gt;

&lt;p&gt;With the release of ChatGPT to the public, a sudden race in the space of search using AI emerged overnight. ChatGPT has become a disruptor to many industries and is no less a threat to Google search. AI-backed tools similar to ChatGPT will disrupt many industries in the coming years. Under tremendous pressure—and possibly to save its search leader status—Google decided to unleash its version of conversational generative AI: its agent called Bard (&lt;a href="https://bard.google.com" rel="noopener noreferrer"&gt;https://bard.google.com&lt;/a&gt;) was made publicly available in May 2023.&lt;/p&gt;

&lt;p&gt;In the meantime, Microsoft committed to investing $10 billion in ChatGPT, over and above its initial investment of $3 billion since 2019. Microsoft’s Edge browser is integrated with ChatGPT via the Bing search engine, which also was made publicly available in May 2023. In addition, Microsoft rolled out AI-powered Microsoft 365 apps, so the AI agent is available in Microsoft Word, Excel, email, and other tools. Meta’s LLaMA is another tool that has begun competing in the generative AI race.&lt;/p&gt;

&lt;p&gt;Search engineers are being asked fundamental questions, including how generative AI agents will change the course of search. Let’s answer this question by asking ChatGPT how AI agents can complement or help modern search or change its direction. These are the areas where tools like generative AI will reshape the search space:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Intuitive Search—Search queries will become more conversational and intuitive. Generative AI models like GPT-4 have an advanced understanding of natural language, enabling them to interpret complex queries more effectively. Users will no longer need to rely on specific keywords or phrases; they can simply ask questions as they would in a conversation with another person. This will allow for more accurate and relevant search results, as AI can better comprehend the context and intent of the query. With the introduction and release of highly capable generative AI agents and models, there is a greater scope to significantly reshape full-text search capabilities provided by modern search engines like Elasticsearch. We can expect to see several key changes that will redefine the search experience for both users and developers as this technology is increasingly integrated into search platforms.&lt;/li&gt;
&lt;li&gt;Personalized search —With the incorporation of generative AI, search results can become more personalized and adaptive. Search engines will be able to learn many valuable data points from users’ preferences, behavior, and search history, which in turn will help engines tailor results to meet individual users’ needs. As the AI gathers more data, it will continually refine its understanding of what users are looking for, leading to an increasingly customized search experience.&lt;/li&gt;
&lt;li&gt;Predictive search —Generative AI has the potential to make search engines more proactive in anticipating user needs. Instead of merely responding to queries, AI-driven search engines may be able to predict what information users are interested in, based on their previous interactions or current context. This will allow search platforms to proactively offer relevant suggestions, increasing the value of the search experience and reducing the need for users to perform additional queries.&lt;/li&gt;
&lt;li&gt;Advanced search —Generative AI will enable search engines to provide more diverse and rich search results. By understanding the context and semantics of a query, AI-driven search engines can generate content summaries and relevant visualizations and even synthesize new information to help answer a user’s question. This will lead to a more comprehensive and informative search experience that goes beyond merely linking to existing content.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Search is the new normal and the most sought-after functionality for organizations, enabling competitive advantage.&lt;/li&gt;
&lt;li&gt;Search engines built using relational databases as the backend used to serve our search purposes but can’t fulfill the full-fledged search functionality found in modern search engines.&lt;/li&gt;
&lt;li&gt;Modern search engines provide multifaceted, full-text search capabilities and multifold benefits from basic search to advanced search and analytical functions, all with split-second performance. They are also expected to handle terabytes to petabytes of data and scale if needed.&lt;/li&gt;
&lt;li&gt;Elasticsearch is an open source search and analytics engine built over Apache Lucene. It is a highly available server-side application developed in Java.&lt;/li&gt;
&lt;li&gt;Because Elasticsearch was designed as a programming-language-agnostic product, communication with the server takes place over HTTP using rich RESTful APIs. These APIs receive and send data in JSON format.&lt;/li&gt;
&lt;li&gt;The Elastic Stack is a suite of products composed of Beats, Logstash, Elasticsearch, and Kibana. Beats are single-purpose data shippers, Logstash is a data-processing ETL (extract, transform, load) engine, Kibana is the administrative UI tool, and Elasticsearch is the heart and soul of the stack.&lt;/li&gt;
&lt;li&gt;The Elastic Stack enables an organization to position itself in three core areas: search, observability, and security.&lt;/li&gt;
&lt;li&gt;Elasticsearch has become popular over the last few years due to its structured/unstructured search and analytics capabilities; rich set of RESTful APIs; its schema-free nature; and performance, high-availability, and scalability characteristics.&lt;/li&gt;
&lt;li&gt;AI-powered search is here. With the advent of generative AI and ChatGPT, the search space will be explored further, and search will become more intuitive and predictive.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Excerpt From Elasticsearch in Action, Second Edition Madhusudhan Konda.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>elasticsearch</category>
    </item>
    <item>
      <title>Comparing React VS HTMX: Choosing the Right Frontend Approach</title>
      <dc:creator>Victor Hazbun</dc:creator>
      <pubDate>Fri, 23 Jun 2023 03:53:31 +0000</pubDate>
      <link>https://dev.to/victorhazbun/comparing-react-vs-htmx-choosing-the-right-frontend-approach-hpb</link>
      <guid>https://dev.to/victorhazbun/comparing-react-vs-htmx-choosing-the-right-frontend-approach-hpb</guid>
      <description>&lt;h2&gt;
  
  
  Introduction:
&lt;/h2&gt;

&lt;p&gt;Building modern web applications often requires combining a robust backend framework with a frontend framework to create dynamic and interactive user experiences. React and HTMX are two popular choices when it comes to frontend development. In this article, we'll explore the differences between React and HTMX, and how they can be used to create compelling web applications. We'll also provide practical examples for each approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  React:
&lt;/h2&gt;

&lt;p&gt;React has gained significant popularity in the web development community due to its component-based architecture and efficient rendering capabilities.&lt;/p&gt;

&lt;p&gt;Using React involves setting up frontend environment powered by tools like Webpack. React components can then be used to fetch data from the backend through APIs and render it dynamically on the client-side. This approach provides a seamless user experience, as React updates only the necessary parts of the UI, avoiding full page reloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Example App:
&lt;/h2&gt;

&lt;p&gt;This example actively searches a contacts database as the user enters text.&lt;/p&gt;

&lt;p&gt;We start with a search input and an empty table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;ContactSearch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;searchResults&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearchResults&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;setSearchResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Search Contacts
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"htmx-indicator"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/img/bars.svg"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Loading..."&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; Searching...
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;
        &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Begin Typing To Search Users..."&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSearch&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"table"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;First Name&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Last Name&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Email&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search-results"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searchResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;ContactSearch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Express.js app for React frontend
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// POST /search route&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Simulating search logic&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jane@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// Filter the search results based on the searchTerm&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstNameMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastNameMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;firstNameMatch&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;lastNameMatch&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;emailMatch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Simulating delay for illustration purposes&lt;/span&gt;
  &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filteredResults&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delayed response for 1 second&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Start the server&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server started on port 3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
   HTMX:
&lt;/h2&gt;

&lt;p&gt;HTMX takes a different approach by focusing on enhancing the user interface with minimal JavaScript code. HTMX allows you to add interactivity to your frontend using declarative attributes embedded directly in your HTML markup.&lt;/p&gt;

&lt;p&gt;With HTMX we leverage the power to update individual task items without reloading the entire page. HTMX achieves this by making HTTP requests to the server in the background and updating specific elements on the page using the hx-swap attribute. This approach simplifies the development process by reducing the need for separate frontend tooling and JavaScript code.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTMX Example App:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt; 
  Search Contacts 
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"htmx-indicator"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/img/bars.svg"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt; Searching... 
   &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt; 
&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; 
       &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Begin Typing To Search Users..."&lt;/span&gt; 
       &lt;span class="na"&gt;hx-post=&lt;/span&gt;&lt;span class="s"&gt;"/search"&lt;/span&gt; 
       &lt;span class="na"&gt;hx-trigger=&lt;/span&gt;&lt;span class="s"&gt;"keyup changed delay:500ms, search"&lt;/span&gt; 
       &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#search-results"&lt;/span&gt; 
       &lt;span class="na"&gt;hx-indicator=&lt;/span&gt;&lt;span class="s"&gt;".htmx-indicator"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;table&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"table"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;First Name&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Last Name&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Email&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tbody&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"search-results"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Express.js app for HTMX frontend
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// POST /search route&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Simulating search logic&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jane@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// Filter the search results based on the searchTerm&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstNameMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastNameMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;firstNameMatch&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;lastNameMatch&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;emailMatch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Generate the HTML for search results&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filteredResults&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Simulating delay for illustration purposes&lt;/span&gt;
  &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delayed response for 1 second&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Start the server&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server started on port 3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Choosing the Right Approach:
&lt;/h2&gt;

&lt;p&gt;When deciding between React and HTMX, consider the following factors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Project Complexity: If your application requires complex UI interactions, real-time updates, and a rich set of reusable components, React might be the better choice. React's component-based architecture and vast ecosystem provide the necessary tools to handle such scenarios.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Development Speed: HTMX can be an excellent choice for projects where simplicity and speed of development are paramount. With HTMX, you can add interactivity to your frontend directly, reducing the need for extensive JavaScript development and tooling setup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Team Expertise: Consider the skills and expertise of your development team. If they are well-versed in React and comfortable with the React ecosystem, React may be the preferred option. On the other hand, if your team prefers a simpler frontend approach, HTMX could be a better fit.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Both React and HTMX offer powerful frontend solutions. React provides a comprehensive framework for building complex, interactive web applications, while HTMX simplifies interactivity by embedding declarative attributes directly in HTML markup. Choosing between the two depends on your project requirements, complexity, and the expertise of your development team. Evaluate the trade-offs, consider your specific needs, and select the approach that aligns best with your goals.&lt;/p&gt;

</description>
      <category>react</category>
      <category>htmx</category>
      <category>node</category>
      <category>express</category>
    </item>
    <item>
      <title>Staff Engineer Interview: Navigating the Path to Technical Leadership</title>
      <dc:creator>Victor Hazbun</dc:creator>
      <pubDate>Fri, 23 Jun 2023 00:52:30 +0000</pubDate>
      <link>https://dev.to/victorhazbun/staff-engineer-interview-navigating-the-path-to-technical-leadership-3a9j</link>
      <guid>https://dev.to/victorhazbun/staff-engineer-interview-navigating-the-path-to-technical-leadership-3a9j</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Becoming a staff engineer is a significant milestone in one's technical career. It represents a transition from individual contributor to a leadership role, where one is expected to guide and influence the engineering team's direction. To successfully navigate the staff engineer interview process and excel in the role, it is crucial to possess a combination of technical expertise, leadership skills, and a deep understanding of software development principles. In this article, we will explore key aspects of a staff engineer interview, including potential interview questions, essential skills, and the knowledge necessary for staff engineers in today's dynamic tech landscape.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Role of a Staff Engineer
&lt;/h2&gt;

&lt;p&gt;A staff engineer is a senior-level position that requires a comprehensive understanding of software engineering principles, coupled with strong leadership and communication abilities. As a staff engineer, you will be responsible for driving technical decisions, mentoring junior engineers, and collaborating with cross-functional teams. You will play a crucial role in defining the architecture, scalability, and performance of software systems while guiding the team towards successful project outcomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Potential Interview Questions
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Technical Depth&lt;/strong&gt;: Expect questions that assess your expertise in core technical areas relevant to the company's tech stack. These may include system design, algorithms, data structures, performance optimization, and distributed systems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Leadership and Collaboration&lt;/strong&gt;: Be prepared to discuss your experience in leading technical projects, managing teams, and fostering collaboration. Questions may focus on your approach to decision-making, conflict resolution, mentoring, and how you enable a productive and inclusive work environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Problem-Solving and Critical Thinking&lt;/strong&gt;: Employers often assess a staff engineer's ability to solve complex problems, think analytically, and make strategic decisions. You may encounter scenario-based questions where you are asked to devise solutions for challenging technical or organizational issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Communication and Influence&lt;/strong&gt;: Effective communication is crucial for staff engineers. Expect questions that evaluate your ability to articulate technical concepts to both technical and non-technical stakeholders. You may be asked about instances where you successfully influenced technical decisions or resolved conflicts through effective communication.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Must-Know Skills for Staff Engineers
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Technical Proficiency&lt;/strong&gt;: A staff engineer should have a deep understanding of the company's tech stack and possess expertise in relevant programming languages, frameworks, and tools. Stay updated with industry trends and emerging technologies to drive innovation and make informed technical decisions. Knowledge on programming, cloud computing, system design, SQL databases, and related topics would be valuable in this role.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Leadership and Mentorship&lt;/strong&gt;: Staff engineers are expected to provide guidance and mentorship to junior team members. Develop strong leadership skills, including the ability to motivate, inspire, and support your colleagues. Cultivate a collaborative environment that fosters continuous learning and growth.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Systems Thinking&lt;/strong&gt;: As a staff engineer, you must have a holistic understanding of software systems. Focus on developing your ability to analyze complex systems, identify bottlenecks, and propose scalable and efficient solutions. This includes considering factors such as performance, security, reliability, and maintainability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Communication and Collaboration&lt;/strong&gt;: Effective communication is paramount for staff engineers. Hone your ability to clearly convey complex technical concepts to different audiences, both verbally and in written form. Foster collaborative relationships with stakeholders across teams to drive alignment and achieve project objectives.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Adapting to the Evolving Tech Landscape
&lt;/h2&gt;

&lt;p&gt;To thrive as a staff engineer in today's dynamic tech landscape, it's essential to embrace continuous learning and adaptability. Stay updated with new technologies, industry best practices, and emerging trends. Cultivate a growth mindset and seek opportunities to expand your skill set through training, attending conferences, participating in open-source projects, and engaging with the developer community.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Job Post for a Staff Engineer
&lt;/h2&gt;

&lt;p&gt;Job Title: Staff Engineer at Dummy.co&lt;/p&gt;

&lt;p&gt;Responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provide technical leadership in software development projects.&lt;/li&gt;
&lt;li&gt;Mentor and guide junior engineers, fostering a collaborative and inclusive work environment.&lt;/li&gt;
&lt;li&gt;Collaborate with cross-functional teams to define architecture, scalability, and performance of software systems.&lt;/li&gt;
&lt;li&gt;Perform code reviews, identify areas for improvement, and ensure high-quality code standards.&lt;/li&gt;
&lt;li&gt;Analyze complex systems, identify bottlenecks, and propose scalable and efficient solutions.&lt;/li&gt;
&lt;li&gt;Stay up-to-date with industry trends and emerging technologies relevant to the tech stack.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bachelor's or Master's degree in Computer Science or related field.&lt;/li&gt;
&lt;li&gt;Strong experience in software development with a focus on Ruby on Rails.&lt;/li&gt;
&lt;li&gt;Proficiency in cloud computing platforms, such as AWS or Azure.&lt;/li&gt;
&lt;li&gt;Solid understanding of system design principles and distributed systems.&lt;/li&gt;
&lt;li&gt;In-depth knowledge of SQL databases and database performance optimization.&lt;/li&gt;
&lt;li&gt;Excellent problem-solving and critical-thinking abilities.&lt;/li&gt;
&lt;li&gt;Proven experience in leading technical projects and mentoring junior engineers.&lt;/li&gt;
&lt;li&gt;Exceptional communication and collaboration skills.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sample Interview at Dummy.co
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Question 1:&lt;/strong&gt; Can you explain the differences between a monolithic architecture and a microservices architecture? What are the advantages and disadvantages of each?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer:&lt;/strong&gt; In a monolithic architecture, the entire application is built as a single, self-contained unit. It is typically easier to develop and test but can become challenging to maintain and scale as the application grows. Microservices architecture, on the other hand, decomposes the application into smaller, independent services that can be developed and deployed separately. It offers benefits like scalability, independent deployment, and fault isolation but introduces complexities in managing inter-service communication and data consistency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question 2:&lt;/strong&gt; How would you approach improving the performance of a slow SQL query in a large database?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer:&lt;/strong&gt; To improve the performance of a slow SQL query, I would start by analyzing the query execution plan using database query profiling tools. This would help identify the bottlenecks, such as missing or inefficient indexes, excessive joins, or suboptimal query structure. Based on the analysis, I would consider strategies like optimizing the query, adding appropriate indexes, denormalizing data, or caching results. It's crucial to strike a balance between query performance and the overall database design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question 3:&lt;/strong&gt; How do you handle conflicts and disagreements within a technical team during a project?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer:&lt;/strong&gt; Conflict resolution is an essential skill for a staff engineer. When conflicts arise within a technical team, I believe in fostering open communication and active listening to understand each person's perspective. I would encourage a collaborative environment where team members can express their ideas and concerns. If a resolution cannot be reached through discussion, I would facilitate a constructive compromise or involve relevant stakeholders for mediation. It's crucial to prioritize the project's objectives and maintain a respectful and inclusive work environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question 4:&lt;/strong&gt; How would you approach mentoring and guiding junior engineers on the team?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer:&lt;/strong&gt; Mentoring and guiding junior engineers is an integral part of the staff engineer role. I would start by understanding their individual strengths, weaknesses, and career goals. I would create a safe space for them to ask questions and seek guidance. Regular one-on-one meetings would provide an opportunity to discuss their progress, offer constructive feedback, and set realistic goals. I would encourage them to take ownership of their projects while providing support and resources for their growth. Celebrating their achievements and fostering a culture of continuous learning would be paramount.&lt;/p&gt;

&lt;p&gt;These sample interview questions and answers are meant to provide a starting point for your preparation. Tailor your responses based on your own experiences and knowledge, and use them as a guide to showcase your technical expertise, problem-solving skills, and leadership abilities during the staff engineer interview.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Learning Path
&lt;/h2&gt;

&lt;p&gt;To sharpen the necessary skills for the staff engineer role, consider the following learning path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Strengthen your programming Skills: Deepen your knowledge of the required programming language by working on real-world projects, exploring advanced topics, and leveraging resources like online tutorials, documentation, and books focused on the language/framework.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gain Expertise in Cloud Computing: Familiarize yourself with cloud computing platforms such as AWS or Azure. Take online courses or certifications to understand their key services, deployment models, and scalability options.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Master System Design Principles: Study system design concepts and patterns to develop the ability to design scalable, fault-tolerant, and high-performance systems. Practice designing and architecting complex systems, considering factors like scalability, security, and maintainability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dive into SQL/noSQL Databases: Learn SQL/noSQL database management and optimization techniques. Gain proficiency in writing efficient queries, indexing, and optimizing database performance. Explore different database management systems and their use cases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enhance Leadership and Collaboration Skills: Invest in developing your leadership and collaboration abilities. Attend leadership workshops, participate in team-building activities, and seek opportunities to mentor and guide junior engineers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stay Updated with Industry Trends: Engage with the developer community, follow influential tech blogs, and attend conferences or webinars to stay current with emerging technologies, industry best practices, and trends in software development.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Remember, this learning path is not exhaustive but provides a starting point. Continuously seek opportunities for growth, practice hands-on coding, and seek feedback from experienced professionals to refine your skills and knowledge.&lt;/p&gt;

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

&lt;p&gt;Becoming a staff engineer requires a combination of technical expertise, leadership skills, and a deep understanding of software engineering principles. When preparing for a staff engineer interview, be ready to showcase your technical depth, problem-solving abilities, leadership experience, and relevant knowledge in areas like programming, cloud computing, system design, and SQL/noSQL databases. By following a learning path tailored to the role's requirements, you can sharpen your skills and position yourself for success as a staff engineer in today's dynamic tech landscape.&lt;/p&gt;

&lt;p&gt;If you are aspiring to become a Staff Engineer and are seeking mentorship to accelerate your professional growth, I highly recommend reading my previous post on &lt;a href="https://dev.to/victorhazbun/the-power-of-mentorship-why-having-a-mentor-is-essential-for-professional-growth-4j61"&gt;The Power of Mentorship: Why Having a Mentor is Essential for Professional Growth&lt;/a&gt; first.&lt;/p&gt;

&lt;p&gt;For personalized guidance and support on your Staff Engineer journey, feel free to contact me at &lt;a href="https://www.codementor.io/@victor_hazbun"&gt;codementor.io&lt;/a&gt;. As an experienced software developer and mentor, I am here to assist you in reaching your full potential as a Staff Engineer. Let's work together and help you achieve success in the software industry.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Power of Mentorship: Why Having a Mentor is Essential for Professional Growth</title>
      <dc:creator>Victor Hazbun</dc:creator>
      <pubDate>Fri, 23 Jun 2023 00:10:23 +0000</pubDate>
      <link>https://dev.to/victorhazbun/the-power-of-mentorship-why-having-a-mentor-is-essential-for-professional-growth-4j61</link>
      <guid>https://dev.to/victorhazbun/the-power-of-mentorship-why-having-a-mentor-is-essential-for-professional-growth-4j61</guid>
      <description>&lt;h2&gt;
  
  
  Introduction:
&lt;/h2&gt;

&lt;p&gt;In the world of software development and tech, continuous learning and growth are paramount. The rapidly evolving landscape demands that professionals stay ahead of the curve, constantly honing their skills and expanding their knowledge. In this pursuit, having a mentor can be an invaluable asset. A mentor provides guidance, support, and expertise that can significantly accelerate your professional journey. In this article, we will explore the importance of having a mentor and how their influence can shape your success as a developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gaining Insight and Wisdom:
&lt;/h2&gt;

&lt;p&gt;One of the primary benefits of having a mentor is gaining access to their wealth of experience and knowledge. A mentor has already walked the path you're embarking on and can offer insights into the challenges, opportunities, and pitfalls you may encounter. Their guidance can help you navigate complex technical problems, improve your decision-making abilities, and avoid common mistakes. Learning from their wisdom can save you valuable time and effort in your career development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expanding Your Network:
&lt;/h2&gt;

&lt;p&gt;A mentor serves as a valuable connection to a broader professional network. They can introduce you to industry experts, influential figures, and potential collaborators. Through their network, you can tap into opportunities that might otherwise be out of reach. Mentors can also provide recommendations and referrals, boosting your credibility and opening doors to exciting career prospects. Building a strong network is crucial for career growth, and a mentor can be a catalyst in expanding your connections.&lt;/p&gt;

&lt;h2&gt;
  
  
  Personalized Guidance and Support:
&lt;/h2&gt;

&lt;p&gt;A mentor understands your strengths, weaknesses, and aspirations. They provide personalized guidance tailored to your specific needs, enabling you to grow in the areas that matter most to you. Whether it's technical skills, project management, or career advancement, a mentor can help you set goals and devise strategies to achieve them. They offer support and encouragement, helping you overcome self-doubt and challenges along the way. Having someone invested in your success can be incredibly motivating and empowering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accelerated Learning Curve:
&lt;/h2&gt;

&lt;p&gt;Learning through trial and error is a valid approach, but it can be time-consuming and inefficient. A mentor can expedite your learning process by sharing their own experiences, offering real-world examples, and providing constructive feedback on your work. They can suggest learning resources, recommend best practices, and challenge you to think critically. With a mentor, you can avoid unnecessary detours and make progress at a faster pace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Confidence and Self-Efficacy:
&lt;/h2&gt;

&lt;p&gt;Entering the tech industry or taking on new responsibilities can be intimidating. A mentor acts as a trusted advisor, boosting your confidence and self-belief. They provide encouragement, acknowledge your achievements, and help you overcome imposter syndrome. By witnessing their own accomplishments and hearing their stories of triumph over adversity, you gain the confidence to tackle challenges head-on and embrace opportunities for growth.&lt;/p&gt;

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

&lt;p&gt;Having a mentor is a vital component of professional growth and development. Their guidance, expertise, and support can propel you towards success in your software development journey. Seek out a mentor within your organization, through networking events, or online platforms like &lt;a href="//codementor.io"&gt;codementor.io&lt;/a&gt;. Codementor.io provides a platform where experienced software developers like &lt;a href="https://www.codementor.io/@victor_hazbun"&gt;Victor Hazbun&lt;/a&gt; offer mentorship services. &lt;/p&gt;

&lt;p&gt;With their expertise, you can unlock your full programming potential and accelerate your growth in the field. Embrace the transformative power of mentorship and take the leap towards achieving your professional goals. Remember, even the most accomplished professionals had mentors who played a crucial role in their rise to greatness.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Mongoid query nested embed document through belongs to and embeds many</title>
      <dc:creator>Victor Hazbun</dc:creator>
      <pubDate>Tue, 27 Apr 2021 19:30:25 +0000</pubDate>
      <link>https://dev.to/victorhazbun/mongoid-query-nested-embed-document-through-belongs-to-and-embeds-many-3p15</link>
      <guid>https://dev.to/victorhazbun/mongoid-query-nested-embed-document-through-belongs-to-and-embeds-many-3p15</guid>
      <description>&lt;p&gt;Given the following documents, I'm trying to find a log document given a token ID.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Log&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;

  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;

  &lt;span class="n"&gt;embeds_many&lt;/span&gt; &lt;span class="ss"&gt;:tokens&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Token&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I tried &lt;code&gt;Log.where('user.tokens._id': BSON::ObjectId('123ABC')&lt;/code&gt; with no luck. Any ideas?&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Learn recursion with Tower of Hanoi game</title>
      <dc:creator>Victor Hazbun</dc:creator>
      <pubDate>Sat, 23 May 2020 21:54:57 +0000</pubDate>
      <link>https://dev.to/victorhazbun/teach-you-recursion-with-hanoi-game-2jnc</link>
      <guid>https://dev.to/victorhazbun/teach-you-recursion-with-hanoi-game-2jnc</guid>
      <description>&lt;p&gt;The objective of the puzzle is to move the entire stack to another rod, obeying the following simple rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only one disk can be moved at a time.&lt;/li&gt;
&lt;li&gt;Each move consists of taking the upper disk from one of the stacks and placing it on top of another stack or on an empty rod.&lt;/li&gt;
&lt;li&gt;No larger disk may be placed on top of a smaller disk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;hanoy.rb&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hanoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;auxiliar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;hanoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;auxiliar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Moved disc from &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; to &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;hanoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;auxiliar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;hanoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'B'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'C'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tower of Hanoi
&lt;/h3&gt;

&lt;p&gt;A Hanoi Tower looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;number&lt;/code&gt; (number of disks)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;origin&lt;/code&gt; (A)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;auxiliar&lt;/code&gt; (B)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;destination&lt;/code&gt; (C)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make this example easier to understand, let's pretend our Hanoi Tower has 4 disks, and columns A, B, C.&lt;/p&gt;

&lt;h3&gt;
  
  
   Our algorithm
&lt;/h3&gt;

&lt;p&gt;The idea is to write a function that calls itself until the puzzle is solved.&lt;/p&gt;

&lt;h3&gt;
  
  
   But how?
&lt;/h3&gt;

&lt;p&gt;First, determine when to stop the function execution. It must stop when all the disks has been moved to the column C. Our program continues executing &lt;code&gt;unless&lt;/code&gt; the disks is equal to zero. Code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;unless number == 0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Our next mission is to actually figure out the puzzle (moving all the disks from "A" to "C").&lt;/p&gt;

&lt;p&gt;Second, we will have to decrement the amount of disks when calling &lt;code&gt;hanoi&lt;/code&gt; and pass along the &lt;code&gt;origin&lt;/code&gt;, &lt;code&gt;destination&lt;/code&gt; and &lt;code&gt;auxiliar&lt;/code&gt;. Code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hanoi(number - 1, origin, destination, auxiliar)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Basically, we are calling the same function (&lt;code&gt;hanoi&lt;/code&gt;) but using &lt;strong&gt;new&lt;/strong&gt; arguments, allowing us to solve the puzzle.&lt;/p&gt;

&lt;p&gt;Third, we also want to print whenever the disks are moving from one place to another. Code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;puts "Moved disc from #{origin} to #{destination}"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally, we will call &lt;code&gt;hanoi&lt;/code&gt; again because we want to move the disks. Code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hanoi(number - 1, auxiliar, origin, destination)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Notice, the arguments are the same but in different order, again allowing us to solve the puzzle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;I do not want you to understand the math behind the Hanoi Tower algorithm, just want you to realize that calling function &lt;code&gt;hanoi&lt;/code&gt; in the same function &lt;code&gt;hanoi&lt;/code&gt; is recursion.&lt;/p&gt;

&lt;p&gt;It is important to understand that a recursive function &lt;strong&gt;needs&lt;/strong&gt; a mechanism to stop executing, otherwise it will run forever or in the worst case it will cause errors.&lt;/p&gt;

&lt;p&gt;Maybe you noticed our &lt;code&gt;hanoi&lt;/code&gt; function did not mutated objects because it calls itself with new arguments rather than using existing objects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DvWl5e04--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xvwgezs7h99yz82mrbqn.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DvWl5e04--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xvwgezs7h99yz82mrbqn.jpeg" alt="Recursion" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>recursion</category>
    </item>
    <item>
      <title>Creating an Alfred workflow with Ruby</title>
      <dc:creator>Victor Hazbun</dc:creator>
      <pubDate>Tue, 28 Apr 2020 07:19:51 +0000</pubDate>
      <link>https://dev.to/victorhazbun/creating-an-alfred-workflow-with-ruby-54e8</link>
      <guid>https://dev.to/victorhazbun/creating-an-alfred-workflow-with-ruby-54e8</guid>
      <description>&lt;p&gt;If you love &lt;a href="https://www.alfredapp.com/"&gt;Alfred&lt;/a&gt; like me, you will enjoy this tutorial, I will teach you how to build a custom workflow to short URLs using &lt;a href="https://bitly.com/"&gt;https://bitly.com/&lt;/a&gt; (Free account).&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a Bitly account
&lt;/h2&gt;

&lt;p&gt;First, you will need to signup for a &lt;a href="https://bitly.com/a/sign_up"&gt;Bitly account&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then create a generic access token (You will need it later). &lt;a href="https://support.bitly.com/hc/en-us/articles/230647907-How-to-create-an-OAuth-access-token-for-the-Bitly-API"&gt;Here are the instructions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Alfred workflow
&lt;/h2&gt;

&lt;p&gt;This is the code for the workflow, let's talk about it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'net/http'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'uri'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'json'&lt;/span&gt;

&lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://api-ssl.bitly.com/v4/shorten'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Set parameters&lt;/span&gt;
&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;long_url:  &lt;/span&gt;&lt;span class="no"&gt;ARGV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# Set headers&lt;/span&gt;
&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s1"&gt;'Host'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'api-ssl.bitly.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'Authorization'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Bearer &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'BITLY_ACCESS_TOKEN'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'application/json'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'Accept'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'application/json'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# Create the HTTP objects&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Force SSL request&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use_ssl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="c1"&gt;# Build POST request&lt;/span&gt;
&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request_uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Set request body (As JSON)&lt;/span&gt;
&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_json&lt;/span&gt;
&lt;span class="c1"&gt;# Send the request&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Get link from response&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s1"&gt;'link'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you might know, you can build your own workflows using Ruby and other languages, even bash.&lt;/p&gt;

&lt;p&gt;I used three Ruby native dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Net::HTTP to make HTTP requests to Bitly&lt;/li&gt;
&lt;li&gt;URI to build URLs&lt;/li&gt;
&lt;li&gt;JSON to parse the response body and be able to extract the shorten link&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;parameters&lt;/code&gt; I'm sending to Bitly come from the user input via Alfred, so in order to access the first and only argument, we have to use &lt;code&gt;ARGV[0]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the &lt;code&gt;headers&lt;/code&gt; it is mandatory to set the &lt;code&gt;Authorization Bearer&lt;/code&gt; since this is how Bitly knows who is trying to shorten the link. We read the access token from the environment variables. &lt;/p&gt;

&lt;p&gt;Alfred will ask for the token when you download the workflow.&lt;/p&gt;

&lt;p&gt;We also need to make the request of type &lt;code&gt;https&lt;/code&gt; since they Bitly API requires a secure protocol. We not only need to use &lt;code&gt;https://&lt;/code&gt; in the request URL, we also have to tell &lt;code&gt;http.use_ssl&lt;/code&gt;, otherwise it won't work.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;request.body&lt;/code&gt; has to be set up as &lt;code&gt;JSON&lt;/code&gt; as Bitly documentation indicates, so we convert the parameters to &lt;code&gt;JSON&lt;/code&gt; like this &lt;code&gt;params.to_json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally we have to parse the JSON response using &lt;code&gt;JSON.parse(response.body)&lt;/code&gt;, which returns a hash with keys and values.&lt;/p&gt;

&lt;p&gt;The key we need is the &lt;code&gt;link&lt;/code&gt;, for Alfred workflows, you actually need to &lt;code&gt;puts&lt;/code&gt; the output, if you don't do this the next script won't contain the expected input.&lt;/p&gt;

&lt;h2&gt;
  
  
  Download the Alfred workflow
&lt;/h2&gt;

&lt;p&gt;You can directly download the workflow from the &lt;a href="https://github.com/bonsai-labs-io/alfredapp-bitly-shorten/raw/master/bitly-shorten.alfredworkflow"&gt;Github repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE: You will be asked to introduce your personal access token.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;I had a really fun time coding this workflow. It was a bit tricky initially since there is not too many examples out there, however the documentation was good enough.&lt;/p&gt;

&lt;p&gt;If you liked the workflow please consider giving it a ⭐ on &lt;a href="https://github.com/bonsai-labs-io/alfredapp-bitly-shorten"&gt;Github&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Docker for Rails Development</title>
      <dc:creator>Victor Hazbun</dc:creator>
      <pubDate>Mon, 24 Feb 2020 04:27:11 +0000</pubDate>
      <link>https://dev.to/victorhazbun/docker-for-rails-development-3pa3</link>
      <guid>https://dev.to/victorhazbun/docker-for-rails-development-3pa3</guid>
      <description>&lt;p&gt;Developing Ruby on Rails applications in large teams could be frustrating because team members use different operative systems, languages, timezones and more.&lt;/p&gt;

&lt;p&gt;Docker is a great tool for software development since it synchronises your team with the same setup for everyone who collaborates in your project. That's fantastic!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Your team will have an stable development environment&lt;/li&gt;
&lt;li&gt;Development it's a mirror of Production&lt;/li&gt;
&lt;li&gt;No bugs caused by environment&lt;/li&gt;
&lt;li&gt;Because Windows XD&lt;/li&gt;
&lt;li&gt;New team members will love it!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How?
&lt;/h2&gt;

&lt;p&gt;Let's break this into multiple sections, we will cover everthing needed to build badass Rails applications in Dockerized environments. &lt;/p&gt;

&lt;h3&gt;
  
  
  Rails in a Docker Container
&lt;/h3&gt;

&lt;p&gt;Running rails in a Docker Container is pretty straightforward, let's begin by creating a Rails application and then configure a custom Docker Image so we can run the Rails application from there.&lt;/p&gt;

&lt;h4&gt;
  
  
  Rails application
&lt;/h4&gt;

&lt;p&gt;Let's start by creating a new Rails application.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm assuming you have Rails 5.2 installed if not please follow one of this &lt;a href="https://gorails.com/setup"&gt;Guides&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;$ rails new myapp --skip-test --skip-bundle&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Docker Image
&lt;/h4&gt;

&lt;p&gt;Now that we have a Rails application, let's create a &lt;strong&gt;simple&lt;/strong&gt; Dockerfile in our Rails application &lt;strong&gt;root&lt;/strong&gt;.&lt;br&gt;
This will help us running our Rails application in Docker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM ruby:2.5
RUN apt-get update -yqq
RUN apt-get install -yqq --no-install-recommends nodejs
COPY . /usr/src/app/
COPY Gemfile* /usr/src/app/
WORKDIR /usr/src/app
RUN bundle install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Line &lt;strong&gt;#1&lt;/strong&gt; Sets Ruby 2.5 as the Ruby version for our custom Docker Image&lt;br&gt;
Line &lt;strong&gt;#2&lt;/strong&gt; Update the Package list&lt;br&gt;
Line &lt;strong&gt;#3&lt;/strong&gt; Install Node.js (needed for the Asset Pipeline)&lt;br&gt;
Line &lt;strong&gt;#4&lt;/strong&gt; Copy our Rails application files from our local directory into the container&lt;br&gt;
Line &lt;strong&gt;#5&lt;/strong&gt; Gemfile caching &lt;br&gt;
Line &lt;strong&gt;#6&lt;/strong&gt; Sets the working directory for the Docker Image&lt;br&gt;
Line &lt;strong&gt;#7&lt;/strong&gt; Installs the Ruby gems&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please make sure you are in the Rails application &lt;strong&gt;root&lt;/strong&gt; directory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;$ docker build .&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
Removing intermediate container 487d39dad5ff
 ---&amp;gt; c2183f884d23
Successfully built c2183f884d23
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Take a look at the &lt;strong&gt;custom image identifier (c2183f884d23)&lt;/strong&gt; because we will use it next. &lt;strong&gt;Your identifier will be different of course&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We should now be able to list all of our available Docker Images.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker images&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REPOSITORY          TAG                  IMAGE ID            CREATED              SIZE
&amp;lt;none&amp;gt;              &amp;lt;none&amp;gt;               c2183f884d23        About a minute ago   381MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see the custom Docker Image is available.&lt;/p&gt;

&lt;p&gt;Now that we have created our own Docker Image, it's time to run the application.&lt;/p&gt;

&lt;h4&gt;
  
  
  Running Rails
&lt;/h4&gt;

&lt;p&gt;To get the application up and running we will execute the following command which basically says "start a containter out of our image (c2183f884d23) and then run rails s -b 0.0.0.0 inside it". The -b tells our Rails server to bind all IP addresses not just localhost. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker run -p 3000:3000 c2183f884d23 rails s -b 0.0.0.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The Rails server boots up,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=&amp;gt; Booting Puma
=&amp;gt; Rails 5.2.0 application starting in development
=&amp;gt; Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.11.4 (ruby 2.5.1-p57), codename: Love Song
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;code&gt;localhost:3000&lt;/code&gt; and you should see Rails welcome page. &lt;strong&gt;Yay! You’re on Rails!&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improve the Docker Image
&lt;/h3&gt;

&lt;p&gt;Using the custom image ID as a reference to start our Rails application is not cool at all because it is not easy to remember this number, let's &lt;code&gt;tag&lt;/code&gt; this image so it is easy to remember:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker tag c2183f884d23 app&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If we list our Docker images:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REPOSITORY    TAG    IMAGE ID    CREATED    SIZE
app           latest      c2183f884d23        5 days ago          1.03GB

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

&lt;/div&gt;



&lt;p&gt;You can use tags to version your custom Docker Image. All about &lt;strong&gt;Docker tag command&lt;/strong&gt; &lt;a href="https://docs.docker.com/engine/reference/commandline/tag/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With the new Docker Image name &lt;strong&gt;app&lt;/strong&gt; we can make run the Rails application easily.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker run -p 3000:3000 app rails s -b 0.0.0.0&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Notice we are no longer using the Docker Image ID but instead the tag name.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now let's add a default command to out image, using CMD:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM ruby:2.5
RUN apt-get update -yqq
RUN apt-get install -yqq --no-install-recommends nodejs
COPY . /usr/src/app/
COPY Gemfile* /usr/src/app/
WORKDIR /usr/src/app
RUN bundle install
CMD ["rails", "s", "-b", "0.0.0.0"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are some files we can ignore in our Docker Image using &lt;code&gt;.dockerignore&lt;/code&gt; and feel free to add more here as needed:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;.dockerignore&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.git
.gitignore
log/*
tmp/*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, let's rebuild the Docker Image with the new CMD instruction:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker build -t app .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Start the Rails application without the &lt;code&gt;rails s -b 0.0.0.0&lt;/code&gt; using the new tag name &lt;code&gt;app&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker run -p 3000:3000 app&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So far we have covered &lt;code&gt;Dockerfile&lt;/code&gt;, &lt;code&gt;.dockerignore&lt;/code&gt; and &lt;code&gt;docker tag&lt;/code&gt;.&lt;br&gt;
Next we will switch to Docker Compose!&lt;/p&gt;
&lt;h3&gt;
  
  
  Rocking with Docker Compose
&lt;/h3&gt;

&lt;p&gt;With Docker Composeyou describe each of your application services.&lt;/p&gt;

&lt;p&gt;Introducing &lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/usr/src/app
    command: bash -c "rm -f tmp/pids/server.pid &amp;amp;&amp;amp; bundle exec rails s -p 3000 -b '0.0.0.0'"

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

&lt;/div&gt;



&lt;p&gt;We will remove the &lt;code&gt;CMD ["rails", "s", "-b", "0.0.0.0"]&lt;/code&gt; line from our &lt;code&gt;Dockerfile&lt;/code&gt; since we are running the same command from the &lt;code&gt;docker-compose.yml&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This step is very important since if we don't do it we could get this error:&lt;/strong&gt; &lt;br&gt;
&lt;code&gt;A server is already running. Check /usr/src/app/tmp/pids/server.pid&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM ruby:2.5
RUN apt-get update -yqq
RUN apt-get install -yqq --no-install-recommends nodejs
COPY . /usr/src/app/
COPY Gemfile* /usr/src/app/
WORKDIR /usr/src/app
RUN bundle install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's build the Docker Image with Docker Compose:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose up --build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Our Rails application is up and running, thanks to Docker Compose, YAY!&lt;/p&gt;

&lt;h4&gt;
  
  
  Docker Compose useful commands
&lt;/h4&gt;

&lt;p&gt;This Docker Compose commands will help you during development and you will use them everyday!&lt;/p&gt;

&lt;p&gt;Builds, (re)creates, starts, and attaches to containers for a service: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose up&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Lists containers:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose ps&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Managing containers lifecycle:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose [start|stop|kill|restart|pause|unpause|rm] SERVICE&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Displays log output from services.:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose logs [SERVICE...]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Run arbitrary commands in your services:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose exec SERVICE COMMAND&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Runs a one-time command against a service.:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose run SERVICE [COMMAND]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Rebuilding a Docker Image:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose build [SERVICE...]&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;We learned how to use Docker for Rails development, we covered some key concepts like: Dockerfile and Docker Compose.&lt;/p&gt;

&lt;p&gt;Now you should be ready to start developing Rails applications in a Dockerized environment!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>rails</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Best practices: Avoid race conditions 🚘💥🚗😰</title>
      <dc:creator>Victor Hazbun</dc:creator>
      <pubDate>Mon, 24 Feb 2020 04:01:42 +0000</pubDate>
      <link>https://dev.to/victorhazbun/best-practices-avoid-race-conditions-i31</link>
      <guid>https://dev.to/victorhazbun/best-practices-avoid-race-conditions-i31</guid>
      <description>&lt;p&gt;Here are some scenarios and tips to combat race conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Race Conditions
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A computer program is like a horse race. The computer program does several things at the same time, similarly to how several horses run at the same time in a horse race. Each horse represents what is usually called a thread of execution. That way, one such thread may handle network communication, another one may be responsible for redrawing the user interface. In the case of a race condition, the application works properly if a given horse wins the race. For example, the application may work if horse number five wins, but it will crash if any other horse wins the race. Source &lt;a href="https://simple.wikipedia.org/wiki/Race_condition"&gt;https://simple.wikipedia.org/wiki/Race_condition&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Real Life Example: Many users booking the same room at the same time
&lt;/h2&gt;

&lt;p&gt;Imagine you have a booking app, let's pretend you a have &lt;code&gt;Room&lt;/code&gt; model. The &lt;code&gt;rooms&lt;/code&gt; table stores the &lt;code&gt;user_id&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Room&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;assign_to_user!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks fine, right? Nope, if two users make the same reservation at the same time you are probably going to run into serious problems. Here is why..&lt;/p&gt;

&lt;p&gt;The first user who submitted the form will &lt;strong&gt;open&lt;/strong&gt; a database transaction and the second user who submitted a millisecond after opened another database transaction. Now we have two opened database transactions, the second transaction has overridden the first. That means, the first user has paid for the room but the second got it, LOL. Just imagine the two hosts discussing in the lobby, you will hear something like this: "No, I booked the room!".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imgflip.com/i/3q3dok"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aCXK0lO1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgflip.com/3q3dok.jpg" title="made at imgflip.com" width="668" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To prevent this you can lock the Room table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Room&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;assign_to_user!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# This block is called within a transaction,&lt;/span&gt;
    &lt;span class="c1"&gt;# room is already locked.&lt;/span&gt;
    &lt;span class="n"&gt;with_lock&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;By locking the table, even if two requests happened at the same time the record won't be updatable UNTIL the DB lock is released, this is called &lt;strong&gt;"Pessimistic locking"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;Pessimistic locking&lt;/strong&gt; whenever you know this kind of things are most likely to happen in your app. See full documentation and examples here: &lt;a href="https://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html"&gt;https://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imgflip.com/i/3q3hm3"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F7RC50AZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgflip.com/3q3hm3.jpg" title="made at imgflip.com" width="620" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Scenarios
&lt;/h2&gt;

&lt;p&gt;Here is a small list of cases where you should implement database locking to avoid unwanted race conditions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Money transactions&lt;/li&gt;
&lt;li&gt;Booking flights&lt;/li&gt;
&lt;li&gt;Making reservations&lt;/li&gt;
&lt;li&gt;Cryptocurrency transactions&lt;/li&gt;
&lt;li&gt;Gambling&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion &amp;amp; Next Steps
&lt;/h2&gt;

&lt;p&gt;Think about which parts of your application deserve database locking, hopefully you can patch those areas so all your users have a great experience.&lt;/p&gt;

&lt;p&gt;Please let me know if you have questions or want to chat about other kinds of database locking mechanisms like &lt;strong&gt;Optimistic Locking&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>security</category>
      <category>ruby</category>
      <category>database</category>
    </item>
  </channel>
</rss>
