<?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: Mạnh Vũ</title>
    <description>The latest articles on Forem by Mạnh Vũ (@manhvanvu).</description>
    <link>https://forem.com/manhvanvu</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%2F1376476%2F12f5e0bf-238c-4ac5-a9d5-4295cc8f0ba3.jpeg</url>
      <title>Forem: Mạnh Vũ</title>
      <link>https://forem.com/manhvanvu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/manhvanvu"/>
    <language>en</language>
    <item>
      <title>Replace JSON by TOON in Phoenix Channel</title>
      <dc:creator>Mạnh Vũ</dc:creator>
      <pubDate>Sat, 21 Mar 2026 08:55:13 +0000</pubDate>
      <link>https://forem.com/manhvanvu/replace-json-by-toon-in-phoenix-channel-gi0</link>
      <guid>https://forem.com/manhvanvu/replace-json-by-toon-in-phoenix-channel-gi0</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;I'm build a realtime system based on Phoenix Channel. After some workload/benchmark test, I realized encode/decode task in JSON is quite expensive tasks for our system 🤔&lt;/p&gt;

&lt;p&gt;I have replaced Jason (default Phoenix JSON lib) by native JSON and save tons of CPU and memory resource. I quite happy for this lib but still want to try more and look around.&lt;/p&gt;

&lt;p&gt;One day, I found TOON format that can save traffic cost for our system.&lt;/p&gt;

&lt;h2&gt;
  
  
  TOON format
&lt;/h2&gt;

&lt;p&gt;I found this is quite fun because I saw people use for saving tokens (and money) and improve accuracy for LLM. &lt;/p&gt;

&lt;p&gt;The documents of &lt;a href="https://github.com/toon-format/toon" rel="noopener noreferrer"&gt;TOON&lt;/a&gt; said can save 30-60% tokens, I found an interested thing in here, I can save bandwidth for network (and my server can serve more users). I also found some benchmarks say parsing TOON format is faster than JSON, that's nice 👌&lt;/p&gt;

&lt;p&gt;Another interested thing is TOON is compatible with JSON, so that enough for me deep dive to TOON.&lt;/p&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Very friendly for dev (like yaml)&lt;/li&gt;
&lt;li&gt;Reduce size of data (much more than JSON if use array of simple objects)&lt;/li&gt;
&lt;li&gt;Don't need to convert to other format and save tokens if you integrate with LLM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some libraries is not optimized&lt;/li&gt;
&lt;li&gt;Not reduce size of you use nested objects&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Look a way to apply Phoenix Channel
&lt;/h2&gt;

&lt;p&gt;After look to Phoenix implement I see Phoenix is using JSON quite simple. A module for serializing between JSON and Elixir type.&lt;/p&gt;

&lt;p&gt;We have two way to replace JSON in Phoenix, one is json library, another is serializer lib for only websocket connections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Change JSON Library
&lt;/h3&gt;

&lt;p&gt;This module use other library. We can change encoder/decoder just by set config in &lt;code&gt;config.exs&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;config:&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="c1"&gt;# used native JSON lib (built-in Erlang) for save cpu &amp;amp; memory&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:phoenix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:json_library&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, I went to find libs that support to encode/decode between string and Elixir type.&lt;/p&gt;

&lt;p&gt;I asked on &lt;a href="https://elixirforum.com/t/how-to-replace-json-with-toon/74581/19" rel="noopener noreferrer"&gt;elixir forum&lt;/a&gt; and &lt;code&gt;toon_ex&lt;/code&gt; is library the member in forum suggested for me, that's nice because &lt;code&gt;toon_ex&lt;/code&gt; is quite similar to Jason library.&lt;/p&gt;

&lt;h3&gt;
  
  
  Change Serializer Module
&lt;/h3&gt;

&lt;p&gt;If we need keep other JSON apis or LiveView, we can update serializer module only for websocket connections.&lt;/p&gt;

&lt;p&gt;The first we need to implement a custom serializer like:&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;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;CustomSerializer&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@behaviour&lt;/span&gt; &lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Serializer&lt;/span&gt;

  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;Broadcast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Reply&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fastline&lt;/span&gt;
  &lt;span class="o"&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;In &lt;code&gt;endpoint.ex&lt;/code&gt; file we add our serializer module to socket like:&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;socket&lt;/span&gt; &lt;span class="s2"&gt;"/socket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MyAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;ChannelSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;websocket:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="ss"&gt;connect_info:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:peer_data&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="ss"&gt;serializer:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;CustomSerializer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 2.0.0"&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="ss"&gt;longpoll:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now I can go further.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply TOON to Phoenix
&lt;/h2&gt;

&lt;p&gt;Because TOON is compatible with JSON then I though I can replace JSON lib for both Phoenix LiveView and Phoenix Channel. For LiveView it need to integrate with JS in client then I chose to start with Channel first.&lt;/p&gt;

&lt;p&gt;After some hours to try &lt;code&gt;toon_ex&lt;/code&gt; I found too many bugs and missed a function &lt;code&gt;encode_to_iodata&lt;/code&gt; for Phoenix, I decided improve this.&lt;/p&gt;

&lt;p&gt;Now &lt;code&gt;toon_ex&lt;/code&gt; can run smoothly, I go to integrate with Phoenix and build a client to test.&lt;/p&gt;

&lt;p&gt;In client, I built a Websocket client for Phoenix Channel, I also use improved &lt;code&gt;toon_ex&lt;/code&gt; library. It works perfectly.&lt;/p&gt;

&lt;p&gt;I try with some complex types and this runs smoothly.&lt;/p&gt;

&lt;p&gt;In my system, Phoenix Channel run in a different app then I don't need to update LiveView this time.&lt;/p&gt;

&lt;p&gt;I published my PoC and my updated &lt;code&gt;toon_ex&lt;/code&gt; at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/manhvu/toon_poc" rel="noopener noreferrer"&gt;My PoC repo&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://hex.pm/packages/toon_ex" rel="noopener noreferrer"&gt;Hex package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/manhvu/toon_ex" rel="noopener noreferrer"&gt;ToonEx repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;TOON format is still new and in Elixir ecosystem it's not good enough, I saw on hex.pm just has two libraries and these are not mature.&lt;/p&gt;

&lt;p&gt;Phoenix quite easy framework for deep dive and see what happen. From my view the maintainers of the framework can use serializer as plug like other module then user can easy to use with other type than JSON (like MessagePack,...).&lt;/p&gt;

&lt;p&gt;I will continue to try to add TOON for LiveView and update this topic later.&lt;/p&gt;

&lt;p&gt;I add some features for TOON and published on &lt;a href="https://hex.pm/packages/toon_ex" rel="noopener noreferrer"&gt;hex.pm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>toon</category>
      <category>phoenix</category>
      <category>elixir</category>
    </item>
    <item>
      <title>App power by LLM and Tools in Elixir</title>
      <dc:creator>Mạnh Vũ</dc:creator>
      <pubDate>Mon, 03 Nov 2025 12:07:26 +0000</pubDate>
      <link>https://forem.com/manhvanvu/app-power-by-llm-and-tools-in-elixir-2bgb</link>
      <guid>https://forem.com/manhvanvu/app-power-by-llm-and-tools-in-elixir-2bgb</guid>
      <description>&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;Recently, I wrote an example for my friend can see and understand how to apply AI to web application. He have used ChatGPT and think AI still unstable &amp;amp; not good enough result.&lt;/p&gt;

&lt;p&gt;Actually, He just use chat mode and provides some basic guides for tasks. He doesn't how to declare rules &amp;amp; guide for AI can understand more about task.&lt;/p&gt;

&lt;p&gt;To help him to understand how AI can process data in an application, I wrote an example by Elixir.&lt;/p&gt;

&lt;p&gt;For save time, I used Phoenix + Ash(with AshAi) + Reactor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concept of application
&lt;/h2&gt;

&lt;p&gt;I made an Elixir application to help process estimate tour cost from raw data.&lt;/p&gt;

&lt;p&gt;I used local LLM &amp;amp; Google Gemini 2.5 Pro for developing.&lt;/p&gt;

&lt;p&gt;For integrating AI with application, I write 2 flows.&lt;/p&gt;

&lt;p&gt;The first one is using AI for extracting data from raw request (text) and get necessary information for later task. After that application have enough information for collecting suppliers then estimate cost for tour. In this flow, data can be processed without any action from user. AI cost for this flow can be optimized easily.&lt;/p&gt;

&lt;p&gt;Some photo from screen of app:&lt;/p&gt;

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

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

&lt;p&gt;The second one is using chat flow for interactive with user for ask requirement and get supported from tools to query local data. This flow is flexible but take time &amp;amp; cost more than the first one.&lt;/p&gt;

&lt;p&gt;Some photo from screen of app:&lt;/p&gt;

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

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

&lt;h2&gt;
  
  
  How I integrate AI with Elixir application
&lt;/h2&gt;

&lt;p&gt;I used Ash framework with AshAi extension &amp;amp; Reactor for fast developing application. This cost 3-4 days for integrating AI (my first app that included AI) and 2 days for declarative domain (database schemas) by Ash and UI for show and input data.&lt;/p&gt;

&lt;p&gt;Ash framework is powerful framework if you want to save time and build extensible things.&lt;br&gt;
Recently, I use Ash framework for almost task with database. I don't want to work with database &amp;amp; query too much!&lt;/p&gt;

&lt;p&gt;When making this application, I explored Reactor is very nice thing when work with flow of actions. Reactor help me easily define complex flow that can rollback, retry and compose with other flows.&lt;/p&gt;

&lt;p&gt;For AshAi, I think is nice but need to improve documents and give community more examples. Don't see any way for export directly tools for using directly in LangChain.&lt;/p&gt;

&lt;p&gt;An other library that I tried is Jido, I like style of Jido than AshAi and Reactor but this lib still so young and need to improve for support LangChain better.&lt;/p&gt;

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

&lt;p&gt;Integration AI to Elixir application is simple. For me, I just need to understand how tools are called in LangChain and how to write right guides to help AI can understand task and tools.&lt;/p&gt;

&lt;p&gt;Elixir is grown fast and has a lot of nice libraries and frameworks from community.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>llm</category>
      <category>ash</category>
    </item>
    <item>
      <title>Solve alias problem in Elixir</title>
      <dc:creator>Mạnh Vũ</dc:creator>
      <pubDate>Fri, 24 Oct 2025 03:04:00 +0000</pubDate>
      <link>https://forem.com/manhvanvu/solve-alias-problem-in-elixir-ml9</link>
      <guid>https://forem.com/manhvanvu/solve-alias-problem-in-elixir-ml9</guid>
      <description>&lt;p&gt;Recently, I must type too much for &lt;code&gt;alias Module&lt;/code&gt; for using short name in code(Module name in Elixir is quite long). Problem here is I need to repeat that action over and over.&lt;/p&gt;

&lt;p&gt;When posted a proposal for solve this problem I receives an advice very valuation from community. I repost the idea in here for people can read and solve problem if that problem is like mine.&lt;/p&gt;

&lt;p&gt;Define a macro and function for supporting centric all aliases like:&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;Namespace&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@moduledoc&lt;/span&gt; &lt;span class="sd"&gt;"""
    This module provides a way to define a namespace for a set of modules.
    It can be used to define a set of modules that share a common prefix.

    This version only support for native atom not a alias.

    # usage
    ```


    use Namespace, DataSpace


    ```
  """&lt;/span&gt;

  &lt;span class="k"&gt;defmacro&lt;/span&gt; &lt;span class="n"&gt;__using__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;namespace&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;Namespace&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;Macro&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand_once&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;__ENV__&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;def&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;Suppliers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="kn"&gt;quote&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Domains&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Suppliers&lt;/span&gt;
      &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Suppliers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Hotel&lt;/span&gt;
      &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Suppliers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Transport&lt;/span&gt;
      &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Suppliers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Restaurant&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Customers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="kn"&gt;quote&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Structs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Customers&lt;/span&gt;
      &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Customers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Address&lt;/span&gt;
      &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Customers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Details&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In other module I can use like:&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;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Processor&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;Namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Suppliers&lt;/span&gt;

&lt;span class="o"&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;This way help me provide a centric way and clean code for alias and avoid to repeat add &lt;code&gt;alias ...&lt;/code&gt; action.&lt;/p&gt;

&lt;p&gt;Downside of this way is compiler is warning if an &lt;code&gt;alias&lt;/code&gt; is unused.&lt;/p&gt;

&lt;p&gt;Original idea is from &lt;a href="https://elixirforum.com/t/proposal-add-support-namespace-for-module/72998/6" rel="noopener noreferrer"&gt;post in Elixir community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>Vibe Coding with Elixir/Phoenix</title>
      <dc:creator>Mạnh Vũ</dc:creator>
      <pubDate>Thu, 18 Sep 2025 08:49:22 +0000</pubDate>
      <link>https://forem.com/manhvanvu/vibe-coding-with-elixirphoenix-3o7i</link>
      <guid>https://forem.com/manhvanvu/vibe-coding-with-elixirphoenix-3o7i</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;I run a startup with 4 members, a full time member and 3 others are part-time (one support for business strategy &amp;amp; documents). It's so hard for us with a ton of tasks (we build a quite big system with numbers of services). We try some ways for speed up development time but still overload for us (limited resources).&lt;/p&gt;

&lt;p&gt;Before go to vibe coding I used Copilot (premium version) for almost thing is suggestion and it quite good for this, much better than Language Server. From my view, Copilot can improve my performance around 10-15%.&lt;/p&gt;

&lt;p&gt;When we start to build DiSport project, LLM model is still in early stage and limitations for coding (especially for Elixir). After couple years, I see it a lot of improvements for coding and vibe coding is booming then I went to try vibe coding with our project (write by Elixir &amp;amp; Flutter).&lt;/p&gt;

&lt;h2&gt;
  
  
  Go to vibe coding
&lt;/h2&gt;

&lt;p&gt;The first try, I start with our web site &lt;a href="https://ohhi.vn" rel="noopener noreferrer"&gt;https://ohhi.vn&lt;/a&gt;. I tried to improve UI for people can easy to read our post on that. I setup a  AI agent with Gemini from Google and setup MCP servers for that. After couple hours our site have totally new UI with much more beautiful &amp;amp; look modern. Agent can run test, migration &amp;amp; compile then fix bugs from our project. Some time it make mistake and loop then a fix with small change then agent can continues task.&lt;/p&gt;

&lt;p&gt;The second try, I go to with both Claude Code &amp;amp; Gemini. I see Claude is good for integrating with Zed and CLI is run faster than Gemini (but Gemini has nice &amp;amp; easy to track change from agent). About Elixir Claude Code is done good than Gemini but I think with UI and work with HEEX template Gemini do better.&lt;/p&gt;

&lt;p&gt;The third try, I try to build all new service by Claude Code, I don't give agent run full script just step by step for easy tracking what happen. I make new Phoenix project and add &lt;a href="https://hexdocs.pm/tidewave/installation.html" rel="noopener noreferrer"&gt;Tidewave&lt;/a&gt;, &lt;a href="https://hexdocs.pm/usage_rules" rel="noopener noreferrer"&gt;UsageRules&lt;/a&gt; and config Zed for this repo. Agent is speedup my process much more than anything else, I think at least x3 time when compare with I coding without agent and just using Copilot for suggestion.&lt;/p&gt;

&lt;p&gt;I have plan to build our agent for other task by &lt;a href="https://hexdocs.pm/jido/readme.html" rel="noopener noreferrer"&gt;Jido&lt;/a&gt; and think again about new way for user interactive with our application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost of vibe coding
&lt;/h2&gt;

&lt;p&gt;I try to build a local LLM with my old PC + couple of GPUs (24 VRAM) that is enough for LLM with 30B (Q4) to run. It's fast for generating new skeleton project but for big project like our it too slow then I go to third party services. For who want to build local LLM I think LLM with 70B enough for almost tasks.&lt;/p&gt;

&lt;p&gt;For Gemini, it's quite expensive for us. I spend about around 300$ for improve UI task.&lt;/p&gt;

&lt;p&gt;For Claude Code, I see it's cheap than Gemini.&lt;/p&gt;

&lt;p&gt;I also try other providers but these are limited their services for Vietnam then I don't use!&lt;/p&gt;

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

&lt;p&gt;Vibe coding is good for experience dev &amp;amp; help any company can save cost &amp;amp; time to develop product. Startups with limited resources are get a lot of benefit from vibe coding.&lt;/p&gt;

&lt;p&gt;From my view, vibe coding improve performance at least 10 times for common tasks also help for dev can summarize &amp;amp; understand big project significant faster. I also reduce number of documents because AI can help to generate that any time!&lt;/p&gt;

&lt;p&gt;Vibe coding is totally change our way to develop prod but it has a downside that is for new members (with limited knowledge about system &amp;amp; skills is weak) they can't catch up process &amp;amp; other members.&lt;/p&gt;

&lt;p&gt;Configs I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gemini 2.5 Pro&lt;/li&gt;
&lt;li&gt;Claude Code Sonet 4&lt;/li&gt;
&lt;li&gt;Zed IDE&lt;/li&gt;
&lt;li&gt;LM Studio for host local LLM on PC (AMD 3700X, 64GB RAM, 2 x Nvidia 3060 12G)&lt;/li&gt;
&lt;li&gt;Dev machine Macbook Pro 14 M1 Pro + 16GB RAM&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>elixir</category>
      <category>phoenix</category>
      <category>vibecoding</category>
    </item>
    <item>
      <title>Server Side Render vs Client Side Render - My POV</title>
      <dc:creator>Mạnh Vũ</dc:creator>
      <pubDate>Thu, 14 Aug 2025 04:56:21 +0000</pubDate>
      <link>https://forem.com/manhvanvu/server-side-render-vs-client-side-render-my-pov-3m5i</link>
      <guid>https://forem.com/manhvanvu/server-side-render-vs-client-side-render-my-pov-3m5i</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Look back a little of bit, we have several decades with hypertext, from static site to web3 (still too early stage).&lt;/p&gt;

&lt;p&gt;I still remember first time I used computer and open a web site. In that time, all things in site is static files with hypertext link. Today, site is wonderful thing with ton of animations &amp;amp; medias.&lt;/p&gt;

&lt;p&gt;Web go from static site to server side render(SSR) to client side render(CSR). Today, sound like we back to SSR. I point some different things in this post.&lt;/p&gt;

&lt;p&gt;Before go further, I will explain a little of bit about SSR &amp;amp; SCR.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSR
&lt;/h2&gt;

&lt;p&gt;SSR is bring web to a dynamic world, we can render a site with dynamic content &amp;amp; more useful things. PHP is a famous web development language using SSR.&lt;/p&gt;

&lt;p&gt;In the first time, web server with SSR is always render full HTML and work with pure HTTP. Now, SSR support transport content by Websocket &amp;amp; just send different content to client.&lt;/p&gt;

&lt;p&gt;Remember in here, we work directly with data and small number of public APIs (almost is HTTP GET/POST).&lt;/p&gt;

&lt;p&gt;In SSR, frontend(FE) and backend(BE) are united.&lt;/p&gt;

&lt;p&gt;Today, some new framework like Phoenix has ton of improvement like just render different HTML and send to client (over Websocket) to update.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSR
&lt;/h2&gt;

&lt;p&gt;CSR is bring web to a higher level, web has much more interact site with tons of medias &amp;amp; animations.&lt;/p&gt;

&lt;p&gt;In CSR way, frontend(FE) and backend(BE) are separated. Between BE &amp;amp; FE is an API layer (Rest API is the most common thing for CSR).&lt;/p&gt;

&lt;p&gt;CSR reduce workload for server but for first time loading site it much more data need to load.&lt;/p&gt;

&lt;p&gt;Remember CSR is better for scale but bring a lot of works for create &amp;amp; maintain APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSR vs CSR
&lt;/h2&gt;

&lt;p&gt;Now, I try to compare SSR and CSR. I will add some uses for easy to understand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Development phase:
&lt;/h3&gt;

&lt;p&gt;In this phase, SSR is much more simple than CSR. SSR doesn't need to thing to much for design &amp;amp; adding Api layer. A fullstack dev can work smoothly from FE to BE.&lt;/p&gt;

&lt;p&gt;A lot of api that mean we need more work to check compatible &amp;amp; security.&lt;/p&gt;

&lt;p&gt;If you have a multi teams work same project, CSR is better for separating work between teams.&lt;/p&gt;

&lt;p&gt;If you develop site with complex state, SSR is matched with you (doesn't require to sync state between server and client).&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment phase:
&lt;/h3&gt;

&lt;p&gt;CSR bring complex to deploy we need to setup &amp;amp; verify thing like api gateway &amp;amp; api version.&lt;/p&gt;

&lt;p&gt;For site need to get data from several BEs, CSR is the best choice.&lt;/p&gt;

&lt;p&gt;With SSR we need more resource in server side.&lt;/p&gt;

&lt;p&gt;CSR is easy to scale &amp;amp; isolation but its downside is hard to troubleshooting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Maintain phase:
&lt;/h3&gt;

&lt;p&gt;CSR has more APIs to maintain.&lt;br&gt;
SSR almost code run in server side then we don't need care about compatible.&lt;/p&gt;

&lt;p&gt;Now we have ton of devices, I will try to figure out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;p&gt;CSR has a lot of work to make sure sites is safe.&lt;/p&gt;

&lt;p&gt;SSR is much more simple than CSR.&lt;/p&gt;

&lt;h3&gt;
  
  
  PC/Laptop
&lt;/h3&gt;

&lt;p&gt;In this type of device, good resource (RAM/CPU) and user behaviors (open a site in long time for work) then CSR is good for this.&lt;/p&gt;

&lt;p&gt;SSR is good for short live site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mobile
&lt;/h3&gt;

&lt;p&gt;Sound like CSR has it limitations, bandwidth of network is an issue. Limited resource of low end device can impact performance for CSR.&lt;/p&gt;

&lt;p&gt;User behavior (short live) is good for SSR (and reduce code 4/5G for user).&lt;/p&gt;

&lt;h3&gt;
  
  
  IoT
&lt;/h3&gt;

&lt;p&gt;I think CSR has a big issue in here, not much resource for CSR can run.&lt;/p&gt;

&lt;p&gt;SSR is good for IoT, it doesn't require good resource for loading sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Today web tech
&lt;/h2&gt;

&lt;p&gt;Both SSR &amp;amp; CSR have use new tech to improve like using websocket for reduce data need to transfer between server &amp;amp; client). &lt;/p&gt;

&lt;p&gt;SSR has improve the way of render like just check changed state and render different contend and update it in client side.&lt;/p&gt;

&lt;p&gt;CSR has reduce data (js/css) need to load in the first time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conslusion
&lt;/h2&gt;

&lt;p&gt;SSR is better in small team (with fullstack devs), small product and large range of devices. Better for stateful site.&lt;/p&gt;

&lt;p&gt;CSR is better in large site (complex &amp;amp; scalable site) or web app with workload run in client side.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>webdev</category>
      <category>ssr</category>
      <category>csr</category>
    </item>
    <item>
      <title>Ash framework and our journey to it!</title>
      <dc:creator>Mạnh Vũ</dc:creator>
      <pubDate>Fri, 25 Jul 2025 14:35:25 +0000</pubDate>
      <link>https://forem.com/manhvanvu/ash-and-our-journey-to-it-4n43</link>
      <guid>https://forem.com/manhvanvu/ash-and-our-journey-to-it-4n43</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;We're a startup with all our system with Elixir (except mobile app).&lt;/p&gt;

&lt;h2&gt;
  
  
  Our journey
&lt;/h2&gt;

&lt;p&gt;We start build our MVP with Elixir from craft with our knowledge. We have a good background about Erlang but still have a lot of things for us. We will talk about some rounds we faced with.&lt;/p&gt;

&lt;p&gt;First round, we start with almost built-in library of Elixir &amp;amp; Erlang (we came from Erlang world). Still fast for us when compare time to develop with other tech stack like Node or Go (Go cannot match with Elixir for build a realtime &amp;amp; reactor system except performance!). In this time, we use Ets for memcache (we have built a cache library based on Ets) and Mnesia for storage (or things that need transaction). Yep, it's nature with dynamic type and we free of mind to work with that. It is fast lane for us, PoC is done so quick! In this time, we put all apps in an umbrella project.&lt;/p&gt;

&lt;p&gt;Second round, we decouple our system for better development phase &amp;amp; can get ready for scale in the future. Yes, dynamic type + cluster (built-in) help us a lot! No other things like Elixir and it ecosystem, we can decouple our system in a week! (benefit from distributed system) Now we have dynamic cluster on K8s, nice job!&lt;/p&gt;

&lt;p&gt;Third round, we start using Ecto + Postgres for better performance &amp;amp; other benefits like code generation, form, validate,... We still happy with Phoenix/Ecto but we see a problem that is we need to write boilerplate code for query and our Apis. We don't use regular Api like Rest Api because it not match with our realtime system and overload for header, security check,...&lt;/p&gt;

&lt;p&gt;Fourth round, we want to try a new thing to reduce time to develop and think about Domain Driven Design system. We changed our system several times and see a problem, we need to reduce change business logic and presentation layer. We have a look with Ash framework and try it. It's so amazing thing for us. Ash framework uses declarative for code generation. From my view, that way help us to reduce time for write &amp;amp; test our code. Ash is extensible that is important thing for us. Ash and LiveView are nice things we found when work with Elixir ecosystem!&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of us when work with Ash
&lt;/h2&gt;

&lt;p&gt;Ash framework has a lot of other benefits but in here we only talk things we used and got benefits.&lt;/p&gt;

&lt;p&gt;The first, we can easy to move from this persist storage system to other. In Ecto we can do that but only with SQL type, in Ash we can build our storage to any type of storage system. Currently, we using Postgres but in the near future we need to move to other things like Cassandra, ClickHouse,... when work with Ash we don't need to rework too much!&lt;/p&gt;

&lt;p&gt;The second, we don't use regular api like Rest api then we need to add a layer for converting from this type of data to other type, with Ash we can easy to create and extension for our api and reduce boilerplate code and have us easy to trace any issue if our system have.&lt;/p&gt;

&lt;p&gt;The third, with Ash, we keep our system around DDD style for expert domain can understand &amp;amp; talk with dev.&lt;/p&gt;

&lt;h2&gt;
  
  
  Downside of Ash
&lt;/h2&gt;

&lt;p&gt;Yes, Ash have a downside for us!&lt;/p&gt;

&lt;p&gt;Need to learn (new style for us but not much because we have worked with Ecto before). &lt;/p&gt;

&lt;p&gt;Error that raised by Ash also is a thing that made us to think because it is raised by macro then we need time to understand this (actually, Ash has Spark library and it raise error quite good).&lt;/p&gt;

&lt;p&gt;Run slow than normal when we work directly with Ecto.&lt;/p&gt;

&lt;p&gt;We will come back and talk more about Ash. Thank you for reading!&lt;/p&gt;

</description>
      <category>ash</category>
      <category>elixir</category>
    </item>
    <item>
      <title>Zed - New universal IDE for me</title>
      <dc:creator>Mạnh Vũ</dc:creator>
      <pubDate>Fri, 25 Jul 2025 03:04:06 +0000</pubDate>
      <link>https://forem.com/manhvanvu/zed-new-ide-for-me-1dj4</link>
      <guid>https://forem.com/manhvanvu/zed-new-ide-for-me-1dj4</guid>
      <description>&lt;p&gt;Totally, I have new IDE that is the best fit for me!&lt;/p&gt;

&lt;p&gt;Before Zed, I usually use VS Code for work. It's quite good for universal IDE if you don't need to care about your computer's resource.&lt;/p&gt;

&lt;p&gt;Sometimes, I tried other text editor/IDE but no one is good enough me almost because lack of extensions and language server, I usually work with two or three languages in same time. I have tried Neovim &amp;amp; Emacs  (actually, I worked with Emacs for Erlang before) but that is not match for my work flow.&lt;/p&gt;

&lt;p&gt;Zed is the best fit for me, it can keep my mindset from time when I worked with VS Code, move from VS Code to Zed without effort that is nice!&lt;/p&gt;

&lt;p&gt;I can get almost things (extensions, LS) like when I worked with VS Code and save tons of resource for me. When working with VS Code I opened 4-5 repos in same times and 2-3 languages and switch between them for me my Macbook Pro 14' with 16GB almost full of RAM (and around &amp;gt;10GB swap disk) and 10-15% cpu for VS Code processes. Now, with Zed I have almost no swap disk and almost zero cpu for Zed, that's amazing! After switch to Zed, I have more resources and battery life for other things!&lt;/p&gt;

&lt;p&gt;An other things, you still using Copilot and other AI for suggesting &amp;amp; solve problems in IDE!&lt;/p&gt;

&lt;h2&gt;
  
  
  Resource before &amp;amp; after
&lt;/h2&gt;

&lt;p&gt;My Macbook Pro 14 (M1 Pro + 16GB Ram) resource before &amp;amp; after:&lt;br&gt;
Before: Ram 80-85% + 10-15 GB swap file. CPU 20-30%&lt;br&gt;
After: Ram 65-72% + 900MB swap file. CPU 10-15%&lt;/p&gt;

&lt;p&gt;(Note: I usually work with 4-7 repos in same time with Elixir + Dart/Flutter).&lt;/p&gt;

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

&lt;p&gt;Yes, Zed save a lot resources for me and electric bill (and save Earth)!&lt;/p&gt;

</description>
      <category>zed</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Migrate to Phoenix 1.8 guide</title>
      <dc:creator>Mạnh Vũ</dc:creator>
      <pubDate>Mon, 28 Apr 2025 11:33:13 +0000</pubDate>
      <link>https://forem.com/manhvanvu/migrate-to-phoenix-18-rc-version-olc</link>
      <guid>https://forem.com/manhvanvu/migrate-to-phoenix-18-rc-version-olc</guid>
      <description>&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;Phoenix is amazing web framework. Now Phoenix released new version, it's RC version but I think it's ok for try a new thing that will bring for us some benefits with daisyUI for supporting add themes &amp;amp; new features (like auth, scopes,...). For more info about v1.8 release please go to this &lt;a href="https://phoenixframework.org/blog/phoenix-1-8-released" rel="noopener noreferrer"&gt;blog&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;You can install Phoenix follow regular cmd:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix archive.install hex phx_new 1.8.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Migration
&lt;/h2&gt;

&lt;p&gt;This guide help you migrate Phoenix from 1.7 to 1.8 version&lt;/p&gt;

&lt;p&gt;Before continue, we need create a simple Phoenix app with new version for copy some scripts to our project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix phx.new &lt;span class="nt"&gt;--no-ecto&lt;/span&gt; hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update assets folder
&lt;/h3&gt;

&lt;p&gt;New version of Phoenix has some new scripts, folders &amp;amp; files look like:&lt;/p&gt;

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

&lt;p&gt;If you don't have any customized script in old project just override all files from new Phoenix app, excepted one file is &lt;code&gt;app.css&lt;/code&gt; need to update a path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Update this follow your app */&lt;/span&gt;
&lt;span class="k"&gt;@source&lt;/span&gt; &lt;span class="s1"&gt;"../../lib/hello_web"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update layouts
&lt;/h3&gt;

&lt;p&gt;Now Phoenix uses single layout, we can remove &lt;code&gt;app.html.heex&lt;/code&gt; in template folder of Layouts.&lt;/p&gt;

&lt;p&gt;Copy &lt;code&gt;root.html.heex&lt;/code&gt; &amp;amp; &lt;code&gt;layouts.ex&lt;/code&gt; from new app or update your old code.&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;Layouts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="n"&gt;flash&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;@flash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="ss"&gt;:breadcrumb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;.&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sx"&gt;~p"/"&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;HOME&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/.&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="ss"&gt;:breadcrumb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="no"&gt;Layouts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't need navigation in your pages you just need to add &lt;code&gt;&amp;lt;Layouts.flash_group flash={@flash} /&amp;gt;&lt;/code&gt; to top of your template.&lt;/p&gt;

&lt;p&gt;Some other modules like router maybe has plug put_root_layout like &lt;code&gt;put_root_layout, {YourApp.LayoutView, :root}&lt;/code&gt; please update to new &lt;code&gt;{YourApp.Layouts, :root}&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update core_components.ex
&lt;/h3&gt;

&lt;p&gt;We need update a little of bit follow new thing in the new version of Phoenix or if you don't have any customized code in here just copy from new app then update module name.&lt;/p&gt;

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

&lt;p&gt;You can see from above photo we need remove &lt;code&gt;phx-feedback-for&lt;/code&gt; &amp;amp; update &lt;code&gt;errors&lt;/code&gt; for input component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update app_web.ex
&lt;/h3&gt;

&lt;p&gt;Now using a single layout we can remove &lt;code&gt;layout&lt;/code&gt; option from live_view function in AppWeb from:&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="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;LiveView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;layout:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;AppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Layouts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:app&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to:&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="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;LiveView&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And add an alias for Layouts to &lt;code&gt;html_helpers&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;defp&lt;/span&gt; &lt;span class="n"&gt;html_helpers&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="kn"&gt;quote&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="c1"&gt;# ...&lt;/span&gt;

      &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;LiveView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;JS&lt;/span&gt;
      &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;AppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Layouts&lt;/span&gt;

      &lt;span class="c1"&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;If you don't have any custom code in this module, you can copy from new app template and update module name.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update config.exs
&lt;/h3&gt;

&lt;p&gt;You need to update config for TailwindCSS follow:&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;config&lt;/span&gt; &lt;span class="ss"&gt;:esbuild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;version:&lt;/span&gt; &lt;span class="s2"&gt;"0.17.11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;hello:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="ss"&gt;args:&lt;/span&gt;
      &lt;span class="sx"&gt;~w(js/app.js --bundle --target=es2022 --outdir=../priv/static/assets/js --external:/fonts/* --external:/images/*)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;cd:&lt;/span&gt; &lt;span class="no"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../assets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="ss"&gt;env:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="s2"&gt;"NODE_PATH"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../deps"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:tailwind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;version:&lt;/span&gt; &lt;span class="s2"&gt;"4.0.9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;hello:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="ss"&gt;args:&lt;/span&gt; &lt;span class="sx"&gt;~w(
      --input=assets/css/app.css
      --output=priv/static/assets/css/app.css
    )&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;cd:&lt;/span&gt; &lt;span class="no"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;__DIR__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Taiwind's config &amp;amp; Relative paths are changed! Need make sure you update correct paths for new version.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update mix.exs
&lt;/h3&gt;

&lt;p&gt;We need update deps to new version:&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;defp&lt;/span&gt; &lt;span class="n"&gt;deps&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:phoenix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.8.0-rc.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;override:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:phoenix_html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 4.1"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:phoenix_live_reload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only:&lt;/span&gt; &lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:phoenix_live_view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.0.9"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:phoenix_live_dashboard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.8.3"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:esbuild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;runtime:&lt;/span&gt; &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:tailwind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;runtime:&lt;/span&gt; &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.5"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:heroicons&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="ss"&gt;github:&lt;/span&gt; &lt;span class="s2"&gt;"tailwindlabs/heroicons"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="ss"&gt;tag:&lt;/span&gt; &lt;span class="s2"&gt;"v2.1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="ss"&gt;sparse:&lt;/span&gt; &lt;span class="s2"&gt;"optimized"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="ss"&gt;app:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="ss"&gt;compile:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="ss"&gt;depth:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="c1"&gt;# ...&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;listeners: [Phoenix.CodeReloader]&lt;/code&gt; to &lt;code&gt;def project&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Update &lt;code&gt;Gettext&lt;/code&gt; to new version if needed. Remove &lt;code&gt;finch&lt;/code&gt; deps because now Phoenix using &lt;code&gt;req&lt;/code&gt; instead if you need to use HTTP client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update your templates
&lt;/h3&gt;

&lt;p&gt;Some core components of Phoenix are changed or remove, you need to update your templates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify &amp;amp; Test
&lt;/h3&gt;

&lt;p&gt;Run &lt;code&gt;mix assets.setup&lt;/code&gt; &amp;amp; &lt;code&gt;mix assets.build&lt;/code&gt; to test our update.&lt;/p&gt;

&lt;p&gt;Test simple daisyUI component from &lt;a href="https://daisyui.com/docs/use/" rel="noopener noreferrer"&gt;daisyUI&lt;/a&gt; to make sure daisyUI is included in our app.&lt;/p&gt;

&lt;p&gt;Note: Phoenix bring some new features you can try like: scopes, magic link,...&lt;/p&gt;

&lt;p&gt;This is my guide based on my migration our projects to Phoenix 1.8 for using daisyUI. I hope it can help you!&lt;/p&gt;

&lt;p&gt;Updated: Changed from RC version to official release.&lt;/p&gt;

</description>
      <category>phoenixwebframework</category>
      <category>elixir</category>
      <category>daisyui</category>
    </item>
    <item>
      <title>Solve problem for dynamic Elixir cluster - ClusterHelper</title>
      <dc:creator>Mạnh Vũ</dc:creator>
      <pubDate>Sun, 23 Mar 2025 07:45:22 +0000</pubDate>
      <link>https://forem.com/manhvanvu/solve-problem-for-dynamic-elixir-cluster-clusterhelper-5dh4</link>
      <guid>https://forem.com/manhvanvu/solve-problem-for-dynamic-elixir-cluster-clusterhelper-5dh4</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;I'm deploying a cluster of Elixir with 5 to 7 nodes (dev env, in prod each node is a deployment and have 1 or more replicas) on Kubernetes(K8s), our system is using EasyRpc (a :erpc wrapper) in internal Elixir cluster for save time to develop. It's perfect for case static/fixed cluster but hard for case run a Elixir cluster(dynamic cluster) on K8s. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why it so hard?
&lt;/h2&gt;

&lt;p&gt;K8s is designed for dynamic things like web service (usually, stateless &amp;amp; not join a cluster like Elixir cluster). IP and hostname of Pod is dynamic it's changed every time pod is restarted an node name of Elixir will be changed follow. It's not match with our system. Of course, we can workaround by using headless service or using Gossip strategy of :libcluster then using prefix of app name for check it in runtime but it's more complicated and sound not good for thing work well with distributed system like Elixir.&lt;/p&gt;

&lt;p&gt;Of course, we can use other thing like broker or bus message or wrap to gRPC/Rest API but that make more complicated for development &amp;amp; deployment. We want to use rpc of Elixir for fast develop (benefit from dynamic type language).&lt;/p&gt;

&lt;h2&gt;
  
  
  Our way
&lt;/h2&gt;

&lt;p&gt;We made a library has name &lt;a href="https://hex.pm/packages/cluster_helper" rel="noopener noreferrer"&gt;ClusterHelper&lt;/a&gt; to map role to Elixir node name in runtime. If a node join to cluster it will auto update all roles of that node for other nodes in cluster. The library run in every Elixir node in our cluster, now we can lookup Elixir node name by role. Each role has one or more nodes depended in our scale strategy.&lt;/p&gt;

&lt;p&gt;In our system, a node can have one or several roles and a role can have several nodes. Information about roles &amp;amp; nodes are auto synced &amp;amp; cached in every node. &lt;/p&gt;

&lt;p&gt;Based on role can bring for us some benefits like scale in/out easily, we don't need to care about node name of Elixir and how to map it on K8s. It's easy to scale a service by add more nodes for that service.&lt;/p&gt;

&lt;p&gt;We have another library with name &lt;a href="https://hex.pm/packages/easy_rpc" rel="noopener noreferrer"&gt;EasyRpc&lt;/a&gt; help us work smoothly with number of nodes have same a role.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>cluster</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Elixir Macro - How it save time &amp; keep code clean for us</title>
      <dc:creator>Mạnh Vũ</dc:creator>
      <pubDate>Wed, 26 Feb 2025 14:43:32 +0000</pubDate>
      <link>https://forem.com/manhvanvu/elixir-macro-how-it-save-time-keep-code-clean-for-us-mj</link>
      <guid>https://forem.com/manhvanvu/elixir-macro-how-it-save-time-keep-code-clean-for-us-mj</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;I have worked with macro (meta-programming) in C, Delphi &amp;amp; Erlang language but with Elixir it is different, meta-programming in Elixir is really fun &amp;amp; useful.&lt;/p&gt;

&lt;p&gt;You can made a DSL style like Plug and Ecto library in your code if you want it isn't hard.&lt;/p&gt;

&lt;p&gt;For us, we call rpc in Elixir cluster so much. In regular way we can call directly to rpc function in :erpc module (Erlang module) but this way is not convenience because: The first we need code a separated function or module to handle rpc call. The second we always need to find target node to call. And more, if we have a ton of nodes that has same function (for HA &amp;amp; scale out) that is painful for dev is not good about distributed computing.&lt;/p&gt;

&lt;p&gt;For reduce time &amp;amp; also support scale out, I made a wrapper module for rpc call, then other devs just need to &lt;code&gt;use&lt;/code&gt; with some options and use same way with local function. Our wrapper module also support change name of target function just by declare in config file.&lt;/p&gt;

&lt;p&gt;This is very efficient way for us, add rpc just in seconds. Every complex thing is behind the scene.&lt;/p&gt;

&lt;p&gt;I will show how I made this.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I use macro
&lt;/h2&gt;

&lt;p&gt;In config file of project user need to declare like:&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;config&lt;/span&gt; &lt;span class="ss"&gt;:my_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:my_rpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="ss"&gt;node_list:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;# or {mod, fun, args}&lt;/span&gt;
   &lt;span class="ss"&gt;module:&lt;/span&gt; &lt;span class="no"&gt;RemoteModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="ss"&gt;funtion_list:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:function_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:funtion_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:new_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In local module dev need use my module with config option (and other options if needed). When compiling macro will inject to local module with function name in config (target name or new name) then local module or other modules can call rpc look like local function.&lt;/p&gt;

&lt;p&gt;local module example:&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;ModA&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;RpcHelper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;otp_app:&lt;/span&gt; &lt;span class="ss"&gt;:my_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;config:&lt;/span&gt; &lt;span class="ss"&gt;:my_rpc&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# usage&lt;/span&gt;
&lt;span class="no"&gt;ModA&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;function_1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dev can have several remote modules in same app if needed.&lt;/p&gt;

&lt;p&gt;So with macro we can cut down a lot of duplicated code and make it easy for dev who not friendly with distributed system.&lt;/p&gt;

&lt;p&gt;I also provided basic technique for select target node for better scalable and HV.&lt;/p&gt;

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

&lt;p&gt;This way help us so much, reduced time for write call rpc code, keep our code clean and easy to maintain!&lt;/p&gt;

&lt;p&gt;Updated: We published our first release! You can get code from &lt;a href="https://github.com/ohhi-vn/easy_rpc" rel="noopener noreferrer"&gt;Github&lt;/a&gt; or on &lt;a href="https://hex.pm/packages/easy_rpc" rel="noopener noreferrer"&gt;Hex.pm&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>macro</category>
    </item>
    <item>
      <title>PhoenixGenApi a general APIs for Channel - Our way to reduce time &amp; cut down cost for developing backend by Elixir</title>
      <dc:creator>Mạnh Vũ</dc:creator>
      <pubDate>Sat, 01 Feb 2025 03:54:12 +0000</pubDate>
      <link>https://forem.com/manhvanvu/general-apis-for-channel-our-way-to-reduce-time-cut-down-cost-for-developing-backend-by-elixir-11gp</link>
      <guid>https://forem.com/manhvanvu/general-apis-for-channel-our-way-to-reduce-time-cut-down-cost-for-developing-backend-by-elixir-11gp</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;To reduce time &amp;amp; cost of development we develop a new way to call api from mobile to backend system for develop real-time application. That is based on Elixir &amp;amp; Phoenix channel, we call it is phoenix general api(phoenix_gen_api). phoenix_gen_api supports for distributed system that help us don't need to care too much about a lot of things.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it's work
&lt;/h2&gt;

&lt;p&gt;For regular type, has several steps to add a api for mobile or web app. Usually, develop internal functions and add to a interface for other service can call. For this way we need to integrate between service &amp;amp; api gateway, this required effort &amp;amp; time.&lt;/p&gt;

&lt;p&gt;For real-time system, develop a system with a lot of services is complexity for traditional/regular type. Chain of apis from public to target service is thing that made us think about new way.&lt;/p&gt;

&lt;p&gt;phoenix_gen_api, we develop our system with Elixir/Phoenix then we can use distributed system of Elixir (Erlang cluster) and real-time of Phoenix channel for develop api for frontend. Imagine you can cut down some steps in the chain of api from public to target service or automate it!&lt;/p&gt;

&lt;p&gt;Public side, we develop a lib that verify &amp;amp; validate data (from json, go to Phoenix is map type) from public then convert it to Elixir struct for internal use. Request from public need to indicate api that want to call &amp;amp; arguments (all of request is a json object) of its api.&lt;/p&gt;

&lt;p&gt;Internal side, we develop a lib that can understand api &amp;amp; its argument from client, after verify data it will call rpc to target node (service) in internal cluster. Lib also support multi nodes with some kind of load balancing for scaling. Chain from api gateway to target service, we can automate this phase by add auto scan (active/passive) &amp;amp; add new api/updated api to api gateway. After api is added gateway can service public without touch from dev then we don't need to care about integrate too much.&lt;/p&gt;

&lt;p&gt;Validation &amp;amp; security, With Phoenix channel we verify user for each connection (WebSocket) then we just need to care about permission &amp;amp; validation for api. Actually, api gateway just read declared api function and execute it. Dev who develop api need to declare argument type, size/length or use default config of api. We don't need too much effort to integrate for every new api.&lt;/p&gt;

&lt;p&gt;Type of response for phoenix_gen_api, we support regular request/response style (sync), async call (result will send later) &amp;amp; stream for continuing send result to client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefit of phoenix_gen_api
&lt;/h2&gt;

&lt;p&gt;For dev, dev doesn't need to care about how complex of api gateway, how client interact with server just think about data need to receive &amp;amp; send. Data in internal is Elixir struct then can help dev can easy to develop. For some special type of Elixir we add a protocol to convert it between json &amp;amp; struct.&lt;/p&gt;

&lt;p&gt;For devops, sound bad for them, no more task like integration &amp;amp; configuration (include scaling). Dev help them go to retired early 😎&lt;/p&gt;

&lt;p&gt;For startup, save time &amp;amp; cost for build a new system. We don't need to much engineer for build a big system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The future of lib
&lt;/h2&gt;

&lt;p&gt;We are still developing more feature for lib. We will add macro for more convenience &amp;amp; reduce time for declare configuration of api. We will support for lib can be and a app that can run independence by wrap Phoenix &amp;amp; add some functions for verify security of connection.&lt;/p&gt;

&lt;p&gt;We have published our library on &lt;a href="https://hex.pm/packages/phoenix_gen_api" rel="noopener noreferrer"&gt;Hex.pm&lt;/a&gt; or you can get code on &lt;a href="https://github.com/ohhi-vn/phoenix_gen_api" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;We hope can help dev who that develop system by Elixir can have a way to save time &amp;amp; cost.&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;p&gt;// we will comeback and update more details in the future.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>phoenix</category>
      <category>websocket</category>
    </item>
    <item>
      <title>SuperCache - An in-house cache we build for our product</title>
      <dc:creator>Mạnh Vũ</dc:creator>
      <pubDate>Sun, 26 Jan 2025 07:36:03 +0000</pubDate>
      <link>https://forem.com/manhvanvu/supercache-an-in-house-cache-we-build-for-our-product-2d5o</link>
      <guid>https://forem.com/manhvanvu/supercache-an-in-house-cache-we-build-for-our-product-2d5o</guid>
      <description>&lt;h2&gt;
  
  
  SuperCache Intro
&lt;/h2&gt;

&lt;p&gt;For build a realtime &amp;amp; low latency application by using Phoenix &amp;amp; Elixir we make a library for cache data in memory. In time we started to build our product we didn't find a good cache library then we desired to build a new cache library with name SuperCache by Elixir.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hex.pm/packages/super_cache" rel="noopener noreferrer"&gt;SuperCache&lt;/a&gt; is simple library based on Ets table (from Erlang), each table for each partition for improving performance in case a lot of processes access to.&lt;/p&gt;

&lt;p&gt;Almost functions are same style with Ets function for people can easy to use (if people have worked with Ets before).&lt;/p&gt;

&lt;p&gt;Why we build cache that based on Ets? It's because in the early of our product, we using tuple a lot then it is perfect for us build a cache with Ets style, we can query with key/value style or by pattern matching. And another reason is Ets has a long time and it is stable &amp;amp; fast enough for us.&lt;/p&gt;

&lt;p&gt;With SuperCache we are easy to share data between processes or between applications (we will add support cluster in the future). This important thing help us so much for reduce time to develop &amp;amp; reduce complexity of our system.&lt;/p&gt;

&lt;p&gt;Belong with Ets style we add support for Key/Value, Stack, Queue struct with multi instances of each for convenience when working with shared global data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;Cache with Ets style and have partitions that can configuration in runtime. Cache is a global data in node then any process from any application run on node can access. You can choose a Ets table type if need.&lt;/p&gt;

&lt;p&gt;Key/Value memory database for simple tasks, supported multi instance of key/value with easy to use and can access from any process in node. Key/Value spreads all it data in all partitions by key (calculated by hash order of Erlang).&lt;/p&gt;

&lt;p&gt;Queue (FIFO), supported multi global queues with much more simple to use. Remember one thing, that is a queue store all it data in a partition then you can access it by match/match_object if need!.&lt;/p&gt;

&lt;p&gt;Stack (FILO), same with Queue.&lt;/p&gt;

&lt;p&gt;Note: For Key/Value, Queue, Stack when get data it can have default value (nil if you don't put to argument) for case no data in it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Guide
&lt;/h2&gt;

&lt;p&gt;It's very easy to use.&lt;/p&gt;

&lt;p&gt;First, add to deps:&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;deps&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:super_cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.6.0"&lt;/span&gt;&lt;span class="p"&gt;}&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;Second, start the cache:&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="no"&gt;SuperCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start!&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Default, number of partitions is a number of online_schedulers of Erlang VM.&lt;/p&gt;

&lt;p&gt;You can run with options like:&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;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;key_pos:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;partition_pos:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;table_type:&lt;/span&gt; &lt;span class="ss"&gt;:bag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;num_partition:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="no"&gt;SuperCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you can use the APIs of lib.&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="no"&gt;SuperCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put!&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:world&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"hello world!"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="no"&gt;SuperCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_by_key_partition!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:world&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="no"&gt;SuperCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete_by_key_partition!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:world&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;KV example (after started cache lib):&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;alias&lt;/span&gt; &lt;span class="no"&gt;SuperCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;KeyValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as:&lt;/span&gt; &lt;span class="no"&gt;KV&lt;/span&gt;
&lt;span class="no"&gt;KV&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"my_kv"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:key_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;KV&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="s2"&gt;"my_kv"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:key_a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Queue example (after started cache lib):&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;alias&lt;/span&gt; &lt;span class="no"&gt;SuperCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as:&lt;/span&gt; &lt;span class="no"&gt;Q&lt;/span&gt;
&lt;span class="no"&gt;Q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"my_queue"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"new_task"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"my_queue"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"new task: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stack example (after started cache lib):&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;alias&lt;/span&gt; &lt;span class="no"&gt;SuperCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as:&lt;/span&gt; &lt;span class="no"&gt;S&lt;/span&gt;
&lt;span class="no"&gt;S&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"my_stack"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:hello&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;S&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"my_stack"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:no_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"data: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Library is still developing and battle test before go to product but you can try!&lt;/p&gt;

&lt;p&gt;Source is available on &lt;a href="https://github.com/ohhi-vn/super_cache" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>kv</category>
      <category>stack</category>
      <category>queue</category>
    </item>
  </channel>
</rss>
