<?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>Forem: Oscar Swanros </title>
    <description>The latest articles on Forem by Oscar Swanros  (@swanros).</description>
    <link>https://forem.com/swanros</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%2F11419%2F51866b56-c55b-43c0-810d-28116184a7df.jpg</url>
      <title>Forem: Oscar Swanros </title>
      <link>https://forem.com/swanros</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/swanros"/>
    <language>en</language>
    <item>
      <title>La barra de progreso de Gmail no es real: ¿por qué?</title>
      <dc:creator>Oscar Swanros </dc:creator>
      <pubDate>Thu, 11 Nov 2021 22:18:32 +0000</pubDate>
      <link>https://forem.com/swanros/la-barra-progreso-de-gmail-no-es-real-por-que-357a</link>
      <guid>https://forem.com/swanros/la-barra-progreso-de-gmail-no-es-real-por-que-357a</guid>
      <description>&lt;p&gt;En smitop:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Un poco de investigación revela que la barra de carga de Gmail no es una barra de carga en absoluto! De hecho, el progreso que se muestra es controlado por una animación de CSS que hace que inicie lento, y luego se quede quieta hasta que Gmail termina de cargar. Esto vence el propósito de una barra de carga: dar un estimado del progreso, no llenarse de manera arbitraria.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Este tipo de problemas es donde muchos programadores pueden “meter el pie”. El impulso inicial de las personas técnicas es hacer las cosas técnicamente correctas, aunque no agreguen tanto valor al producto final o aporten a mejorar la experiencia del usuario.&lt;/p&gt;

&lt;p&gt;Tomando en cuenta el caso de uso más obvio de una barra de progreso, comunicar progreso, ¿qué debería hacer Gmail para ofrecer información técnicamente correcta? Sin lujo de detalle, y vagamente en el orden adecuado:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Analizar la velocidad de conexión actual&lt;/li&gt;
&lt;li&gt;Analizar el tamaño del bundle de JavaScript que hay que cargar desde el servidor&lt;/li&gt;
&lt;li&gt;Hacer un cálculo de la transferencia de los datos de manera continua, tomando en cuenta fluctuaciones en la velocidad de la conexión.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Suena relativamente sencillo; son pocos pasos. Pero toma en cuenta a) la escala a la que opera Gmail, y b) el objetivo real de presentar una barra de navegación, que es darle seguridad a tu usuario de que estás haciendo algo. Considera las implicaciones de hacer un cambio “sencillo” a la escala de Google. Además, la idea de que realmente lo que importa es la experiencia de usuario, y no necesariamente la exactitud de la barra del progreso. Te das cuenta de que implementar una barra de progreso que muestre información técnicamente correcta, realmente no vale la pena.&lt;/p&gt;

&lt;p&gt;Por si no te habías dado cuenta, muchas de las barras de carga que encuentras en tu día a día son completamente falsas. Hoy en día, los sistemas son tan complejos, impredecibles y con tanta entropía, que hacer una barra de carga que muestre progreso requeriría una inversión de tiempo que muy pronto deja de ser rentable para el producto.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Este post originalmente fue publicado en &lt;a href="https://softskillsparadevs.com/productividad/la-barra-progreso-de-gmail-no-es-real-por-que/"&gt;Soft Skills para Devs&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>overengineering</category>
      <category>ux</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Experimenting with inherited tables in Ecto</title>
      <dc:creator>Oscar Swanros </dc:creator>
      <pubDate>Wed, 27 Sep 2017 17:36:51 +0000</pubDate>
      <link>https://forem.com/swanros/experimenting-with-inherited-tables-in-ecto-5oa</link>
      <guid>https://forem.com/swanros/experimenting-with-inherited-tables-in-ecto-5oa</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted at my blog, &lt;a href="https://swanros.com" rel="noopener noreferrer"&gt;swanros.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I've been working on a personal project with some mates for the past few months, and I've been mostly responsible for building our backend with Phoenix. &lt;/p&gt;

&lt;p&gt;It's come to a time where we need to implement some sort of "comments &amp;amp; likes" functionality for the app, so I set out to start thinknig how to go about it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: this is just me experimenting, not trying to say that this is the right way to do it. I'm still learning about these things, so if you think I'm missing something, by all means, let me know at &lt;a href="//mailto:oscar@swanros.com?subject=table%20inheritance%20in%20Ecto"&gt;oscar@swanros.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note 2: the example code for this post is &lt;a href="https://github.com/OscarSwanros/ecto-table-inheritance" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When I started digging around, most of the answers I found about how to implement such functionality pointed to using table inheritance so that I could have a &lt;code&gt;ActionableEntities&lt;/code&gt; table, and &lt;code&gt;EntityComments&lt;/code&gt; and &lt;code&gt;EntityLikes&lt;/code&gt; tables. Then, &lt;code&gt;Posts&lt;/code&gt;, &lt;code&gt;Photos&lt;/code&gt;, &lt;code&gt;Events&lt;/code&gt; whould inherit from &lt;code&gt;ActionableEntities&lt;/code&gt; gaining the ability of being commented or 'liked'.&lt;/p&gt;

&lt;p&gt;"Simple enough," I said to myself. Then I started digging. This is what I found.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing table inheritance with Ecto
&lt;/h3&gt;

&lt;p&gt;I couldn't find concrete examples of how to do this, but did read the &lt;a href="https://hexdocs.pm/ecto/Ecto.Migration.html#table/2" rel="noopener noreferrer"&gt;official Ecto documentation&lt;/a&gt;, though, and found that you can pass an &lt;code&gt;:options&lt;/code&gt; parameter to specify extra attributes that you want your table to have, such as &lt;code&gt;WITH&lt;/code&gt;, &lt;code&gt;INHERITS&lt;/code&gt; or &lt;code&gt;ON COMMIT&lt;/code&gt;. So, the migration looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:actionable_entities&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:entity_comments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
        &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:entity_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;references&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:actionable_entities&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;options:&lt;/span&gt; &lt;span class="s2"&gt;"INHERITS (actionable_entities)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:content&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="c1"&gt;# photos and all other tables follow the same structure as the posts one.&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the modules that're going to be using each of these tables are defined as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Inh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;ActionableEntity&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;

  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="s2"&gt;"interactive_entities"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Inh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;EntityComments&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Comment&lt;/span&gt;

    &lt;span class="n"&gt;timestamps&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="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Inh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;EntityComments&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Comment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;

  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="s2"&gt;"entity_comments"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
    &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Inh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;ActionableEntity&lt;/span&gt;

    &lt;span class="n"&gt;timestamps&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="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Inh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Posts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Post&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;

  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="s2"&gt;"posts"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;

    &lt;span class="n"&gt;timestamps&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"This ought to work right here," I thought to myself. And it does for the most part: I can create a post, and get a list of posts. I can even query for a &lt;code&gt;Post&lt;/code&gt;'s comments eventhough there are none on the database.&lt;/p&gt;

&lt;p&gt;However, the following error on the database arises when trying to create a comment for a given post:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ERROR: insert or update on table &lt;span class="s2"&gt;"entity_comments"&lt;/span&gt; violates foreign key constraint &lt;span class="s2"&gt;"entity_comments_actionable_entity_id_fkey"&lt;/span&gt; DETAIL: Key &lt;span class="o"&gt;(&lt;/span&gt;entity_id&lt;span class="o"&gt;)=(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt; is not present &lt;span class="k"&gt;in &lt;/span&gt;table &lt;span class="s2"&gt;"actionable_entities"&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code used for trying to insert a new comment looks something along the lines of&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;create_for_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&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;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ActionableEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build_assoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First get the post I want to comment, build the corresponding association and then insert it into the database. Here's the problem, though: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;indexes (including unique constraints) and foreign key constraints only apply to single tables, not to their inheritance children.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, if I add a record to &lt;code&gt;posts&lt;/code&gt; or to &lt;code&gt;photos&lt;/code&gt;, the information from the inherited table bubbles up to teh parent table. But then, technically, the information is a &lt;code&gt;post&lt;/code&gt;, not an &lt;code&gt;actionable_entity&lt;/code&gt;. ðŸ¤”&lt;/p&gt;

&lt;p&gt;Postgres is right to be telling me that there's no &lt;code&gt;ActionableEntity&lt;/code&gt; with the given &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I could get more of a sense that something is really wrong here by creating a new &lt;code&gt;photos&lt;/code&gt; table that too inherits from &lt;code&gt;actionable_entity&lt;/code&gt; and adding some records to it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cl.ly/2U373E2h2W02" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd1ax1i5f2y3x71.cloudfront.net%2Fitems%2F2g2l3C3T1Q1i3n3I0P2A%2FImage%25202017-09-23%2520at%25206.35.04%2520PM.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, there's no data consistency as the database can't distinguish between &lt;code&gt;Photos&lt;/code&gt; and &lt;code&gt;Posts&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;One way to solve this is to create a trigger on the database to check every time we try to inset a new &lt;code&gt;EntityComment&lt;/code&gt; for a &lt;code&gt;Post&lt;/code&gt;, that the &lt;code&gt;Post&lt;/code&gt; indeed exists on the database. To do this, the foreign key constraint needs to be removed from the database. So first, update the &lt;code&gt;entity_comments&lt;/code&gt; migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:entity_comments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
  &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:entity_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:integer&lt;/span&gt;

  &lt;span class="n"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;entity_id&lt;/code&gt; is now just a simple &lt;code&gt;:integer&lt;/code&gt;, there's not an explicit reference to the &lt;code&gt;actionable_entities&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;Then, create the trigger:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;execute&lt;/span&gt; &lt;span class="sd"&gt;"""
  CREATE OR REPLACE FUNCTION internal_post_check() RETURNS TRIGGER AS $$
  BEGIN
    IF NOT EXISTS(SELECT 1 FROM posts WHERE id = new.entity_id) THEN
      RAISE EXCEPTION 'Post does not exist:  %', new.entity_id;
    END IF;
    RETURN new;
  END;
  $$ language plpgsql;
"""&lt;/span&gt;

&lt;span class="n"&gt;execute&lt;/span&gt; &lt;span class="sd"&gt;"""
  CREATE TRIGGER CheckEntityExists BEFORE INSERT OR UPDATE ON entity_comments
  FOR EACH ROW EXECUTE PROCEDURE internal_post_check();
"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This trigger will run every time a new record wants to be inserted on the &lt;code&gt;entity_comments&lt;/code&gt; table and will manually check if a post with the value on &lt;code&gt;entity_id&lt;/code&gt; as &lt;code&gt;id&lt;/code&gt; exists.&lt;/p&gt;

&lt;p&gt;It may seem that the problem is now solved, but then again, what would happen when I have a &lt;code&gt;Post&lt;/code&gt; and want to retrieve its comments? If I have &lt;code&gt;Posts&lt;/code&gt; and &lt;code&gt;Photos&lt;/code&gt; and potentially N number of "interactive entities" on my database, how would I be able to query just for those?&lt;/p&gt;

&lt;p&gt;I solved this by adding a new &lt;code&gt;type:String&lt;/code&gt; column on the &lt;code&gt;actionable_entity&lt;/code&gt; table. Posts would have the value &lt;code&gt;post&lt;/code&gt; in that column, photos would have the value &lt;code&gt;photo&lt;/code&gt;, and so on for every type of actionable entity I eventually add to the database.&lt;/p&gt;

&lt;p&gt;This way, now I can query for the comments of a specific photo with a given &lt;code&gt;id&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;comments_for_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="no"&gt;ActionableEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;where:&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="s2"&gt;"post"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;left_join:&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;assoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="ss"&gt;preload:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;comments:&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final notes
&lt;/h2&gt;

&lt;p&gt;Although this &lt;em&gt;works&lt;/em&gt; it does require to bypass the database's integrity checks to handle those on my own. This is very error prone and would require me to constantly run tests to verify that I'm not missing addig a new trigger for photos, events, or any other "actionable entity" that I want to add to my system.&lt;/p&gt;

&lt;p&gt;Also, if I decide to add another kind of action to these entities, such as "likes" or "claps," I'd have add another set of checks for those too.&lt;/p&gt;

&lt;p&gt;This is very soon becoming a maintainability nightmare.&lt;/p&gt;

&lt;p&gt;I asked friend whose really experienced with backend development and he just sent me &lt;a href="https://rhnh.net/2010/07/02/3-reasons-why-you-should-not-use-single-table-inheritance/" rel="noopener noreferrer"&gt;this link&lt;/a&gt; to a post called &lt;a href="https://rhnh.net/2010/07/02/3-reasons-why-you-should-not-use-single-table-inheritance/" rel="noopener noreferrer"&gt;Three Reasons Why You Shouldn't Use Single Table Inheritance&lt;/a&gt;. Read it.&lt;/p&gt;

&lt;p&gt;In the end, this was just me trying to implement a solution that I thought would make for a good one, but it seems that the compromises that need to be made here are not worth it.&lt;/p&gt;

&lt;p&gt;What I went with was the simplest approach: add to the &lt;code&gt;entity_comments&lt;/code&gt; table the columns of the entities that I want to enable comments for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;id&lt;/span&gt; | content | post_id | photo_id | event_id | inserted_at | updated_at
&lt;span class="nt"&gt;-----------------------------------------------------------------------&lt;/span&gt;
1    Hey!      1                               &lt;span class="nt"&gt;-----&lt;/span&gt;         &lt;span class="nt"&gt;-----&lt;/span&gt;
2    &lt;span class="nb"&gt;nice&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;               1                     &lt;span class="nt"&gt;-----&lt;/span&gt;         &lt;span class="nt"&gt;-----&lt;/span&gt;
3    Good!     4                               &lt;span class="nt"&gt;-----&lt;/span&gt;         &lt;span class="nt"&gt;-----&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As stated in &lt;a href="https://github.com/elixir-ecto/ecto/blob/master/lib/ecto/schema.ex#L806" rel="noopener noreferrer"&gt;schema.ex#L806&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Unless you have dozens of columns, this is simpler for the developer,&lt;br&gt;
more DB friendly and more efficient in all aspects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So there's that! Thanks for reading.&lt;/p&gt;

</description>
      <category>ecto</category>
      <category>elixir</category>
      <category>phoenix</category>
      <category>tableinheritanceecto</category>
    </item>
    <item>
      <title>Becoming a Better iOS Developer Through Tooling: My AltConf 2017 talk</title>
      <dc:creator>Oscar Swanros </dc:creator>
      <pubDate>Tue, 15 Aug 2017 02:56:47 +0000</pubDate>
      <link>https://forem.com/swanros/becoming-a-better-ios-developer-through-tooling-my-altconf-2017-talk</link>
      <guid>https://forem.com/swanros/becoming-a-better-ios-developer-through-tooling-my-altconf-2017-talk</guid>
      <description>&lt;p&gt;The fine folks at Realm have now uploaded the remaining videos from AltConf 2017 — including the presentation that I gave there.&lt;br&gt;
​&lt;br&gt;
You can watch it a Realm Academy, &lt;a href="https://academy.realm.io/posts/altconf-2017-oscar-swanros-better-ios-tooling/"&gt;here&lt;/a&gt;.&lt;br&gt;
​&lt;br&gt;
Presenting in the US for the first time was a really exciting experience for me — and something that I'm going to push myself to do more of. I really loved the rush of being there presenting in a foreign country on a foreign language. &lt;br&gt;
​&lt;br&gt;
I'm gonna call this one a victory — although I know there's some stuff in the presentation that could've used a little more polishing, I'm quite happy with how everything turned out. &lt;br&gt;
​&lt;br&gt;
What's nice about this, is that I can now watch myself with a calm head and take notes of things that I can improve for future conference talks in the US or around the world.&lt;br&gt;
​&lt;br&gt;
&lt;strong&gt;I'd really appreciate any constructive feedback you share with me about this presentation.&lt;/strong&gt; Hit me up at &lt;a href="//mailto://oscar@swanros.com?subject=AltConf%20talk%20feedback"&gt;oscar@swanros.com&lt;/a&gt;, or &lt;a href="https://twitter.com/swanros"&gt;@Swanros on Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>conference</category>
      <category>feedback</category>
    </item>
  </channel>
</rss>
