<?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: Horia Constantin</title>
    <description>The latest articles on DEV Community by Horia Constantin (@treaz).</description>
    <link>https://dev.to/treaz</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%2F250386%2Ff766c54e-52b5-4c58-8e96-8a15f51c81df.jpg</url>
      <title>DEV Community: Horia Constantin</title>
      <link>https://dev.to/treaz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/treaz"/>
    <language>en</language>
    <item>
      <title>Book summary: SQL Antipatterns</title>
      <dc:creator>Horia Constantin</dc:creator>
      <pubDate>Tue, 06 Sep 2022 08:05:20 +0000</pubDate>
      <link>https://dev.to/treaz/book-summary-sql-antipatterns-1a5l</link>
      <guid>https://dev.to/treaz/book-summary-sql-antipatterns-1a5l</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HnFESAxf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dm82jjquu6dg8ve0tb94.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HnFESAxf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dm82jjquu6dg8ve0tb94.jpeg" alt="Image description" width="417" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was recently going through my notes of &lt;a href="https://bookwyrm.social/book/547394/s/sql-antipatterns"&gt;SQL Antipatterns&lt;/a&gt; and was shocked to realize how actual this book still is. I'm going to share my summary of the book. I guarantee you'll find at least a few antipatterns in your current database design.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logical Database Design Antipatterns
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Jaywalking
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; Storing a delimiter-separated value string in a varchar field instead of creating an intersection table. It might be easier, but it makes queries harder. And updating the field is also a pain. And your field might have all kinds of consistency errors (for instance, ids are normally numbers, but now you have a varchar. The DB cannot ensure consistency for you).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; when the data you're storing in the varchar is not needed to be used in the queries (gets displayed as-is).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; create an intersection table.&lt;/p&gt;

&lt;h4&gt;
  
  
  Naive trees
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; When you have multiple level parent -&amp;gt; child relationship and you represent it using an Adjacency list (you have a parent id in every row). It becomes impossible to get the whole tree in one query (because by default you can only get the next level).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; when you're certain that you will only have 1 level of queries. The alternatives are harder to implement.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Path Enumeration (storing the string of ancestors as an attribute of each node, just like the filesystem directories). Drawback: limitations of the Jaywalking antipattern.&lt;/li&gt;
&lt;li&gt;Nested Sets (add to each node nsleft and nsright: the nsleftnumber is less than the numbers of all the node’s children, whereas the nsright number is greater than the numbers of all the node’s children. These numbers have no relation to the id values). General tree reading becomes easy, but editing the tree becomes hard because all the nsleft and nsright need to be reprocessed.&lt;/li&gt;
&lt;li&gt;Closure Table: an extra table that holds all the relations between ancestors and descendants (including node indirect relationships and a reference to itself). The only drawback is the extra table size for big trees. But other operations are very easy to implement.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Reference:&lt;/strong&gt; "Joe Celko’s Trees and Hierarchies in SQL for Smarties"&lt;/p&gt;

&lt;h4&gt;
  
  
  ID required
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; Using a primary key that is not the appropriate primary key for this table (e.g., there is a natural primary key like social security number or there could be a compound key in there). If a table has a unique column then, most probably that could be the primary key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; declare a primary key on a field that is easy to index and makes the most sense for that particular table&lt;/p&gt;

&lt;h4&gt;
  
  
  Keyless entry
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; when you don't use the constraints offered by the DB (especially foreign keys).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; never, unless your DB doesn't support it&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; always declare constraints&lt;/p&gt;

&lt;h4&gt;
  
  
  Mixing data with metadata
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; For example, by appending the year onto the base table name, we’ve combined a data value with a metadata identifier.&lt;/p&gt;

&lt;p&gt;This is the reverse of mixing data with metadata from the Entity-Attribute-Value and Polymorphic Associations antipatterns. In those cases, we stored metadata identifiers (a column name and table name) as string data.&lt;/p&gt;

&lt;p&gt;In Multicolumn Attributes and Metadata Tribbles, we’re making a data value into a column name or a table name. If you use any of these antipatterns, you create more problems than you solve.&lt;/p&gt;

&lt;h4&gt;
  
  
  Entity-value-attribute
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; when you have a table with the columns: entity_id, attribute_name, attribute_value&lt;/p&gt;

&lt;p&gt;It appears when you have OOP inheritance and the children have various fields. If you use it, you lose referential integrity and data type validation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; you shouldn't use this in a relational DB. Just use a non-relational DB or one of the solutions below.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Single table inheritance: one table with all the attributes of the children (it's going to be a sparse table&lt;/li&gt;
&lt;li&gt;Concrete table inheritance: completely independent tables for each subtype&lt;/li&gt;
&lt;li&gt;Class table inheritance (one table for the parent properties and tables with the child-specific properties)&lt;/li&gt;
&lt;li&gt;Semistructured data (one table with the parent properties and an extra blob field with the child-specific attributes). Disadvantages similar to the Entity-value-attribute.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Polymorphic associations
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; When you need to reference from a single table, multiple parent tables (e.g., comments to features/bugs). You're using the pattern if you store in a column the name of your type of parent table.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Create intersection tables&lt;/li&gt;
&lt;li&gt;Create a common super table (with only ids) and reference that with your new table. The children will reference the super table (ex: comments references issues; bugs references issues, features references issues)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Multicolumn attributes
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; When an entity's attribute can have multiple values, you create multiple columns called attribute1, attribute2, etc.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Create a dependent table (a table that references the initial table by id and has the attribute as the other column)&lt;/li&gt;
&lt;li&gt;Store each value with the same meaning in a single column.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Metadata tribbles
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; When to support scalability and performance, you clone tables or new columns to support new partitions: ex: sales_2013, sales_2014, etc. (tables of the same schema with different entities). Basically, in your database, you will have a table per "some data value".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; when splitting the database sensibly makes database administration tasks easier after the database size passes a certain threshold.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Using Horizontal Partitioning: rows are separated into partitions. Mostly managed by the DB.&lt;/li&gt;
&lt;li&gt;Using Vertical Partitioning: splitting a table by columns. Databases usually do this for TEXT and BLOB.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Physical Database Design Antipatterns
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Rounding errors (when you want to store floating point numbers in the DB)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; When you use float, double, or any other related DB type. The problem is how the number is represented internally by the DB. It will do all kinds of unpredictable roundings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; scientific applications.&lt;br&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; use NUMERIC or decimal&lt;/p&gt;

&lt;h4&gt;
  
  
  31 flavors
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; When you want to restrict a column to specific values (e.g., the status of a ticket), you define the allowed values in the table's schema or as a trigger.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; when you have very few values that will never change. But you might still get it wrong (e.g., gender).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; create a lookup table.&lt;/p&gt;

&lt;h4&gt;
  
  
  Phantom files
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; When you want to store Store Images or Other Bulky Media (when you reference them via the DB), and you use the FS directly, instead of the DB. These need to be specifically backed up, and the DB does not manage them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; when the data files might affect how your DB behaves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Use BLOB Data Types As Needed&lt;/p&gt;

&lt;h4&gt;
  
  
  Index shotgun
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; When you want to Optimize the performance of the DB, and you throw indexes here and there without thinking too much about it (no indexes, too many indexes, queries that cannot benefit from indexes).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; none&lt;br&gt;
&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Measure the query times&lt;/li&gt;
&lt;li&gt;Get the query execution plan (QEP)&lt;/li&gt;
&lt;li&gt;Analyze the QEP and find where the index needs to be added
after creating the index, test&lt;/li&gt;
&lt;li&gt;Optimize: covering (compound) indexes could speed up things even more; use in mem vs. on disk indexes&lt;/li&gt;
&lt;li&gt;Rebuild: because indexes become fragmented as rows are deleted/created/updated&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Query Antipatterns
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Fear of the unknown
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; thinking that null is just another value. Actually, SQL treats null as a special value, different from zero, false, or an empty string. As a general rule, all operations with null will return null. Or using a value to represent null.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Treat null as a unique value. Declare Columns NOT NULL when it makes sense. Also, consider if using default makes sense.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ambiguous groups
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; What you're already doing: Get Row with Greatest Value per Group. When you're using group by and are trying to get extra information from the row that you selected (like other columns that are not included in the group by expression), in other words, referencing Nongrouped Columns in the select list of the query.&lt;/p&gt;

&lt;p&gt;Every column in the select list of a query must have a single value row per row group. This is called the Single-Value Rule. Columns named in the GROUP BY clause are guaranteed to be exactly one value per group, no matter how many rows the group matches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; none because most DBs will throw an error&lt;br&gt;
&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't add an extra column to the select list&lt;/li&gt;
&lt;li&gt;Using a Correlated Subquery (own note: seems pretty hard to implement)&lt;/li&gt;
&lt;li&gt;Using a Derived Table: use the group query as a subquery of a query that selects the columns that you need. But merging their results with left join
&lt;a href="https://stackoverflow.com/questions/7745609/sql-select-only-rows-with-max-value-on-a-column"&gt;https://stackoverflow.com/questions/7745609/sql-select-only-rows-with-max-value-on-a-column&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Using an Aggregate Function for Extra Columns -&amp;gt; apply a function to the extra column in the select list so that you ensure that there's only one value coming back (e.g., max or GROUP_CONCAT)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Random selection
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; When you must fetch a random sample from one of your tables, you sort data randomly -&amp;gt; ORDER BY RAND(). This operation does a full table scan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; only when you know for sure that the size of the data that you're randomizing will not be bigger than 50-100 rows.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Pick a Random primary Key Value Between 1 and MAX; only when primary keys are contiguous&lt;/li&gt;
&lt;li&gt;Choose Next Higher Key Value: just like before, except you'll be picking the next available key (assumes that the keys are non-contiguous). The results will not be evenly distributed&lt;/li&gt;
&lt;li&gt;Get a List of All Key Values. Choose One at Random (do it in the application; does not scale well)&lt;/li&gt;
&lt;li&gt;Choose a Random Row Using an Offset: select a random between 0 and total_rows and use it in an OFFSET command&lt;/li&gt;
&lt;li&gt;Search the docs of your DB of choice&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Spaghetti query
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; When you want to achieve everything in only one SQL query (solving a complex problem in one step,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You might create a cartesian product without wanting to do that&lt;/li&gt;
&lt;li&gt;It's going to be hard to maintain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; when you're going to use that query as a datasource in a 3rd party app&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Split your initial query into multiple smaller ones&lt;/li&gt;
&lt;li&gt;Use the union label (to combine smaller queries)&lt;/li&gt;
&lt;li&gt;Writing SQL Automatically—with SQL -&amp;gt; use concat to create a list of queries to run; you can also do this with a script in bash&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Readable passwords
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; Store Password in Plain Text&lt;br&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; hash your passwords with a salt directly in your application.&lt;/p&gt;

&lt;h4&gt;
  
  
  SQL injection
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; when writing dynamic SQL queries, you end up executing unverified input as code.&lt;br&gt;
&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parameterize Dynamic Values (use query parameters)&lt;/li&gt;
&lt;li&gt;Filter Input&lt;/li&gt;
&lt;li&gt;Do your best not to write standard SQL. Rely on your data access framework as much as possible&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Diplomatic immunity
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; when you want to code fast, completely skipping engineering best practices. Make SQL a Second-Class Citizen, not giving the DB the same importance that the code gets in terms of quality.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Forget about self-documenting code. It's a myth. Use Entity-relationship diagrams, break them down into functionalities and mention triggers and stored procedures&lt;/li&gt;
&lt;li&gt;Use source control&lt;/li&gt;
&lt;li&gt;Have tests that test the interaction with the DB&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Magic beans
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; when designing an MVC application and you don't consider enough how to separate the app logic between the M, V, and C. (Own note: I'll probably need to re-read this chapter from the book)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Active record is a design pattern that maps objects to DB tables. The Model Has an Active Record -&amp;gt; basically, build services that compose the models. Aim to make your model a domain model, not a database model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rules of normalization
&lt;/h3&gt;

&lt;p&gt;Should be considered only in the context of your app. How much do you want to normalize/denormalize? It's a tradeoff. And it would be best if you benchmarked it.&lt;/p&gt;

&lt;p&gt;The objectives of normalization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To represent facts about the real world in a way that we can understand&lt;/li&gt;
&lt;li&gt;To reduce storing facts redundantly and to prevent anomalous or inconsistent data&lt;/li&gt;
&lt;li&gt;To support integrity constraints&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  The forms
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;First Normal Form: no repeating groups (no multicolumn attributes, no multiple values in one column)&lt;/li&gt;
&lt;li&gt;Second Normal Form: when you're repeating values on a column, instead of creating a dependent table&lt;/li&gt;
&lt;li&gt;Third Normal Form: single responsibility principle for tables (put the column in the table that it belongs to)&lt;/li&gt;
&lt;li&gt;Advanced 3rd form (Boyce-Codd Normal Form): table doesn’t contain any field (other than the primary key) that can determine the value of another field. Example: teacher, subject, student. The subject is always dependent on the teacher.&lt;/li&gt;
&lt;li&gt;Fourth Normal Form: BCNF without compound keys&lt;/li&gt;
&lt;li&gt;Sixth normal form: It’s typically used to support a history of changes to attributes (e.g., an audit log).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  See no evil
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; discarding DB error messages or not looking at the raw SQLs that get run when debugging the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Recover from Errors Gracefully -&amp;gt; log potential exceptions every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Antipatterns that are not that current anymore?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Implicit Columns
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; when you want to reduce typing (like explicitly mentioning all columns in the select list), you use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For insert without specifying the columns, when you refactor you might break the insert or, even worse, the database&lt;/li&gt;
&lt;li&gt;A select with * will fetch and display all the data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; when you're writing queries to try things out&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Name Columns Explicitly&lt;/p&gt;

&lt;h4&gt;
  
  
  Poor man’s search engine
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; when you want to do a full-text search, you use pattern-matching predicates (e.g., LIKE, REGEXP).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; don't use SQL. Elasticsearch has made this one easy. If you have to use SQL (for simple cases, each vendor has a solution for this already)&lt;/p&gt;

&lt;h4&gt;
  
  
  Pseudokey neat-freak
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Antipattern:&lt;/strong&gt; when you want to have contiguous keys in a table (e.g., when you have deletions in the DB), you want to fill in the gaps.&lt;/p&gt;

&lt;p&gt;Instead of allocating a new primary key value using the automatic pseudokey mechanism, you might want to make any new row use the first unused primary key value&lt;br&gt;
Renumbering Existing Rows -&amp;gt; changing the existing keys so that they are contiguous.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legitimate Uses of the Antipattern:&lt;/strong&gt; none.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; just let it be. You can see the primary key id as UUIDs. The fact that they are consecutive is just a coincidence of the implementation.&lt;/p&gt;

</description>
      <category>sql</category>
    </item>
    <item>
      <title>CITCON 2020, a virtual unconference</title>
      <dc:creator>Horia Constantin</dc:creator>
      <pubDate>Mon, 08 Feb 2021 21:42:56 +0000</pubDate>
      <link>https://dev.to/treaz/citcon-2020-a-virtual-unconference-5g8</link>
      <guid>https://dev.to/treaz/citcon-2020-a-virtual-unconference-5g8</guid>
      <description>&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TgwLcCWg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/EZR6wRiX0AEPaoJ.jpg" alt="unknown tweet media content"&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--GKEIBII_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1134004637282033664/G_WB283X_normal.jpg" alt="Adina Moldovan profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Adina Moldovan
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @adinnaplus
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      CITCON rocked again, this time ONLINE! &lt;br&gt;&lt;a href="https://t.co/UpjmGAk95v"&gt;citconf.com&lt;/a&gt; &lt;a href="https://twitter.com/hashtag/citcon"&gt;#citcon&lt;/a&gt; &lt;a href="https://twitter.com/citcon"&gt;@citcon&lt;/a&gt; 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      16:44 PM - 30 May 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1266772475003768838" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WwRENZp4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1266772475003768838" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PFD0MJBa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1266772475003768838" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6wx1BHu3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Have you heard about &lt;a href="https://en.wikipedia.org/wiki/Open_Space_Technology"&gt;open-spaces&lt;/a&gt; before? Have you ever been to an unconference? If yes, find something else to read. Otherwise, keep on reading. I’m going to describe how I experienced a virtual unconference I recently attended. By the end, you will have some good reasons to join one.&lt;br&gt;
What is an unconference?&lt;/p&gt;

&lt;p&gt;I’ve written about &lt;a href="https://www.horiaconstantin.com/tag/unconference/"&gt;unconferences&lt;/a&gt; before, but I never explained why I love this event format. There’s a lot to say, but I’ll restrict myself to the top three reasons why I keep coming back:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Autonomy and empowerment: &lt;a href="https://en.wikipedia.org/wiki/Open_Space_Technology"&gt;the format&lt;/a&gt; of the event allows the participants to focus on meeting their individual needs. The law of two feet means that you are expected to use your own two feet to move to whatever place you can best contribute and learn. In the same way, all participants are allowed to adjust scheduled sessions as they see fit.&lt;/li&gt;
&lt;li&gt;Strong engagement of participants: anyone can propose a topic for a session. During a session, you are encouraged to suggest an improvement if you notice that a session is not going well.&lt;/li&gt;
&lt;li&gt;Relaxed expectations: two &lt;a href="https://www.openspaceworld.org/files/tmnfiles/2pageos.htm"&gt;guiding principles&lt;/a&gt; remind participants to take it easy. &lt;em&gt;“Whoever comes is the right people”&lt;/em&gt; and &lt;em&gt;“Whatever happens is the only thing that could’ve happened“&lt;/em&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An open-space offers a different kind of experience than a regular conference. Even with a good understanding of the guiding principles, it’s going to be hard to imagine how it develops unless you attend it.&lt;/p&gt;
&lt;h2&gt;
  
  
  A typical unconference session
&lt;/h2&gt;

&lt;p&gt;A typical unconference session is usually a “go-with-the-flow” discussion on the proposed topic, and it depends on the participants to set the direction and to keep the session on track. Often, participants, bring up a couple of subjects related to the topic. Commonly, some of the subjects will be touched only briefly. There’s no slide deck to take away at the end; every participant takes from the session whatever they need.&lt;/p&gt;
&lt;h2&gt;
  
  
  CITCON unconference goes virtual
&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.citconf.com/"&gt;CITCON&lt;/a&gt; usually takes place in a European city. Since COVID-19 makes traveling unsafe, CITCON 2020 went online. I volunteered to help the organizers, &lt;a href="https://www.linkedin.com/in/jfredrick/"&gt;Jeff&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/thepj/"&gt;PJ&lt;/a&gt;. We used the &lt;a href="https://medium.com/swlh/how-to-run-a-zoom-cocktail-party-and-have-better-classes-conferences-and-meetings-too-dc2c5b58f8be"&gt;suggestions&lt;/a&gt; from Misha Glouberman, did a couple of test runs, and, in the end, we had a good understanding of the technology stack needed to need all the needs of an open-space. Amelie sums it up perfectly.&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--UZMjjDQH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/476494473287831552/4qtvK0FM_normal.jpeg" alt="Amélie Cornélis profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Amélie Cornélis
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="comment-mentioned-user" href="https://dev.to/ameliecornelis"&gt;@ameliecornelis&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Tool stack this time is:&lt;br&gt;- slack (single channel)&lt;br&gt;- zoom rooms (we're all co-hosts)&lt;br&gt;- single google doc with All The Links&lt;br&gt;- miro for the schedule
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      10:37 AM - 30 May 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1266680249124900865" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WwRENZp4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1266680249124900865" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PFD0MJBa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1266680249124900865" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6wx1BHu3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;The tools worked well on the day of the conference (~70 participants). A couple of notes on the tools: the organizers arranged for a basic Zoom subscription, and a basic &lt;a href="https://miro.com/app/"&gt;Miro&lt;/a&gt; subscription. There was also a need for a full-time “Zoom receptionist”, with the primary responsibility of elevating participants to co-hosts. Being a co-host means that you can move around the breakout rooms, which served as the rooms of the sessions (the blue horizontal swimlanes in the schedule below).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YMfCx_xH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.horiaconstantin.com/wp-content/uploads/2020/06/EZQl87WXkAEqp2Q.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YMfCx_xH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.horiaconstantin.com/wp-content/uploads/2020/06/EZQl87WXkAEqp2Q.jpg" alt="CITCON 2020, virtual open-space schedule"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When it’s over, it’s over
&lt;/h2&gt;

&lt;p&gt;I am finishing with another of the four principles of open-spaces. Creativity has its rhythm. So do groups. When you think it is over, ask: Is it over? And if it is, go on to the next thing you have passion for. See you at &lt;a href="https://citconf.com/"&gt;CITCON&lt;/a&gt;. Or at &lt;a href="https://www.humansconf.org/"&gt;humansconf&lt;/a&gt;. Or at &lt;a href="https://devopsdays.org/"&gt;DevOpsDays&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>unconference</category>
    </item>
    <item>
      <title>Checklist for learning Scala</title>
      <dc:creator>Horia Constantin</dc:creator>
      <pubDate>Mon, 08 Feb 2021 21:30:27 +0000</pubDate>
      <link>https://dev.to/treaz/checklist-for-learning-scala-1m0m</link>
      <guid>https://dev.to/treaz/checklist-for-learning-scala-1m0m</guid>
      <description>&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--rqRN42gD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1244735072823062528/yAAYPlmF_normal.jpg" alt="Horia Constantin profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Horia Constantin
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @constantinhoria
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Just when I thought I knew enough programming: "Defining a set as  a function that says whether an item is included in the set or not" 🤯 &lt;a href="https://twitter.com/hashtag/scala"&gt;#scala&lt;/a&gt;&lt;br&gt;&lt;br&gt;type Set = Int =&amp;gt; Boolean&lt;br&gt;  def contains(s: Set, elem: Int): Boolean = s(elem)
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      09:16 AM - 19 Jan 2021
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1351458487088406529" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WwRENZp4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1351458487088406529" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PFD0MJBa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1351458487088406529" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6wx1BHu3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Learning Scala doesn’t have to be painful. &lt;a href="https://www.horiaconstantin.com/checklist-for-learning-a-new-programming-language/"&gt;In a previous article&lt;/a&gt;, I proposed the use of a checklist to give structure to learning a new programming language. My intention with this article is to demonstrate how to use a checklist to learn scala.&lt;/p&gt;

&lt;h2&gt;
  
  
  The checklist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mindset
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Personal why’s for learning Scala:&lt;/strong&gt; I’ve wanted to start to learn a new programming language for some time. I chose Scala thinking that I can get a freelance gig faster than anything else. And because a former colleague recommended it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find a project/application to build with Scala:&lt;/strong&gt; a web app that supports most technologies that are required these days for a fully-featured website. I called it &lt;a href="https://github.com/treaz/scalatraseed"&gt;scalatraseed&lt;/a&gt; since it uses the Scalatra web framework at its core.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Setting
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Find a high-quality online Scala course/book:&lt;/strong&gt; I’ve found excellent resources &lt;a href="https://docs.scala-lang.org/learn.html"&gt;here&lt;/a&gt;. Scala originated in EPFL, so I started with &lt;a href="https://courseware.epfl.ch/courses/course-v1:EPFL+progfun1+2018_T1/about"&gt;Functional Programming Principles in Scala&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find/create Scala cheat sheet:&lt;/strong&gt; &lt;a href="https://github.com/treaz/scala-cheat-sheet"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find the official Scala documentation:&lt;/strong&gt; start with the &lt;a href="https://www.scala-lang.org/api/2.13.1/"&gt;standard library&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find/create a comparison between Scala and Java:&lt;/strong&gt; &lt;a href="https://docs.scala-lang.org/tutorials/scala-for-java-programmers.html"&gt;these docs&lt;/a&gt; and &lt;a href="https://app.pluralsight.com/library/courses/scala-for-java-developers/table-of-contents"&gt;this course&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find/create a dictionary/glossary of the concepts, keywords, etc.:&lt;/strong&gt; I haven’t been doing very well at this point because I tend to look up a concept as soon as I encounter it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Take notes:&lt;/strong&gt; questions, curiosities, “strange” code: useful point, but the questions and curiosities change from one day to another that it makes it useless to write it here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start collaborating on an open-source library:&lt;/strong&gt; this point was a bit more complicated than I thought. Many libraries are either too big or have too many contributors already or are too advanced for a beginner or don’t have good-first-issues. I decided to settle down on &lt;a href="https://github.com/scalatra/scalatra"&gt;Scalatra&lt;/a&gt; because I was already using it in my demo project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find/create a roadmap that describes the learning process:&lt;/strong&gt; &lt;a href="https://www.scala-lang.org/old/node/8610"&gt;this&lt;/a&gt; is a good start&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find a code conventions document:&lt;/strong&gt; the online Scala course that I’ve started uses &lt;a href="http://www.scalastyle.org/"&gt;Scalastyle&lt;/a&gt; for enforcing the style of the code. If it’s good enough for the Scala core team, it’s good enough for me.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find/create a list of antipatterns:&lt;/strong&gt; I couldn’t find anything, probably because Scala is such a flexible language (allowing full OOP or FP and anything else in between). The small things that I’ve found so far revolve around using the language constructs correctly (e.g., use “if” as an expression, not a statement). So, nothing useful here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find and learn how to use the most popular build tool:&lt;/strong&gt; I wanted to leverage my maven knowledge initially, but it’s a constant uphill battle. &lt;a href="https://www.scala-sbt.org/"&gt;Sbt&lt;/a&gt; for the win!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find a list of Scala project seeds:&lt;/strong&gt; &lt;a href="https://developer.lightbend.com/start/"&gt;from lightbend&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find the frameworks:&lt;/strong&gt; &lt;a href="http://www.scalatest.org/"&gt;Scalatest&lt;/a&gt;, &lt;a href="http://scalatra.org/"&gt;Scalatra&lt;/a&gt;, &lt;a href="https://sangria-graphql.org/"&gt;Sangria&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Having applied the checklist, I’m discovering that some points are part of the continuous process of learning (take notes; create a dictionary/glossary), while others are a one-time task (find the official documentation).&lt;/p&gt;

&lt;p&gt;I’m also learning that some tasks are not so useful as others. That can be because they’re part of another, more comprehensive task (the online Scala course that I found uses Scalatest) or because they’re not that important at this stage of learning (they just take up mental and checklist space).&lt;/p&gt;

&lt;p&gt;Based on this experience and the idea of lean learning, I’ll be updating the &lt;a href="https://www.horiaconstantin.com/checklist-for-learning-a-new-programming-language/"&gt;checklist template&lt;/a&gt; so that it is a more effective learning resource. For historical reasons, I’ll keep the checklist in this article as it is.&lt;/p&gt;

</description>
      <category>scala</category>
      <category>tips</category>
    </item>
    <item>
      <title>Checklist for learning a new programming language</title>
      <dc:creator>Horia Constantin</dc:creator>
      <pubDate>Sat, 06 Feb 2021 20:39:11 +0000</pubDate>
      <link>https://dev.to/treaz/checklist-for-learning-a-new-programming-language-5g67</link>
      <guid>https://dev.to/treaz/checklist-for-learning-a-new-programming-language-5g67</guid>
      <description>&lt;p&gt;&lt;strong&gt;Update 22/01/2020:&lt;/strong&gt; I’ve applied the checklist to &lt;a href="https://www.horiaconstantin.com/checklist-for-learning-scala/"&gt;learning Scala&lt;/a&gt; and I’m updating it based on that experience.&lt;/p&gt;

&lt;p&gt;In a workshop that I recently gave, I compared learning a new programming language with learning a new natural language. Depending on your experience, learning a new programming language might be a medium difficulty task or a hard project. In the latter situation, you’re going to need to have some structure in your approach, to ensure you reach your goal. But what is an easy way to start? I propose to use a checklist similar to the one I’ve written below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Naive solution
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;“I’ve got enough Java experience. I’m a good software engineer. I’ve played with other languages before, and it went well.”&lt;/em&gt; I said to myself. I was aware that Scala has some very funky notations and that it uses plenty of functional programming concepts. But my confidence was high. I’ll do it as I did it before: take an online course, read a book, find the documentation, make a small app, and go from there. But I didn’t expect to get into analysis paralysis because of the overwhelming number of books, frameworks, courses, etc. I eventually decided on an online course and finished it only to realize that I wasn’t learning as much as I wanted. I decided to make the learning process explicit by creating a checklist that I could improve iteratively.&lt;/p&gt;

&lt;h2&gt;
  
  
  The checklist
&lt;/h2&gt;

&lt;p&gt;I created this checklist iteratively as I was learning Scala, but I’ve generalized it for any programming language. In a future post, I’ll show how I’ve applied it to my learning.&lt;/p&gt;

&lt;p&gt;There are two components that I found valuable while learning Scala: keeping my motivation high (mindset) and having a good learning plan that supports my learning experience (setting). Start with mindset first (ordered starting with top priority), continue with the setting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mindset
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Clarify what your personal why’s for learning are. &lt;a href="https://en.wikipedia.org/wiki/Self-determination_theory"&gt;Try to connect this to intangible needs/wants/dreams&lt;/a&gt;. Bad: I want to learn this because my boss promised me a 2% raise at the end of the year. Good: I want to learn this because I’m curious about how it works&lt;/li&gt;
&lt;li&gt;Find a project to build while learning. Online courses and books tend to teach concepts without applying them to real-world use cases.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  One-time tasks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Follow a high-quality online course/book about the language. Material created by the language’s author or main contributor clarifies the language philosophy and its specific patterns.&lt;/li&gt;
&lt;li&gt;Find/create a cheat sheet with the most common expressions and idioms of the language and keep it open in a browser tab&lt;/li&gt;
&lt;li&gt;Find/create a comparison between the new language and another that you’re familiar with&lt;/li&gt;
&lt;li&gt;Start collaborating on an open-source library. Pick a common one, but not a complex one. Start by searching on GitHub.&lt;/li&gt;
&lt;li&gt;Find the official language documentation, learn how to read it, and keep it open in a browser tab&lt;/li&gt;
&lt;li&gt;Find/create a roadmap that describes the steps that you will go through (the table of contents of online courses are usually a good source)&lt;/li&gt;
&lt;li&gt;Find a code-conventions/style-guide document&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Continuous tasks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Take notes: questions, curiosities, “strange” code.&lt;/li&gt;
&lt;li&gt;Find someone to review the code that you write.&lt;/li&gt;
&lt;li&gt;Find/create a dictionary/glossary of the concepts, keywords, etc. which are specific to the new language (consider making a mindmap). Aim to understand the use cases for them. And practice it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deprecated tasks
&lt;/h3&gt;

&lt;p&gt;These tasks seemed a good idea in theory but were not useful to me in practice.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find/create a list of antipatterns. It might be syntax or design patterns, but the language that you are learning is going to do a couple of things differently compared to what you were used to.&lt;/li&gt;
&lt;li&gt;Find the frameworks that you foresee needing and are the most popular (GitHub search with the new language tag)&lt;/li&gt;
&lt;li&gt;Find and learn how to use the most popular build tool&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Work in progress
&lt;/h2&gt;

&lt;p&gt;At this point, I’m convinced of the usefulness of having a checklist for learning a new programming language. However, I’m aware that some of these ideas are more effective than others. In a future article, I’ll tell you how my learning process was affected by following this checklist.&lt;/p&gt;

</description>
      <category>tips</category>
    </item>
    <item>
      <title>Mobile app makers review</title>
      <dc:creator>Horia Constantin</dc:creator>
      <pubDate>Sat, 06 Feb 2021 20:13:36 +0000</pubDate>
      <link>https://dev.to/treaz/mobile-app-makers-review-1k83</link>
      <guid>https://dev.to/treaz/mobile-app-makers-review-1k83</guid>
      <description>&lt;p&gt;A friend came to me recently with the idea of creating a mobile app that would support the learning platform that he already has. We discussed what features he wanted and what his budget was. The budget was tight, and I realized that developing the app from scratch was not an option. I used &lt;a href="https://www.appdevelopmentcost.com"&gt;this cost calculator&lt;/a&gt; to get an estimate for the custom-built app. Later, I found &lt;a href="https://digitalya.co/app-cost-calculator/"&gt;this calculator&lt;/a&gt; that seems simpler and gives a lower estimated cost. It seemed that the only way forward was to look for a platform that would generate the app for me.&lt;/p&gt;

&lt;p&gt;I knew that there should be some mobile app generators on the market, but I had no idea what features they offered and at what cost. To my surprise, I discovered that there were more than mature 20 platforms, all offering similar features. I soon found out that the mobile-app-makers industry is quite mature: there are &lt;a href="https://www.websitetooltester.com/en/blog/app-makers/"&gt;reviews&lt;/a&gt; and &lt;a href="https://apptooltester.com/best-app-maker/"&gt;comparisons&lt;/a&gt; and &lt;a href="https://mashable.com/article/build-mobile-apps/"&gt;top10’s&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I soon understood that all those articles would not help me with my problem: determine how much it would cost to run such an app. The reason is that the platforms are vastly diverse in terms of their offering: different prices for similar, but not always the same set of app features. The services included in the contract and the actual terms would also vary greatly. I had to make my research and comparison, based on the needs of my friend.&lt;/p&gt;

&lt;p&gt;In this post, I’m sharing the results of the research that I’ve done. Disclaimer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I might have missed a few app makers as I only used &lt;a href="https://www.websitetooltester.com/en/blog/app-makers/"&gt;this article&lt;/a&gt; as a source&lt;/li&gt;
&lt;li&gt;My focus was on the feature set that my friend needed. I didn’t look at the rest of the offered features.&lt;/li&gt;
&lt;li&gt;I only spent 10-15 minutes with each app builder platform, so I might have missed details that need more digging (or contacting customer support).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://docs.google.com/spreadsheets/d/1WyHLw6Me-z0Xlr7LN3yDkofoKiII19xEZYAQILvR5-0/edit#gid=0"&gt;This comparison sheet&lt;/a&gt; is not detailed nor complete enough to allow me to select a “winner”. Instead, I will use it during the discussions with my friend to make a shortlist of 2-3 mobile app makers that I will investigate further.&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>review</category>
    </item>
    <item>
      <title>How’s Xiaomi MiBand privacy?</title>
      <dc:creator>Horia Constantin</dc:creator>
      <pubDate>Sat, 06 Feb 2021 19:45:42 +0000</pubDate>
      <link>https://dev.to/treaz/how-s-xiaomi-miband-privacy-74i</link>
      <guid>https://dev.to/treaz/how-s-xiaomi-miband-privacy-74i</guid>
      <description>&lt;p&gt;&lt;strong&gt;29/12/2020 Final update:&lt;/strong&gt; Almost a year after my complaint, I received an answer: the Dutch Personal Data Authority is not going to research my complaint further because they can’t say if they are able to be effective in reaching the goal of the complaint. Additionally, there were no other complaints against Huami, so they consider it a small risk (I wonder if they know that Huami is actually behind Xiaomi). &lt;a href="https://www.horiaconstantin.com/wp-content/uploads/2020/12/Scannable-document-op-18-dec.-2020-19_46_20.pdf"&gt;Here's the full official response&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;02/06/2020 Update:&lt;/strong&gt; While still waiting for a response from the &lt;a href="http://autoriteitpersoonsgegevens.nl/"&gt;Dutch Personal Data Authority&lt;/a&gt;, I’ve been contacted by Kevin Grahl, who wrote a &lt;a href="https://kevingrahl.de/article/mi-band-4-review"&gt;great article&lt;/a&gt; on how to protect yourself from leaking personal data to Xiaomi. The trick is to use the &lt;a href="https://lockdownhq.com/"&gt;Lockdown&lt;/a&gt; iOS app. I’m confident about this solution 🙂&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;27/11/2019 Update:&lt;/strong&gt; After 2 SARs without a response from Huami, I’ve decided to make a complaint with the &lt;a href="http://autoriteitpersoonsgegevens.nl/"&gt;Dutch Personal Data Authority&lt;/a&gt;. The estimated response time is 3 months.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7/11/2019 Update:&lt;/strong&gt; I just received a concrete answer from Xiaomi’s Privacy Office: “MiFit is a product of Huami. Xiaomi Singapore Pte Ltd is not the MiFit data controller and is not responsible for processing the personal data of MiFit ‘s data subject. Please refer below Huami’s contact information is &lt;a href="mailto:privacy@huami.com"&gt;privacy@huami.com&lt;/a&gt;.”. So, I’ve made a &lt;a href="https://www.mydatadoneright.eu/"&gt;SAR&lt;/a&gt; to Huami.&lt;/p&gt;

&lt;h2&gt;
  
  
  Xiaomi Miband
&lt;/h2&gt;

&lt;p&gt;Xiaomi produces a wearable activity tracker called MiBand. The 3rd generation has a reasonable feature set, and it is 2-3 times cheaper than its competitors. It’s a great entry-level band if you want to begin tracking your fitness levels.&lt;/p&gt;

&lt;p&gt;I bought a Xiaomi MiBand3 because I was hoping to make sense of my erratic sleeping patterns. I was also eager to discover how much movement I was getting through the day. Additionally, I was hoping to connect with some faraway friends via the MiFit phone app.&lt;/p&gt;

&lt;h2&gt;
  
  
  But what about privacy?
&lt;/h2&gt;

&lt;p&gt;The data that a fitness tracker generates feels personal, and Xiaomi is a Chinese company. I don’t want the Chinese government to have information about me. It’s bad enough that &lt;a href="https://en.wikipedia.org/wiki/Mass_surveillance_in_China"&gt;Chinese citizens have no privacy&lt;/a&gt;. To make an informed purchase, I searched for articles about “Xiaomi privacy”. I found two articles (&lt;a href="https://openeffect.ca/fitness-tracker-privacy-and-security/"&gt;1&lt;/a&gt; and &lt;a href="https://www.av-test.org/en/news/seven-fitness-wristbands-and-the-apple-watch-in-a-security-check-2016/"&gt;2&lt;/a&gt;) reviewing the InfoSec aspects of a couple of fitness trackers. Yet, nothing that answered my question about Xiaomi. In the end, I decided to buy the band, but I felt uneasy every time the MiFit app “synchronized” with the band. Uneasy, but not concerned enough to look deeper into the matter.&lt;/p&gt;

&lt;p&gt;Susana Sanz, from &lt;a href="https://balkontactics.nl/"&gt;BalkonTactics&lt;/a&gt;, renewed my interest in privacy and InfoSec. After our talk, my unease changed into serious concern about the data generated by my shiny, new fitness tracker. The ethical/moral/philosophical aspect of privacy did not interest me; that’s something that others have talked in more detail (&lt;a href="https://www.ted.com/talks/glenn_greenwald_why_privacy_matters"&gt;Glenn Greenwald&lt;/a&gt; and &lt;a href="https://www.amazon.com/Permanent-Record-Edward-Snowden/dp/1250237238"&gt;Edward Snowden&lt;/a&gt; come to mind).&lt;/p&gt;

&lt;p&gt;I was interested to know what exactly does Xiaomi know about me. &lt;a href="https://www.techrepublic.com/article/how-to-request-your-personal-data-under-gdpr/"&gt;Making a Subject Access Request&lt;/a&gt; (SAR), a right recognized by the &lt;a href="https://gdpr-info.eu/art-15-gdpr/"&gt;GDPR&lt;/a&gt; is one way to go about it. For the sake of learning how SAR work, I submitted one to &lt;a href="mailto:privacy@xiaomi.com"&gt;privacy@xiaomi.com&lt;/a&gt;. But this process would take a long time, and patience is not one of my virtues. While waiting for an official response, why not use a “hacky”, DIY approach to get an answer?&lt;/p&gt;

&lt;h2&gt;
  
  
  The privacy investigation
&lt;/h2&gt;

&lt;p&gt;Nowadays, almost all phone apps communicate with a server on the internet. It is possible to intercept that communication, while it’s happening (see the technical method section at the bottom of the post). Thirty minutes later, I confirmed my concern: Xiaomi collects all the data that MiBand generates. To be more specific, all the data displayed in the MiFit app (e.g., sleep data, training data, heart rate) gets uploaded to the Xiaomi servers. There is no way to disable the upload in the configuration of the application. The band keeps a backlog of all the recorded data, and everything gets uploaded to Xiaomi when I open the mobile app. If you don’t use the MiFit app, you’ll end up with a band that only knows how to count your steps and how to measure your heart rate.&lt;/p&gt;

&lt;p&gt;The only good news here is that, at this moment, the geo-location data is not collected passively (outside training sessions). But there is no guarantee that it will stay like this in the future.&lt;/p&gt;

&lt;p&gt;In the end, I’m left feeling disappointed that Xiaomi has unrestricted access to sensitive information about my lifestyle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what would happen if someone infiltrates their systems? I’m sure that there are ways in which this data could be exploited to my disadvantage.&lt;/li&gt;
&lt;li&gt;what’s up with this &lt;a href="https://www.mi.com/us/about/agreement/"&gt;shady user agreement&lt;/a&gt;? Not clear to me what Xiaomi and its partners do with the data. I understand that the moment it gets uploaded, I “waive any and all ownership, legal and moral rights” to my data. But how does Xiaomi use it? Who are the third parties or Xiaomi affiliates that have access to it? Is it sold or monetized in any way? Lots of questions and no clear answers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’ve been on the internet long enough, you’re familiar with the phrase “If you’re not paying for the product, you are the product”. Fun fact, in 2016, the average worth of a Facebook user was &lt;a href="https://www.theguardian.com/technology/2016/jan/28/how-much-are-you-worth-to-facebook"&gt;$3.73 per quarter&lt;/a&gt;. I’m not ok with that, but let’s leave it there for now. Thinking logically, the phrase should not stand once I start paying for the product. Right? Well, it seems that this is not the case with Xiaomi MiBand.&lt;/p&gt;

&lt;h2&gt;
  
  
  There’s no privacy and I don’t own the data
&lt;/h2&gt;

&lt;p&gt;I’m dissatisfied that, despite paying for the MiBand, I “waive any and all” rights over the data that I generate. In this new light, what seemed to be a good deal (best cheapest fitness tracker on the market) became a lousy deal when reading the fine print and doing a bit of research.&lt;/p&gt;

&lt;p&gt;In the end, there are two big questions left in my mind about this way of collecting personal data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this a general practice of the fitness band industry, or is Xiaomi an exception?&lt;/li&gt;
&lt;li&gt;Are other Xiaomi products collecting data in the same way?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you own a fitness tracker or another Xiaomi product, can you do a bit of digging around and let me know? Or get in touch with me and we can do the research together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical details of the investigation
&lt;/h2&gt;

&lt;p&gt;The technical method of finding out what MiBand3 data gets uploaded to Xiaomi’s servers was simple. Had I known it would be so simple, I wouldn’t have postponed it so much.&lt;/p&gt;

&lt;p&gt;The hardware setup: I had to install &lt;a href="https://mitmproxy.org/"&gt;mitmproxy&lt;/a&gt; on my laptop.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;connect both my phone (with the Xiaomi MiFit app) and my laptop to the same WiFi network&lt;/li&gt;
&lt;li&gt;install and run mitmproxy on my laptop&lt;/li&gt;
&lt;li&gt;install the mitmproxy root certificate on my phone&lt;/li&gt;
&lt;li&gt;on my phone, set the proxy server for the WiFi to point to my laptop&lt;/li&gt;
&lt;li&gt;open the Xiaomi MiFit app and look at the requests going into the proxy running on my laptop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Out of all the requests made by the Xiaomi MiFit app, only one sends a lot of data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST https://api-mifit-de.huami.com/v1/data/band_data.json?r=50AB6198-7007-47BF-86AC-53F606CDD4F6&amp;amp;t=1565977799279
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the payload of this request is a key called data_json that contains all the recent band data (as the name of the endpoint suggests). I took a look at the data in the JSON object and saw all the data points that are shown on all the graphs (in the app), including all the geo-coordinates of my running sessions. To my surprise, the MiFit app didn’t seem to send to Xiaomi information about my current location. Yet, this is not a guarantee that this information will remain on my phone in the future.&lt;/p&gt;

&lt;p&gt;From a technical perspective, I enjoyed doing this little research. Using mitmproxy was straightforward, and I recommend it if you want to see what communication goes on between the apps on your phone and the internet. &lt;/p&gt;

</description>
      <category>privacy</category>
      <category>debug</category>
    </item>
    <item>
      <title>Unit testing algorithms</title>
      <dc:creator>Horia Constantin</dc:creator>
      <pubDate>Wed, 03 Feb 2021 23:28:54 +0000</pubDate>
      <link>https://dev.to/treaz/unit-testing-algorithms-28pg</link>
      <guid>https://dev.to/treaz/unit-testing-algorithms-28pg</guid>
      <description>&lt;p&gt;In the last weeks, I’ve been improving my computer science knowledge by solving programming problems. Since these problems have multiple solutions, I find myself writing duplicated unit tests. And refactoring these tests is cumbersome (if find&amp;amp;replace doesn’t work).&lt;/p&gt;

&lt;p&gt;To make the point clear, I’m going to pick a problem with many possible implementations: sorting an integer array. Let’s keep things simple and solve the problem using heap sort, insertion sort, merge sort, quick sort, and selection sort. When the time comes to write the tests, all of the tests will be duplicated between implementations. If, in the future, I come up with a new test case, I have to write (copy&amp;amp;paste) that test to the test class of each implementation. This is far from optimal.&lt;/p&gt;

&lt;p&gt;After doing a bit of digging, I found a convenient solution to removing the duplication: JUnit5’s @ParameterizedTest and @ValueSource. I had to do a bit of refactoring: I created a new interface that declares the sort method, and I made sure that all *sort classes implement the interface properly (you did create one class per implementation, right?). After that, it was just a matter of wiring up the tests.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Cool! 🙂 Before, the unit tests were all over the place, and not all implementations had all the corner cases tested. Soon enough, I found that the QuickSort implementation throws StackOverflowError when the input array contains duplicate values. You can find the source code &lt;a href="https://github.com/treaz/algorithms/tree/master/src/main/java/com/horiaconstantin/sorting/bycompare"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>testing</category>
    </item>
    <item>
      <title>Database integration tests</title>
      <dc:creator>Horia Constantin</dc:creator>
      <pubDate>Mon, 01 Feb 2021 22:03:24 +0000</pubDate>
      <link>https://dev.to/treaz/database-integration-tests-53ef</link>
      <guid>https://dev.to/treaz/database-integration-tests-53ef</guid>
      <description>&lt;p&gt;Did you ever get stuck while trying to find the best way to write a database integration test without mocking the third party? I know I did.&lt;/p&gt;

&lt;p&gt;I’ve known about Martin Fowler since I was a junior developer. He is one of my favorite technology thought-leaders and I enjoy reading the thought-provoking articles that he publishes on &lt;a href="https://martinfowler.com/"&gt;his blog&lt;/a&gt;. In this post, I want to expand on his article about the &lt;a href="https://martinfowler.com/bliki/TestPyramid.html"&gt;test pyramid&lt;/a&gt;, in which he explains the difference between unit tests, integration tests and, UI tests. Specifically, I’ll expand on the part about integration tests.&lt;/p&gt;

&lt;p&gt;I want to show you an easy way to run integration tests against a database. With this goal in mind, I’ve created a &lt;a href="https://github.com/treaz/integrationtestingdocker"&gt;java demo project&lt;/a&gt;, that illustrates the idea and can be used as a starting point for more complicated applications.&lt;/p&gt;

&lt;p&gt;I chose this topic because of all the moments of hesitation that I had when I was developing applications that interacted with a database. I wanted to have tests, but I didn’t want to spend too much time on their setup and my options were limited:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mocking/stubbing the database interaction layer&lt;/li&gt;
&lt;li&gt;connecting to an in-memory database&lt;/li&gt;
&lt;li&gt;connecting to a local/remote test database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regardless of the option I picked, I always had the feeling that the solution could be more elegant. My hesitation would turn into frustration as the application grew and the tests would become harder to maintain. Recently, I discovered a better option: connecting the tests to a database running in a Docker container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database integration tests with docker
&lt;/h2&gt;

&lt;p&gt;In my last project, &lt;a href="https://www.linkedin.com/in/vladyslav-maksymenko-453b3838/"&gt;Vlad&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/mchireychik/"&gt;Max&lt;/a&gt; showed me that using docker containers simplifies running integration tests against a database. No mocking, no complicated infrastructure, no tinkering with configuration files. As long as you can run Docker on the build machine, you can run the tests.&lt;/p&gt;

&lt;p&gt;This is the elegant solution that I was looking for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;install and configure Docker on the build servers and the developer machines that will run the tests&lt;/li&gt;
&lt;li&gt;use &lt;a href="https://github.com/fabric8io/docker-maven-plugin"&gt;docker-maven-plugin&lt;/a&gt; to build a docker image of the database and start/stop a container based on the image&lt;/li&gt;
&lt;li&gt;populate the database with the necessary data (use ‘/docker-entrypoint-initdb.d/’ or a database migration tool like &lt;a href="https://flywaydb.org/"&gt;flyway&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;finally, use &lt;a href="https://maven.apache.org/surefire/maven-failsafe-plugin/"&gt;maven-failsafe-plugin&lt;/a&gt; to run the integration tests&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The benefits of Docker integration tests
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Integration tests become portable and easy to debug.&lt;/strong&gt; If the tests run on my laptop, they will run also on the build machine. If the tests fail on the build machine, the problem will also appear on my laptop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tests become repeatable:&lt;/strong&gt; the plugin builds the docker image from scratch before the tests start and remove it after the tests finish.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This approach is transferable,&lt;/strong&gt; to other types of integration tests. It’s easy to replace the database container with a dockerized REST API (in a move towards &lt;a href="https://martinfowler.com/articles/practical-test-pyramid.html#ContractTests"&gt;contract testing&lt;/a&gt;) or with a message queue container.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/treaz/integrationtestingdocker"&gt;demo project&lt;/a&gt; that I wrote is more than a typical “hello world” application. The integration test starts a docker MySQL container and makes a simple SQL query. You will notice that the docker-maven-plugin configuration is more complicated than necessary, given such a simple test. The reason: the code samples that I found online seemed trivial. I wanted to have a “bootstrap” project that I could reuse in real-life projects without the hassle of gluing everything from scratch.&lt;/p&gt;

&lt;p&gt;This approach to writing integration tests has opened my eyes to the possibilities that exist today in the QA automation domain. The tooling around Docker seems varied enough to accommodate all test types. The number of plausible excuses for not having a proper CI pipeline is getting too low…&lt;/p&gt;

</description>
      <category>java</category>
      <category>maven</category>
      <category>testing</category>
    </item>
    <item>
      <title>Setting up a development MacBook</title>
      <dc:creator>Horia Constantin</dc:creator>
      <pubDate>Mon, 01 Feb 2021 21:43:01 +0000</pubDate>
      <link>https://dev.to/treaz/setting-up-a-development-macbook-4apm</link>
      <guid>https://dev.to/treaz/setting-up-a-development-macbook-4apm</guid>
      <description>&lt;p&gt;I wrote a set of quick-start scripts for developers that use macOS. A Windows version of these scripts might follow soon.&lt;/p&gt;

&lt;p&gt;Setting up a “fresh” laptop for development is always painful, be it windows, macOS or Linux.&lt;/p&gt;

&lt;p&gt;It was the second time in the year when I was doing a fresh install of macOS on my MacBook. I was tired of installing all the apps that I need in a one-by-one fashion. I was tired of doing all the small configurations (for macOS and for the apps). Most of the time I forgot some of them and there are a couple of settings that I have to search online every time.&lt;/p&gt;

&lt;p&gt;I started off by making a list of settings and applications that I use and then I discovered that most of these things can be automated via the command line. I was sure that someone did this before me and I started searching for some scripts that automate the installation of the development environment on a MacBook. I hit jackpot.&lt;/p&gt;

&lt;p&gt;Using a couple of GitHub repositories as inspiration, I created a couple of simple scripts that should install almost everything that I need to start developing on a MacBook. The scripts and the instructions are available here: &lt;a href="https://github.com/treaz/mac-dev-setup/"&gt;https://github.com/treaz/mac-dev-setup/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m curious how much it will hurt the next time that I have to set up a development MacBook.&lt;/p&gt;

</description>
      <category>macbook</category>
      <category>tips</category>
    </item>
    <item>
      <title>Maven plugins that I like</title>
      <dc:creator>Horia Constantin</dc:creator>
      <pubDate>Fri, 22 Jan 2021 22:02:27 +0000</pubDate>
      <link>https://dev.to/treaz/maven-plugins-that-i-like-5hmk</link>
      <guid>https://dev.to/treaz/maven-plugins-that-i-like-5hmk</guid>
      <description>&lt;p&gt;I’ve been through a couple of projects until now and I’m noticing that there are a couple of maven plugins that are useful but are not that famous. I’ll list them below, together with a small explanation of why I find them useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build Number Maven Plugin (org.codehaus.mojo)
&lt;/h2&gt;

&lt;p&gt;Sometimes you want to expose the current build version of your application without necessarily updating the artifact version (when you’re iterating fast and using *-SNAPSHOT). I didn’t get to use this one, but I can imagine that it would be good to have in a /info endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apache Maven Shade Plugin
&lt;/h2&gt;

&lt;p&gt;Sometimes you need to package all your dependencies into a single jar file. If you’re using Spring-Boot, you’ll have an easier life if you use the spring-boot-maven-plugin. Most of the time I use it for small projects, where I want to keep everything compact.&lt;/p&gt;

&lt;h2&gt;
  
  
  License Maven Plugin (org.codehaus.mojo)
&lt;/h2&gt;

&lt;p&gt;Sometimes you need to add a license header to all the files of your project or you need to pack with your application a file with all the licenses of the 3rd party libraries that you’re using. I wish I would have known about it three years ago when I was updating THIRD-PARTY.txt files manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Versions Maven Plugin
&lt;/h2&gt;

&lt;p&gt;Sometimes you want to update the libraries that you’re using to the latest version. This plugin makes managing that update a lot easier. You have good control over the strategy of the version advance. This plugin makes your life easier, assuming you have enough tests to make sure that the update didn’t break your application. I just discovered this plugin and I like that it makes the library update chore a breeze.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apache Maven Enforcer Plugin
&lt;/h2&gt;

&lt;p&gt;Sometimes you need to make it clear what versions of OS, Java, etc. the application can be built with (because of incompatibilities). I like that the set of already-made rules is extensive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apache Maven Checkstyle Plugin
&lt;/h2&gt;

&lt;p&gt;Sometimes you need to enforce the codestyle that the team has agreed to. A bonus is that it helps the new members of the team to pick up the code standards immediately. I have a love and hate relationship with this plugin, but overall I’m happy to see the same kind of code everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  OWASP Dependency-Check Plugin
&lt;/h2&gt;

&lt;p&gt;You always want to have an application that is as secure as possible. This plugin allows you to automatically check for the latest reported vulnerabilities. I knew about the &lt;a href="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project"&gt;OWASP Top Ten&lt;/a&gt; for a couple of years and I learned about this plugin 2 months ago. I’ll never stop using it.&lt;/p&gt;

</description>
      <category>java</category>
      <category>maven</category>
      <category>tips</category>
    </item>
    <item>
      <title>Java Unconferences/Open-spaces</title>
      <dc:creator>Horia Constantin</dc:creator>
      <pubDate>Mon, 18 Jan 2021 11:07:16 +0000</pubDate>
      <link>https://dev.to/treaz/java-unconferences-open-spaces-27oh</link>
      <guid>https://dev.to/treaz/java-unconferences-open-spaces-27oh</guid>
      <description>&lt;p&gt;In 2018, I attended &lt;a href="http://www.citconf.com/"&gt;CITCON&lt;/a&gt; for the first time and then I searched for a similar Java unconference/open-space. I got super lucky to be accepted at JCrete, but that’s another story. The reality is that unconferences are mind-blowing, but a bit hard to find if you don’t know what to look for.&lt;/p&gt;

&lt;p&gt;These are the unconferences that I currently know about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jalba.scot/"&gt;JAlba&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.jcrete.org/"&gt;JCrete&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://voxxeddays.com/hawaii/"&gt;Unvoxxed Hawaii&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jspirit.org/"&gt;JSpirit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mcrjava.github.io/jmanc/"&gt;JManc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Join one… it’s going to be worth it.&lt;/p&gt;

</description>
      <category>java</category>
      <category>unconference</category>
    </item>
    <item>
      <title>Testing JPQL queries straight from Intellij</title>
      <dc:creator>Horia Constantin</dc:creator>
      <pubDate>Sun, 17 Jan 2021 21:39:04 +0000</pubDate>
      <link>https://dev.to/treaz/testing-jpql-queries-straight-from-intellij-10no</link>
      <guid>https://dev.to/treaz/testing-jpql-queries-straight-from-intellij-10no</guid>
      <description>&lt;p&gt;In my current project, most of the queries are written in Java Persistence Query Language (&lt;a href="https://javaee.github.io/tutorial/persistence-querylanguage.html#BNBTG"&gt;JPQL&lt;/a&gt;). As with any *QL (that eventually gets translated to SQL), it’s cumbersome to do the translation of the *QL to SQL and vice-versa. This translation is generally done when you’re creating a new query or trying to debug an existing query. It would be great to be able to send JPQL queries directly to the DB.&lt;/p&gt;

&lt;p&gt;One way to do this is to configure the &lt;a href="https://www.jetbrains.com/help/idea/using-jpa-console.html"&gt;JPA console&lt;/a&gt; in IntelliJ IDEA. Note that this feature is only available in the Ultimate Edition (paid).&lt;/p&gt;

&lt;p&gt;For those that are in a rush, this is the minimal configuration needed to get the JPA console going. To keep things simple, let’s assume that you have a single module project, called test-jpa:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a new data source to the project (View | Tool Windows | Database). This data source should point to the same DB that your entities use.&lt;/li&gt;
&lt;li&gt;Add “JavaEE Persistence” framework support to test-jpa (right click module | Add framework support…). Click OK&lt;/li&gt;
&lt;li&gt;Open the Persistence Window (View | Tool Windows | Persistence)&lt;/li&gt;
&lt;li&gt;In this window, you will assign a data source to test-jpa (right click module | Assign data sources)&lt;/li&gt;
&lt;li&gt;In the Assign Data Sources window, you will see a line with the value “Entities” which points to an empty Data Source field. Click on this field and select the data source from step 1. Click OK.&lt;/li&gt;
&lt;li&gt;In the Persistence Window, expand the module and right click on Entities | Console. You have a choice between JPA and Hibernate Console.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Some cool features that both Consoles support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigating to the declaration of a class or field&lt;/li&gt;
&lt;li&gt;Auto-completion&lt;/li&gt;
&lt;li&gt;Parameterized queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reference: &lt;a href="https://www.jetbrains.com/help/idea/using-jpa-console.html"&gt;https://www.jetbrains.com/help/idea/using-jpa-console.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>intellij</category>
      <category>java</category>
      <category>tips</category>
    </item>
  </channel>
</rss>
