<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: lechat</title>
    <description>The latest articles on DEV Community by lechat (@lechatthecat).</description>
    <link>https://dev.to/lechatthecat</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%2F320154%2F4d96f0be-7f98-42f7-a931-91f4af8cd75a.jpeg</url>
      <title>DEV Community: lechat</title>
      <link>https://dev.to/lechatthecat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lechatthecat"/>
    <language>en</language>
    <item>
      <title>I Built a Laravel-like Web Framework for Rust</title>
      <dc:creator>lechat</dc:creator>
      <pubDate>Sat, 18 Apr 2026 22:26:06 +0000</pubDate>
      <link>https://dev.to/lechatthecat/i-built-a-laravel-like-web-framework-for-rust-but-nobody-is-using-it-yet-39hh</link>
      <guid>https://dev.to/lechatthecat/i-built-a-laravel-like-web-framework-for-rust-but-nobody-is-using-it-yet-39hh</guid>
      <description>&lt;p&gt;I recently built a Rust web framework called &lt;strong&gt;Willow Forge&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/lechatthecat/willow-forge" rel="noopener noreferrer"&gt;https://github.com/lechatthecat/willow-forge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s a Laravel-like layer on top of axum, designed to give you structure, productivity, and a batteries-included developer experience — something I personally missed when building apps in Rust.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Willow Forge Is
&lt;/h2&gt;

&lt;p&gt;Willow Forge is a &lt;strong&gt;productivity-focused framework for Rust web development&lt;/strong&gt;, inspired by Laravel and Rails.&lt;/p&gt;

&lt;p&gt;It provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MVC-style project structure&lt;/li&gt;
&lt;li&gt;Controllers, middleware&lt;/li&gt;
&lt;li&gt;Request validation&lt;/li&gt;
&lt;li&gt;Server-side HTML rendering + JSON APIs&lt;/li&gt;
&lt;li&gt;Routing separation (&lt;code&gt;web.rs&lt;/code&gt; / &lt;code&gt;api.rs&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Migrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the hood, it uses &lt;code&gt;axum&lt;/code&gt;, but instead of starting from a blank slate every time, you get a structured foundation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Built It
&lt;/h2&gt;

&lt;p&gt;Every time I started a new Rust web project with axum, I found myself rebuilding the same things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Folder structure&lt;/li&gt;
&lt;li&gt;Routing organization&lt;/li&gt;
&lt;li&gt;Validation layer&lt;/li&gt;
&lt;li&gt;Middleware grouping&lt;/li&gt;
&lt;li&gt;Basic app architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rust gives you power — but not much &lt;strong&gt;guidance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In contrast, frameworks like Laravel or Rails give you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clear place for everything&lt;/li&gt;
&lt;li&gt;Consistent patterns&lt;/li&gt;
&lt;li&gt;Fast onboarding&lt;/li&gt;
&lt;li&gt;Less decision fatigue&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted that experience — but in Rust.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who This Is For
&lt;/h2&gt;

&lt;p&gt;Willow Forge is probably a good fit if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You like Laravel style structure&lt;/li&gt;
&lt;li&gt;You don’t want to reinvent app architecture every time&lt;/li&gt;
&lt;li&gt;You’re building:

&lt;ul&gt;
&lt;li&gt;CRUD apps&lt;/li&gt;
&lt;li&gt;internal tools&lt;/li&gt;
&lt;li&gt;dashboards&lt;/li&gt;
&lt;li&gt;SSR + API combined apps&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>rust</category>
      <category>laravel</category>
      <category>web</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Create a k8s development environment by Minikube</title>
      <dc:creator>lechat</dc:creator>
      <pubDate>Thu, 20 Mar 2025 17:39:16 +0000</pubDate>
      <link>https://dev.to/lechatthecat/create-a-development-environment-by-minikube-1a9b</link>
      <guid>https://dev.to/lechatthecat/create-a-development-environment-by-minikube-1a9b</guid>
      <description>&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;My environment is Windows10.&lt;/p&gt;

&lt;h2&gt;
  
  
  Download tools
&lt;/h2&gt;

&lt;p&gt;Please install minikube from here:&lt;br&gt;&lt;br&gt;
&lt;a href="https://minikube.sigs.k8s.io/docs/star" rel="noopener noreferrer"&gt;https://minikube.sigs.k8s.io/docs/star&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's use virtualbox driver for minikube.&lt;br&gt;&lt;br&gt;
Please install virtualbox from here:&lt;br&gt;&lt;br&gt;
&lt;a href="http://virtualbox.org/wiki/Downloads" rel="noopener noreferrer"&gt;http://virtualbox.org/wiki/Downloads&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;We will use Git too. Please install Git from here:&lt;br&gt;&lt;br&gt;
&lt;a href="https://git-scm.com/downloads" rel="noopener noreferrer"&gt;https://git-scm.com/downloads&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's install skaffold too:&lt;br&gt;&lt;br&gt;
&lt;a href="https://skaffold.dev/docs/install/" rel="noopener noreferrer"&gt;https://skaffold.dev/docs/install/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then please install kubernetes too:&lt;br&gt;&lt;br&gt;
&lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(If you use choco or scoop, it is easy to install)&lt;/p&gt;

&lt;p&gt;After installing them, let's confirm if you can access minikube from Powershell.&lt;br&gt;
Open Powershell then run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;minikube version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you get minikube version&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;minikube version: v1.35.0
commit: dd5d320e41b5451cdf3c01891bc4e13d189586ed-dirty
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the same way, please check git version too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nt"&gt;-v&lt;/span&gt;
git version 2.47.1.windows.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's make a test project for this test.&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;cd &lt;/span&gt;Documents
&lt;span class="nb"&gt;mkdir &lt;/span&gt;projects
&lt;span class="nb"&gt;cd &lt;/span&gt;projects
&lt;span class="nb"&gt;mkdir &lt;/span&gt;test-project
&lt;span class="nb"&gt;cd &lt;/span&gt;test-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Minikube start (minikube cluster)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  terminology
&lt;/h3&gt;

&lt;h4&gt;
  
  
  What are Containers?
&lt;/h4&gt;

&lt;p&gt;Containers are lightweight, isolated runtime environments that package an application and its dependencies. They ensure consistency across different computing environments.&lt;/p&gt;

&lt;h4&gt;
  
  
  What are Pods?
&lt;/h4&gt;

&lt;p&gt;A Pod is the smallest deployable unit in Kubernetes, acting as a wrapper for one or more containers.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is a Cluster?
&lt;/h4&gt;

&lt;p&gt;A Cluster is the highest-level component in Kubernetes, consisting of multiple worker nodes that run Pods.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start a minikube cluster
&lt;/h3&gt;

&lt;p&gt;Please run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube start --driver=virtualbox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then minikube will start. Please note that, if it is docker driver, you can use mount option like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube start --mount --mount-string="$HOME:/src" --driver=docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but unfortunately this is impossible with virtualbox driver. (but virtualbox is free unlike docker desktop...)&lt;/p&gt;

&lt;p&gt;Now let's install kubernetes. But we will just install kubernetes via minikube:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube kubectl -- version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After kubernetes is installed, kubernetes version is displayed like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube kubectl -- version
Client Version: v1.32.0
Kustomize Version: v5.5.0
Server Version: v1.32.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create pods
&lt;/h2&gt;

&lt;p&gt;Let's create PHP, Nginx, MariaDB environment.&lt;br&gt;&lt;br&gt;
At first, enable ingress:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube addons enable ingress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then please save the following as &lt;code&gt;php-mariadb.yaml&lt;/code&gt;. This file contains definition of containers in the pods. Please note that you must use "LF" for this file's linebreaks not "CRLF":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# MariaDB Deployment&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Deployment name&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb&lt;/span&gt;
  &lt;span class="c1"&gt;# Labels for identifying the deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Number of MariaDB instances&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Matching labels for pods&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb&lt;/span&gt;
          &lt;span class="c1"&gt;# Docker image for MariaDB&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb:11.3&lt;/span&gt;
          &lt;span class="c1"&gt;# Port on which MariaDB runs&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3306&lt;/span&gt;
          &lt;span class="c1"&gt;# Environment variables for MariaDB&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rootpassword"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MYSQL_DATABASE&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mydatabase"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MYSQL_USER&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;myuser"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MYSQL_PASSWORD&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mypassword"&lt;/span&gt;
          &lt;span class="c1"&gt;# Volume mounting for MariaDB data storage&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb-storage&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/mysql&lt;/span&gt;
      &lt;span class="c1"&gt;# Definition of volumes&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb-storage&lt;/span&gt;
          &lt;span class="na"&gt;emptyDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# MariaDB Service&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Service name for MariaDB&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3306&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Selector for connecting to MariaDB pods&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# PHP Application Deployment&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Deployment name&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php-app&lt;/span&gt;
  &lt;span class="c1"&gt;# Labels for identifying the PHP deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php-app&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Number of PHP application instances&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php-app&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php-app&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php-app&lt;/span&gt;
          &lt;span class="c1"&gt;# Docker image for PHP application&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php:8.3-apache&lt;/span&gt;
          &lt;span class="c1"&gt;# Port on which PHP Apache runs&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
          &lt;span class="c1"&gt;# Volume mounting for PHP application code from host machine&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php-app-code&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/www/html&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apache-config&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/apache2/sites-enabled/000-default.conf&lt;/span&gt;
              &lt;span class="na"&gt;subPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
      &lt;span class="c1"&gt;# Definition of volumes&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php-app-code&lt;/span&gt;
          &lt;span class="na"&gt;hostPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/mnt/project"&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Directory&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apache-config&lt;/span&gt;
          &lt;span class="na"&gt;configMap&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apache-config&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# ConfigMap for Apache Configuration&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ConfigMap&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apache-config&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;&amp;lt;VirtualHost *:80&amp;gt;&lt;/span&gt;
        &lt;span class="s"&gt;ServerAdmin webmaster@localhost&lt;/span&gt;
        &lt;span class="s"&gt;DocumentRoot /var/www/html&lt;/span&gt;
        &lt;span class="s"&gt;&amp;lt;Directory "/var/www/html"&amp;gt;&lt;/span&gt;
            &lt;span class="s"&gt;Options Indexes FollowSymLinks&lt;/span&gt;
            &lt;span class="s"&gt;AllowOverride All&lt;/span&gt;
            &lt;span class="s"&gt;Require all granted&lt;/span&gt;
            &lt;span class="s"&gt;DirectoryIndex index.html index.php&lt;/span&gt;
        &lt;span class="s"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;
        &lt;span class="s"&gt;ErrorLog /var/log/apache2/error.log&lt;/span&gt;
        &lt;span class="s"&gt;CustomLog /var/log/apache2/access.log combined&lt;/span&gt;
    &lt;span class="s"&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/span&gt;
&lt;span class="s"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# PHP Application Service&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Service name for PHP application&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php-app-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Selector for connecting to PHP pods&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php-app&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# Ingress resource for PHP Application&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php-app-ingress&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ingressClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost&lt;/span&gt;
      &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
            &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
            &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php-app-service&lt;/span&gt;
                &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then please save the following as skaffold.yaml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: skaffold/v4beta12
kind: Config
metadata:
  name: php-mariadb-app
deploy:
  kubectl: {}
manifests:
  rawYaml:
    - php-mariadb.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our environment is ready to go!&lt;br&gt;&lt;br&gt;
Before starting our environment, let's create a mount directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir mounttest
minikube mount "$Home\\Documents\\projects\\test-project\\mounttest:/mnt/project"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This mount command will keep running. For subsequent commands, please open a new terminal and run the commands on it.&lt;/p&gt;

&lt;p&gt;Please run this command (please make sure you in the test-project directory):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd {the test-project directory}
skaffold delete
skaffold run --force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will keep running. For subsequent commands, please open a new terminal and run the commands on it.&lt;/p&gt;

&lt;p&gt;Please wait a while... Your kubernetes environment is being created in the minikube cluster. This will take time.&lt;br&gt;&lt;br&gt;
See here for more skaffold examples: &lt;a href="https://github.com/GoogleContainerTools/skaffold/tree/main/examples" rel="noopener noreferrer"&gt;https://github.com/GoogleContainerTools/skaffold/tree/main/examples&lt;/a&gt;&lt;br&gt;&lt;br&gt;
For available paramters: &lt;a href="https://skaffold.dev/docs/references/yaml/" rel="noopener noreferrer"&gt;https://skaffold.dev/docs/references/yaml/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now your php and mariadb should be running. Let's check it by &lt;code&gt;kubectl get pods&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
mariadb-998f96ddb-84kqs   1/1     Running   0          64s
php-app-bf6f77579-454jl   1/1     Running   0          64s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all of them are "Ready 1/1", it means your environment is running without problem.&lt;br&gt;&lt;br&gt;
By the way, these are called pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mariadb-998f96ddb-84kqs (pod)
php-app-bf6f77579-454jl (pod)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our containers defined by the yaml file are in the pods. One pod can have multiple containers inside.&lt;br&gt;&lt;br&gt;
Sometimes we define logger container and put them in the pod together with a php container.&lt;br&gt;
Such containers are called "sidecar container."&lt;/p&gt;

&lt;p&gt;If any of the pods is not ready, please check the pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl describe pod php-app-bf6f77579-454jl 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or check the standard output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl logs php-app-bf6f77579-454jl 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see cluster-wide information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get events --sort-by='.metadata.creationTimestamp'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the creation is done, to access minikube environment from host, let's run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube tunnel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will keep running. For subsequent commands, please open a new terminal and run the commands on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mount /var/www/html to the host PC and access the file through ingress
&lt;/h2&gt;

&lt;p&gt;Now let's see if you can access the ingress. Run this command and get ingress information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get ingress
NAME              CLASS    HOSTS       ADDRESS          PORTS   AGE
php-app-ingress   &amp;lt;none&amp;gt;   localhost   192.168.59.100   80      103s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, following this information, if you access 192.168.59.100 from your browser, you will see 404.&lt;/p&gt;

&lt;p&gt;If you can see the 404, you are ready to go further.&lt;br&gt;&lt;br&gt;
Please check the ingress ip by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get ingress
NAME              CLASS   HOSTS       ADDRESS          PORTS   AGE
php-app-ingress   nginx   localhost   192.168.59.100   80      93s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My IP is 192.168.59.100, so please update the php-mariadb.yaml's ingress configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Ingress resource for PHP Application
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: php-app-ingress
spec:
  ingressClassName: nginx
  rules:
    - host: 192.168.59.100.nip.io #!!! Change here !!!!
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: php-app-service
                port:
                  number: 80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have mounted our "mounttest" to "/mnt/project" (of minikube) and this "/mnt/project" is mounted again to "/var/www/html" of php-appache pod. So let's create index.php like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
echo "Hello World!";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please save it in the &lt;code&gt;mounttest&lt;/code&gt; of your &lt;code&gt;project&lt;/code&gt; folder.&lt;br&gt;&lt;br&gt;
Now open &lt;a href="http://192.168.59.100.nip.io/" rel="noopener noreferrer"&gt;http://192.168.59.100.nip.io/&lt;/a&gt; from your browser. You should see &lt;code&gt;Hello World!&lt;/code&gt; If you change the php code, you can see that the change is reflected in real time (if not, please disable opcache from your php.ini). Your PHP code is working in a k8s cluster!&lt;/p&gt;

&lt;p&gt;Now you can edit your php in your &lt;code&gt;mounttest&lt;/code&gt; folder and the edit is reflected to the php pod in the kubernetes cluster in real time. If you need, you can even set php debug for your development. But, if you with minikube &amp;amp; kubernetes in your local, please don't forget to disable opcache in your php.ini:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;opcache.enable=0
opcache.validate_timestamps=1
opcache.revalidate_freq=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why did it return 404 at first, but started working after changing the IP from localhost to 192.168.59.100.nip.io?&lt;/p&gt;

&lt;p&gt;In the initial Ingress definition inside the .yaml file, it was configured like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means the Ingress rule is set to only handle requests where the hostname is localhost.&lt;/p&gt;

&lt;p&gt;However, the virtual network created by Minikube (e.g., 192.168.59.100) exists outside the host OS's localhost.&lt;br&gt;
So when you access 192.168.59.100 in your browser, the Ingress controller:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sees that the hostname doesn't match (localhost ≠ 192.168.59.100)&lt;/li&gt;
&lt;li&gt;finds no matching rule&lt;/li&gt;
&lt;li&gt;and returns a 404 error&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So why does it work when you change to 192.168.59.100.nip.io?&lt;br&gt;&lt;br&gt;
When you change the rule like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rules:
  - host: 192.168.59.100.nip.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ingress recognizes the hostname and thinks:&lt;/p&gt;

&lt;p&gt;"Ah, this is the hostname I'm in charge of!"&lt;/p&gt;

&lt;p&gt;As a result, it correctly applies the routing rule.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use MariaDB from host pc
&lt;/h3&gt;

&lt;p&gt;Let's change MariaDB's service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# MariaDB Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  # Deployment name
  name: mariadb
  # Labels for identifying the deployment
  labels:
    app: mariadb
spec:
  # Number of MariaDB instances
  replicas: 1
  selector:
    # Matching labels for pods
    matchLabels:
      app: mariadb
  template:
    metadata:
      labels:
        app: mariadb
    spec:
      containers:
        - name: mariadb
          # Docker image for MariaDB
          image: mariadb:11.3
          # Port on which MariaDB runs
          ports:
            - containerPort: 3306
          # Environment variables for MariaDB
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: "rootpassword"
            - name: MYSQL_DATABASE
              value: "mydatabase"
            - name: MYSQL_USER
              value: "myuser"
            - name: MYSQL_PASSWORD
              value: "mypassword"
          # Volume mounting for MariaDB data storage
          volumeMounts:
            - name: mariadb-storage
              mountPath: /var/lib/mysql
      # Definition of volumes
      volumes:
        - name: mariadb-storage
          emptyDir: {}
---
kind: Service
apiVersion: v1
metadata:
  name: mariadb
spec:
  type: NodePort
  selector:
    app: mariadb
  ports:
    - port: 3306
      targetPort: 3306
      protocol: TCP
      nodePort: 30036   # for example (must be within the allowed range, e.g., 30000-32767)
---
# PHP Application Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  # Deployment name
  name: php-app
  # Labels for identifying the PHP deployment
  labels:
    app: php-app
spec:
  # Number of PHP application instances
  replicas: 1
  selector:
    matchLabels:
      app: php-app
  template:
    metadata:
      labels:
        app: php-app
    spec:
      containers:
        - name: php-app
          # Docker image for PHP application
          image: php:8.3-apache
          # Port on which PHP Apache runs
          ports:
            - containerPort: 80
          # Volume mounting for PHP application code from host machine
          volumeMounts:
            - name: php-app-code
              mountPath: /var/www/html
            - name: apache-config
              mountPath: /etc/apache2/sites-enabled/000-default.conf
              subPath: default
      # Definition of volumes
      volumes:
        - name: php-app-code
          hostPath:
            path: "/mnt/project"
            type: Directory
        - name: apache-config
          configMap:
            name: apache-config
---
# ConfigMap for Apache Configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: apache-config
data:
  default: |
    &amp;lt;VirtualHost *:80&amp;gt;
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html
        &amp;lt;Directory "/var/www/html"&amp;gt;
            Options Indexes FollowSymLinks
            AllowOverride All
            Require all granted
            DirectoryIndex index.html index.php
        &amp;lt;/Directory&amp;gt;
        ErrorLog /var/log/apache2/error.log
        CustomLog /var/log/apache2/access.log combined
    &amp;lt;/VirtualHost&amp;gt;
---
# PHP Application Service
apiVersion: v1
kind: Service
metadata:
  # Service name for PHP application
  name: php-app-service
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: 80
  selector:
    # Selector for connecting to PHP pods
    app: php-app
---
# Ingress resource for PHP Application
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: php-app-ingress
spec:
  ingressClassName: nginx
  rules:
    - host: 192.168.59.100.nip.io #!!! Change here !!!!
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: php-app-service
                port:
                  number: 80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that the MariaDB service is using &lt;code&gt;NodePort&lt;/code&gt; now.&lt;br&gt;&lt;br&gt;
Stop the &lt;code&gt;skaffold run&lt;/code&gt; from the terminal where you executed the command (by ctrl+c), then start again by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd {the test-project directory}
skaffold delete
skaffold run --force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check minikube IP by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube ip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will give you the IP address of minikube. You can use this IP and the NodePort to access the MariaDB.&lt;/p&gt;

&lt;p&gt;For me, the IP address was 192.168.59.100 &lt;br&gt;
The NodePort is defined as 30036 in the yaml file.&lt;/p&gt;

&lt;p&gt;So by using both 192.168.59.100:30036, you can access the MariaDB.&lt;br&gt;
Please note that the environment of MariaDB is configured this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: MYSQL_ROOT_PASSWORD
  value: "rootpassword"
- name: MYSQL_DATABASE
  value: "mydatabase"
- name: MYSQL_USER
  value: "myuser"
- name: MYSQL_PASSWORD
  value: "mypassword"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>kubernetes</category>
      <category>webdev</category>
      <category>operations</category>
    </item>
    <item>
      <title>I'm scared of AI that automates coding in very high level..</title>
      <dc:creator>lechat</dc:creator>
      <pubDate>Sun, 12 Jan 2025 19:20:53 +0000</pubDate>
      <link>https://dev.to/lechatthecat/im-scared-of-ai-that-automates-coding-in-very-high-level-1i99</link>
      <guid>https://dev.to/lechatthecat/im-scared-of-ai-that-automates-coding-in-very-high-level-1i99</guid>
      <description></description>
    </item>
    <item>
      <title>Building a Developer-Focused Search Engine in Rust: Lessons Learned and Challenges Overcome 🚀</title>
      <dc:creator>lechat</dc:creator>
      <pubDate>Sat, 11 Jan 2025 06:57:34 +0000</pubDate>
      <link>https://dev.to/lechatthecat/building-a-developer-focused-search-engine-in-rust-lessons-learned-and-challenges-overcome-1jdn</link>
      <guid>https://dev.to/lechatthecat/building-a-developer-focused-search-engine-in-rust-lessons-learned-and-challenges-overcome-1jdn</guid>
      <description>&lt;p&gt;As developers, we all know the struggle of wading through irrelevant search results to find that one golden line of code. So, I thought, why not build a search engine tailored for us devs? With Rust, Actix, Elasticsearch, React, and Next.js, I created a search engine for developers. &lt;/p&gt;

&lt;p&gt;Here is what I made:&lt;br&gt;
&lt;a href="https://dev-search.com/" rel="noopener noreferrer"&gt;https://dev-search.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am not a senior dev, so if I am doing something stupid, please let me know 😅&lt;/p&gt;
&lt;h2&gt;
  
  
  🎯 The Mission
&lt;/h2&gt;

&lt;p&gt;The goal was simple: create a developer's information-focused search engine with:&lt;/p&gt;

&lt;p&gt;Frontend: React + Next.js (SSG for speed and SEO)&lt;/p&gt;

&lt;p&gt;Backend: Rust and Elasticsearch for robust, scalable search functionality&lt;/p&gt;
&lt;h2&gt;
  
  
  🚧 Challenges Faced
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Search by Elasticsearch is slow 😢
&lt;/h2&gt;

&lt;p&gt;Because there are more than 10 million documents, the search of elesticsearch was slow. &lt;/p&gt;

&lt;p&gt;I found that the problem that was slowing it down was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"track_total_hits": {big number like 10000}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;Actually keeping that number big like 10000 is as slow as actually fetching 10000 documents from elasticsearch. By changing this to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"track_total_hits": false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;made the search a lot faster. But this change disables ability to track how many records were hit by a search, so you must consider well if it is good for your use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Too Many Malicious Users Scanning the Website 👽
&lt;/h2&gt;

&lt;p&gt;Ah, the joys of running a public-facing site! Within days of launching, I noticed strange requests hitting my server logs. From bots pretending to be browsers to outright weird payloads like \x00\x00SMB, my site became a playground for malicious users. Here's a gem from my logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;35.203.211.8 - - [30/Dec/2024:05:15:37 +0000] "\x00\x00\x00\xAC\xFESMB..."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Solution: Fail2Ban
&lt;/h3&gt;

&lt;p&gt;Fail2Ban came to the rescue! This nifty tool monitors log files and dynamically bans IPs that show malicious behavior. Here's how I set it up:&lt;/p&gt;

&lt;h3&gt;
  
  
  Defined a Fail2Ban Jail for Nginx:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[nginx-malicious]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 300
bantime = 600
action = iptables[name=nginx-malicious, port="http,https", protocol=tcp]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Filter to Detect Malicious Patterns:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Definition]
failregex = ^&amp;lt;HOST&amp;gt; - - .*SMB.*
ignoreregex =
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dynamic Blocking in Action:
&lt;/h3&gt;

&lt;p&gt;When Fail2Ban detects malicious requests, it updates the firewall to block the offending IP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo iptables -L -n | grep DROP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Fail2Ban, malicious IPs were swiftly banned, and my server logs became much cleaner. Lesson learned: Bots will come, but so will the ban hammer. 🛠️&lt;/p&gt;

&lt;p&gt;Please note that, if you are using Docker/Docker compose, you might need the following:&lt;br&gt;
&lt;a href="https://github.com/fail2ban/fail2ban/issues/2376#issuecomment-2565534465" rel="noopener noreferrer"&gt;https://github.com/fail2ban/fail2ban/issues/2376#issuecomment-2565534465&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Adsense not showing 😿
&lt;/h2&gt;

&lt;p&gt;As you can see on the capture:&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%2Fuhkq9oahc0jvpq8rskm2.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%2Fuhkq9oahc0jvpq8rskm2.png" alt=" " width="800" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even though Adsense is set, the Adsense often doesn't show up...&lt;br&gt;
I investigated why it is not showing up, but I guess there are 2 reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;My website's reputation is low&lt;/li&gt;
&lt;li&gt;Google cannot find ad for the specified ad size&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Well, I cannot change the first reason, but maybe I can do something for the second one. What I did is as follows.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;At first, I tried the fixed sized ad because I wanted a not too large ad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;GoogleAdUnit&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ins&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"adsbygoogle"&lt;/span&gt;
        &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display:inline-block;width:300px;height:90px"&lt;/span&gt;
        &lt;span class="na"&gt;data-ad-client=&lt;/span&gt;&lt;span class="s"&gt;"ca-pub-{ad-client-id}"&lt;/span&gt;
        &lt;span class="na"&gt;data-ad-slot=&lt;/span&gt;&lt;span class="s"&gt;"{slot id}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ins&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/GoogleAdUnit&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this often fails to show the ad.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Please note that I am using &lt;code&gt;nextjs13_google_adsense&lt;/code&gt; because I am using Next.js.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, after that, I tried a responsive ad. The default code of the responsive ad is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;GoogleAdUnit&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ins&lt;/span&gt;
        &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"adsbygoogle"&lt;/span&gt;
        &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;display:&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;block&lt;/span&gt;&lt;span class="err"&gt;',&lt;/span&gt; &lt;span class="na"&gt;width:&lt;/span&gt; &lt;span class="err"&gt;'100%'&lt;/span&gt; &lt;span class="err"&gt;}}&lt;/span&gt;
        &lt;span class="na"&gt;data-ad-client=&lt;/span&gt;&lt;span class="s"&gt;"ca-pub-{ad-client-id}"&lt;/span&gt; &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="na"&gt;Replace&lt;/span&gt; &lt;span class="na"&gt;with&lt;/span&gt; &lt;span class="na"&gt;your&lt;/span&gt; &lt;span class="na"&gt;AdSense&lt;/span&gt; &lt;span class="na"&gt;client&lt;/span&gt; &lt;span class="na"&gt;ID&lt;/span&gt;
        &lt;span class="na"&gt;data-ad-slot=&lt;/span&gt;&lt;span class="s"&gt;'{slot id}'&lt;/span&gt; &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="na"&gt;Replace&lt;/span&gt; &lt;span class="na"&gt;with&lt;/span&gt; &lt;span class="na"&gt;your&lt;/span&gt; &lt;span class="na"&gt;Ad&lt;/span&gt; &lt;span class="na"&gt;slot&lt;/span&gt; &lt;span class="na"&gt;ID&lt;/span&gt;
        &lt;span class="na"&gt;data-ad-format=&lt;/span&gt;&lt;span class="s"&gt;"auto"&lt;/span&gt;
        &lt;span class="na"&gt;data-full-width-responsive=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/GoogleAdUnit&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the best because the size is changed in accordance with the ad size. But, to me, the auto sized ad looked too big 😅&lt;/p&gt;

&lt;p&gt;So I limited the height like this. Please note that I am using the "horizontal" for the &lt;code&gt;data-ad-format&lt;/code&gt; because I wanted a not-too-big horizontal ad.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;GoogleAdUnit&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ins&lt;/span&gt;
        &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"adsbygoogle"&lt;/span&gt;
        &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;display:&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;block&lt;/span&gt;&lt;span class="err"&gt;',&lt;/span&gt; &lt;span class="na"&gt;width:&lt;/span&gt; &lt;span class="err"&gt;'100%',&lt;/span&gt; &lt;span class="na"&gt;height:&lt;/span&gt; &lt;span class="err"&gt;'50&lt;/span&gt;&lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="err"&gt;}}&lt;/span&gt; &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="na"&gt;limit&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;
        &lt;span class="na"&gt;data-ad-client=&lt;/span&gt;&lt;span class="s"&gt;"ca-pub-{ad-client-id}"&lt;/span&gt; &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="na"&gt;Replace&lt;/span&gt; &lt;span class="na"&gt;with&lt;/span&gt; &lt;span class="na"&gt;your&lt;/span&gt; &lt;span class="na"&gt;AdSense&lt;/span&gt; &lt;span class="na"&gt;client&lt;/span&gt; &lt;span class="na"&gt;ID&lt;/span&gt;
        &lt;span class="na"&gt;data-ad-slot=&lt;/span&gt;&lt;span class="s"&gt;'{slot id}'&lt;/span&gt; &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="na"&gt;Replace&lt;/span&gt; &lt;span class="na"&gt;with&lt;/span&gt; &lt;span class="na"&gt;your&lt;/span&gt; &lt;span class="na"&gt;Ad&lt;/span&gt; &lt;span class="na"&gt;slot&lt;/span&gt; &lt;span class="na"&gt;ID&lt;/span&gt;
        &lt;span class="na"&gt;data-ad-format=&lt;/span&gt;&lt;span class="s"&gt;"horizontal"&lt;/span&gt; &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="na"&gt;horizontal&lt;/span&gt;
        &lt;span class="na"&gt;data-full-width-responsive=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/GoogleAdUnit&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It still sometimes fail to show ad, but ad more often appear on my website now because there is not limitation for the width 😀&lt;/p&gt;

&lt;h2&gt;
  
  
  Unsolved Problems
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Website Design is too simple &lt;/li&gt;
&lt;li&gt;The search accuracy is low&lt;/li&gt;
&lt;li&gt;The returned data is almost always only stackoverflow because large amount of the database is records from stackoverflow. Not sure whether this is OK..&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🙏 Thanks for Reading!
&lt;/h2&gt;

</description>
      <category>rust</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I created a simple app by very fast Rust web framework Actix web. Please use this as a sample code.</title>
      <dc:creator>lechat</dc:creator>
      <pubDate>Thu, 15 Aug 2024 03:36:21 +0000</pubDate>
      <link>https://dev.to/lechatthecat/i-created-a-simple-app-by-very-fast-rust-web-framework-actix-web-please-use-this-as-a-sample-code-e60</link>
      <guid>https://dev.to/lechatthecat/i-created-a-simple-app-by-very-fast-rust-web-framework-actix-web-please-use-this-as-a-sample-code-e60</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I believe it was last year when I had an interview at a company. As part of the technical assessment, I created a simple web application using Rust, React, and Next.js. Since I built it in just a few days specifically for the interview, it may not be highly polished, but I aimed to make it as robust as possible for production use. Therefore, I think it could be a good reference for those looking to create something with Actix web. The application uses Next.js for SSG, so it should load quickly.&lt;br&gt;
&lt;a href="https://github.com/lechatthecat/assignment" rel="noopener noreferrer"&gt;https://github.com/lechatthecat/assignment&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every time I start a new development project, I find it tedious to repeatedly implement the same things, like the Docker Compose YAML file, API handlers, and Next.js configurations. I also often find myself wondering, "How did I do that again?" Because of this, I think developing based on this working project could save time.&lt;/p&gt;

&lt;p&gt;Although I didn't end up joining the company, I wanted to share this repository with everyone instead of letting it go unused. I've removed any parts related to that company and erased them from the Git history as well.&lt;/p&gt;

&lt;p&gt;However, one of the interview conditions was not to use any ORM libraries (such as Diesel), so there are no ORMs included. If you plan to use this as a reference, please keep this in mind, and you’ll likely need to incorporate Diesel or another ORM if you build upon it.&lt;/p&gt;

&lt;p&gt;Lastly, please don't use the test code as a reference—it's something I put together quickly under time constraints. I'm sharing this purely as a reference.&lt;/p&gt;

&lt;p&gt;By the way, it seems that Actix web, the Rust web framework, is incredibly fast. A few years ago, it topped the charts in the benchmark below.&lt;br&gt;
&lt;a href="https://www.techempower.com/benchmarks/#hw=ph&amp;amp;test=fortune&amp;amp;section=data-r22" rel="noopener noreferrer"&gt;https://www.techempower.com/benchmarks/#hw=ph&amp;amp;test=fortune&amp;amp;section=data-r22&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although its ranking has dropped quite a bit, as of August 15, 2024, Actix ecosystem's actix-http is still in 12th place. It's probably still one of the faster frameworks, especially among the more mature ones.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to use
&lt;/h2&gt;

&lt;p&gt;This is witten in the Readme.md too:&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="nv"&gt;$ &lt;/span&gt;git clone https://github.com/lechatthecat/assignment
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;assignment
&lt;span class="nv"&gt;$ &lt;/span&gt;docker compose up &lt;span class="nt"&gt;--build&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will start release build of the Rust code. When it is done, you can access the app from this URL. &lt;br&gt;
&lt;a href="http://localhost/login" rel="noopener noreferrer"&gt;http://localhost/login&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please use the following information to login.&lt;br&gt;
name: test_user1&lt;br&gt;
password: password&lt;/p&gt;
&lt;h3&gt;
  
  
  For development
&lt;/h3&gt;

&lt;p&gt;If you want to use the docker compose file for development:&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="nv"&gt;$ &lt;/span&gt;docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose-dev.yml up &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What does the app do?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Structure
&lt;/h3&gt;

&lt;p&gt;The app is divided into an API server built with Actix web and a React + Next.js application that calls it. To see which APIs are available, please refer to the API handlers.&lt;br&gt;
&lt;a href="https://github.com/lechatthecat/assignment/blob/main/simple_restaurant_api/src/api/api_handler/handlers.rs" rel="noopener noreferrer"&gt;https://github.com/lechatthecat/assignment/blob/main/simple_restaurant_api/src/api/api_handler/handlers.rs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The API server, nginx, and PostgreSQL are all set up as separate containers using Docker Compose. The code in the &lt;code&gt;frontend&lt;/code&gt; folder is automatically synchronized within the nginx container, which serves the frontend. However, any request that starts with &lt;code&gt;/api&lt;/code&gt; is redirected (via reverse proxy) by nginx to the Actix web server. All other requests are handled by the &lt;code&gt;frontend&lt;/code&gt; inside the nginx container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;This is a simple SPA (though technically it's SSG with Next.js, so I'm not sure if SPA is the right term) designed for use in a restaurant with 10 tables. The idea is that each waiter has a tablet, and when taking orders, they first select the table from which the order is being placed.&lt;/p&gt;

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

&lt;p&gt;After selecting the table, you'll be taken to a screen showing the list of currently received orders for that table.&lt;/p&gt;

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

&lt;p&gt;When you press "Menu," you'll be taken to a page displaying the full menu, where you can click on the items that have been ordered. Each menu item includes the price and the estimated time until it's ready. By pressing "Add this to order," you can add the selected menu item to the list of received orders.&lt;/p&gt;

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

&lt;p&gt;Once you add an order, a real-time countdown begins until the preparation is complete. When it reaches zero, the waiter is expected to go to the kitchen to pick up the dish and serve it to the customer at that table. You can also see the estimated time when the dish will be ready.&lt;/p&gt;

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

&lt;p&gt;To be honest, the functionality itself isn't anything special. As I mentioned before, I built this in just a few days for an interview, so I only implemented the bare minimum.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Recommendations
&lt;/h2&gt;

&lt;p&gt;Here are a few things that I think should be added to the to-do list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There’s no documentation for the API yet, so I think it would be a good idea to implement Swagger for that.&lt;/li&gt;
&lt;li&gt;Implementing caching with Redis on the API side, as well as using a CDN like Cloudflare, could help reduce server load. In this case, since it’s only being used internally, I didn’t bother with it. However, if this were a publicly available app, caching would be necessary.&lt;/li&gt;
&lt;li&gt;If you're hosting a service that might experience high traffic, it’s better to separate containers for the API server, frontend, and load balancer, and use Kubernetes for container management instead of Docker Compose. This makes scaling out much easier.&lt;/li&gt;
&lt;li&gt;In the docker-compose.yml file, the myrust volume is bound file-by-file, as shown below. This is to avoid overwriting the container’s target folder (built within the container) with an empty target folder from the host. However, for local development, it might be more convenient to sync entire folders instead of individual files. For example, you could set up a shell script that automatically builds the project whenever the container starts. That said, this isn’t mandatory, and using a separate docker-compose.yml for development could also work. I didn’t include the shell script because, during the interview, I wanted to avoid confusing the interviewer with a 404 error that would occur while waiting for the build command (by the script) to finish, even after running docker compose up. Docker compose command wouldn't wait for the script execution to finish if it is executed as &lt;code&gt;command&lt;/code&gt; of Dockerfile or docker compose file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# log&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./logs:/simple_restaurant_api/log&lt;/span&gt;
    &lt;span class="c1"&gt;# Rust code&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./simple_restaurant_api/src:/simple_restaurant_api/src&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./simple_restaurant_api/Cargo.lock:/simple_restaurant_api/Cargo.lock&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./simple_restaurant_api/Cargo.toml:/simple_restaurant_api/Cargo.toml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;On the frontend, I committed the Next.js out directory, but ideally, it would be better to generate it each time the container is started using npm run build, rather than committing it. Since the focus of the interview was on the API implementation, I didn’t want to require the interviewer to run the npm run build command manually. However, for a production environment, this should be fixed (for example, by setting up an automated script to handle the build process).&lt;/li&gt;
&lt;li&gt;Normally, there would be a step where the customer confirms their order (something like "Is this order correct?") before it's sent to the kitchen. This would require an additional feature to temporarily hold the order for confirmation before actually submitting it. However, since the main focus of this test was the API, I skipped it.&lt;/li&gt;
&lt;li&gt;I used the unwrap function outside of tests, which isn’t good practice in Rust, especially for production environments. It would be better to replace it with the expect function (which allows for custom error messages) or, for cases where errors are likely in production, handle them explicitly with a match statement or the or_else function.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>actix</category>
      <category>actixweb</category>
      <category>rust</category>
      <category>restapi</category>
    </item>
    <item>
      <title>How to "permanently" remove annoying websites from your google's search result</title>
      <dc:creator>lechat</dc:creator>
      <pubDate>Wed, 14 Aug 2024 17:55:45 +0000</pubDate>
      <link>https://dev.to/lechatthecat/how-to-remove-annoying-websites-from-your-search-result-3mfo</link>
      <guid>https://dev.to/lechatthecat/how-to-remove-annoying-websites-from-your-search-result-3mfo</guid>
      <description>&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;I dislike annoying websites like pinterest or tiktok. I don't want to create an account just to see some normal pictures or some short videos of baseball. I want those to disappear from my google search result, so I always search like "baseball -tiktok", but I don't want to write "-tiktok" every time I google search, so I checked how to make it default. &lt;/p&gt;

&lt;p&gt;After writing this article, I realized that with this approach, it would also filter out news articles that have 'TikTok' in the title. So, instead of just 'TikTok,' it might be better to specify the URL, like using -inurl:tiktok. If this concerns you, give it a try this:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;&lt;a href="https://www.google.com/search?q=-site:tiktok.*+-site:*.tiktok.*+-site:pinterest.*+-site:*.pinterest.*+%s" rel="noopener noreferrer"&gt;https://www.google.com/search?q=-site:tiktok.*+-site:*.tiktok.*+-site:pinterest.*+-site:*.pinterest.*+%s&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Android&lt;br&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install &lt;code&gt;kiwi browser&lt;/code&gt; from playstore.&lt;/li&gt;
&lt;li&gt;Write &lt;code&gt;chrome://settings/&lt;/code&gt; in the kiwi browser's search bar.&lt;/li&gt;
&lt;li&gt;Click on the browser configuration icon
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcg1xdjbfb6m32gyfkdry.png" alt="Image description"&gt;
&lt;/li&gt;
&lt;li&gt;You will find &lt;code&gt;Search engine&lt;/code&gt;. Tap it. Then tap on the &lt;code&gt;Manage search engines..&lt;/code&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8plk0h6x6luzm2bp507y.png" alt="Image description"&gt;
&lt;/li&gt;
&lt;li&gt;Add a new search engine from &lt;code&gt;Add&lt;/code&gt; of &lt;code&gt;Site search&lt;/code&gt;. The name and keyword of the new search engine to be added can be anything like &lt;code&gt;noiseless google&lt;/code&gt; for the name and &lt;code&gt;@nggl&lt;/code&gt; for the keyword. The url for the new search engine is &lt;code&gt;https://www.google.com/search?q=-tiktok+-pinterest+%s&lt;/code&gt; and save it.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftev39lfpb9q234m6hnr3.png" alt="Image description"&gt;
&lt;/li&gt;
&lt;li&gt;Make this the default search engine.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frrvhrqb17ewb5yswn066.png" alt="Image description"&gt; &lt;/li&gt;
&lt;li&gt;Now, when you google something from your chrome browser, your search result filters the specified websites by default. 
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9mxbvnlduybffml1mz6.png" alt="Image description"&gt;
&lt;/li&gt;
&lt;li&gt;Please note that you can restore to the old search engine configuration from kiwi browser's &lt;code&gt;Setting&lt;/code&gt; page.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpuir8b16mfo2gay4f5cg.png" alt="Image description"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  PC chrome
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open Chrome browser&lt;/li&gt;
&lt;li&gt;Write &lt;code&gt;chrome://settings/&lt;/code&gt; in the chrome browser's search bar.&lt;/li&gt;
&lt;li&gt;Look for &lt;code&gt;Search&lt;/code&gt; configuration and open it. Click on the &lt;code&gt;Manage search engines..&lt;/code&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wdm3br2wshnby6negie.png" alt="Image description"&gt;
&lt;/li&gt;
&lt;li&gt;Add a new search engine from the lowest of the list. The name and keyword of the new search engine to be added can be anything like &lt;code&gt;noiseless google&lt;/code&gt; for the name and &lt;code&gt;@nggl&lt;/code&gt; for the keyword. The url for the new search engine is &lt;code&gt;https://www.google.com/search?q=-tiktok+-pinterest+%s&lt;/code&gt; and save it.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4ajw662xqpid2196lvk.png" alt="Image description"&gt;
&lt;/li&gt;
&lt;li&gt;Make this the default search engine.&lt;/li&gt;
&lt;li&gt;Now, when you google something from your browser, your search result filters the specified websites by default. &lt;/li&gt;
&lt;li&gt;Please note that you can restore to the old search engine configuration from the browser's &lt;code&gt;Setting&lt;/code&gt; page.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://conpath.net/columns/filter-google-search-results-by-default/" rel="noopener noreferrer"&gt;https://conpath.net/columns/filter-google-search-results-by-default/&lt;/a&gt;
Images of &lt;code&gt;PC chrome&lt;/code&gt; section are cited from here&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  See also
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://noteoneverything.blogspot.com/2017/07/contents-1.html" rel="noopener noreferrer"&gt;https://noteoneverything.blogspot.com/2017/07/contents-1.html&lt;/a&gt;
my blog&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>productivity</category>
      <category>browser</category>
      <category>android</category>
    </item>
    <item>
      <title>My language now can make instances</title>
      <dc:creator>lechat</dc:creator>
      <pubDate>Sun, 10 Jul 2022 02:23:56 +0000</pubDate>
      <link>https://dev.to/lechatthecat/my-language-now-can-make-instances-4hel</link>
      <guid>https://dev.to/lechatthecat/my-language-now-can-make-instances-4hel</guid>
      <description>&lt;p&gt;I made &lt;a href="https://github.com/lechatthecat/marie"&gt;a language&lt;/a&gt; and the language now can make instances:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"john"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"cat"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;A&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="py"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="nf"&gt;.f&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wow, I'm happy for this :)&lt;/p&gt;

</description>
      <category>rust</category>
      <category>diy</category>
      <category>showdev</category>
    </item>
    <item>
      <title>You sure you will go with Laravel Horizon?</title>
      <dc:creator>lechat</dc:creator>
      <pubDate>Thu, 17 Feb 2022 12:55:00 +0000</pubDate>
      <link>https://dev.to/lechatthecat/you-sure-go-with-laravel-horizon-2o52</link>
      <guid>https://dev.to/lechatthecat/you-sure-go-with-laravel-horizon-2o52</guid>
      <description>&lt;p&gt;You sure you will go with Laravel horizon? In some cases, you shouldn't. Especially when you use Redis cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Horizon doesn't work with Redis cluster
&lt;/h3&gt;

&lt;p&gt;Horizon doesn't work with Redis cluster if it has multiple shards. But this is not mentioned &lt;a href="https://laravel.com/docs/9.x/horizon#:~:text=Laravel%20Horizon%20provides%20a%20beautiful,%2C%20runtime%2C%20and%20job%20failures." rel="noopener noreferrer"&gt;in the doc&lt;/a&gt;. You will notice it when you increase number of shards of Redis cluster, or when you find &lt;a href="https://github.com/laravel/horizon/issues/274#issuecomment-457218217" rel="noopener noreferrer"&gt;this issue&lt;/a&gt;. As a workaround, I tried hash tag keys, but Laravel horizon still didn't work alongside Redis cluster with mutiple shards.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Laravel queues work with Redis cluster?
&lt;/h3&gt;

&lt;p&gt;On the other hand, &lt;a href="https://laravel.com/docs/9.x/queues#redis" rel="noopener noreferrer"&gt;queues&lt;/a&gt; of Laravel seems working with Redis cluster. It's confusing to me. Please note that I haven't tested queues alongside Redis cluster with multiple shards, so actually I don't know if it really works, but queues seems better bet. &lt;/p&gt;

&lt;p&gt;Even if you go with laravel queues, if you use database driver with MySQL that is older than 8.0, &lt;a href="https://divinglaravel.com/a-production-ready-database-queue-diver-for-laravel" rel="noopener noreferrer"&gt;it might cause deadlocks&lt;/a&gt;. I think this is not mentioned in the doc too.&lt;/p&gt;

&lt;h3&gt;
  
  
  You cannot use multi/exec/watch/unwatch in Redis cluster with multiple shards (at least with predis)
&lt;/h3&gt;

&lt;p&gt;You know, to keep data consistency, you sometimes must  use watch/unwatch/multi/exec (to start something like transaction) to save dave data in Redis. &lt;a href="https://github.com/predis/predis/issues/275#issuecomment-133649461" rel="noopener noreferrer"&gt;But this doesn't work in redis cluster&lt;/a&gt;. It might work in your dev environment that uses single Redis node but not in production that uses Redis cluster with multiple shards.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In some situations, queues is a better bet.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>laravel</category>
      <category>redis</category>
    </item>
    <item>
      <title>I made an android app that has JS quizzes and you can write and run answers inside </title>
      <dc:creator>lechat</dc:creator>
      <pubDate>Tue, 21 Sep 2021 15:30:11 +0000</pubDate>
      <link>https://dev.to/lechatthecat/i-made-android-app-that-has-js-quizzes-and-you-can-write-answers-inside-4o9c</link>
      <guid>https://dev.to/lechatthecat/i-made-android-app-that-has-js-quizzes-and-you-can-write-answers-inside-4o9c</guid>
      <description>&lt;p&gt;Do you know websites like Confingbat? I really like that kind of websites and spent a lot of time to solve programming quizzes there.&lt;/p&gt;

&lt;p&gt;But, after solving many quizzes there, I wondered if there is an android app where you can do something like that. It would be better if I could solve quizzes on android app. You know, it would be more relaxing if I could do it on sofa or bed with my phone.&lt;/p&gt;

&lt;p&gt;Well, as far as I searched, I could not find any android app like that.&lt;/p&gt;

&lt;p&gt;So I made such android app by myself. On this Android app, with Javascript, you can solve quizzes by writing and running the answer directly on the app. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.notesoneverythin.jsprogrammingprac"&gt;https://play.google.com/store/apps/details?id=com.notesoneverythin.jsprogrammingprac&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>javascript</category>
      <category>android</category>
    </item>
    <item>
      <title>SPA with Springboot+JWT+Vue.js+Web socket </title>
      <dc:creator>lechat</dc:creator>
      <pubDate>Sun, 20 Jun 2021 12:59:06 +0000</pubDate>
      <link>https://dev.to/lechatthecat/spa-with-springboot-jwt-vue-js-web-socket-day-2-27o4</link>
      <guid>https://dev.to/lechatthecat/spa-with-springboot-jwt-vue-js-web-socket-day-2-27o4</guid>
      <description>&lt;p&gt;As I wrote before, I made a &lt;a href="https://dev.to/lechatthecat/spa-with-springboot-jwt-vue-js-web-socket-48c4"&gt;SPA with Springboot+JWT+Vue.js+Web socket&lt;/a&gt;, but only a few people tested it, maybe because, to test the project, people needed to prepare Postgresql by themselves. It is really tiring to install and init DB. Even worse, it is also tiring removing DB once it is installed.&lt;/p&gt;

&lt;p&gt;So, today, I moved the Postgresql DB in docker container. And if you want to test my project, you can do the preparation almost automatically. And it is very easy to remove containers after testing.&lt;/p&gt;

&lt;p&gt;You can test the project from here:&lt;br&gt;
&lt;a href="https://github.com/lechatthecat/JavaChatSPA"&gt;https://github.com/lechatthecat/JavaChatSPA&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How to test the project
&lt;/h2&gt;

&lt;p&gt;Prerequisites&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java 11&lt;/li&gt;
&lt;li&gt;Maven 3.*&lt;/li&gt;
&lt;li&gt;Docker 20.10.6&lt;/li&gt;
&lt;li&gt;Docker-compose 1.29.1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone https://github.com/lechatthecat/JavaChatSPA.git
$ cd JavaChatSpa
$ docker-compose up -d --build
$ npm i
$ npm run build
$ mvn clean package
$ mvn spring-boot:run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Working example:&lt;br&gt;
&lt;a href="https://chatboard.page/boards/lounge/0"&gt;https://chatboard.page/boards/lounge/0&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>showdev</category>
      <category>vue</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Let's use reduce, map, filter, foreach and be more functional in javascript</title>
      <dc:creator>lechat</dc:creator>
      <pubDate>Fri, 16 Apr 2021 15:50:51 +0000</pubDate>
      <link>https://dev.to/lechatthecat/let-s-use-reduce-map-filter-foreach-and-be-more-functional-g85</link>
      <guid>https://dev.to/lechatthecat/let-s-use-reduce-map-filter-foreach-and-be-more-functional-g85</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="c1"&gt;// 10 &lt;/span&gt;
&lt;span class="c1"&gt;// Elements reduced to one value&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="c1"&gt;// [6,7,8,9] &lt;/span&gt;
&lt;span class="c1"&gt;// Do something for each value and make a new array&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;  &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="c1"&gt;// [2,4] &lt;/span&gt;
&lt;span class="c1"&gt;// Filter the elements and make a new array&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array1&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;array1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)});&lt;/span&gt;
&lt;span class="c1"&gt;// For each loop.&lt;/span&gt;

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

&lt;/div&gt;



</description>
      <category>functional</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>As a first project in Rust, I made a programming language on my own</title>
      <dc:creator>lechat</dc:creator>
      <pubDate>Sat, 20 Mar 2021 14:23:52 +0000</pubDate>
      <link>https://dev.to/lechatthecat/as-a-first-project-in-rust-i-made-a-programming-language-3mg9</link>
      <guid>https://dev.to/lechatthecat/as-a-first-project-in-rust-i-made-a-programming-language-3mg9</guid>
      <description>&lt;p&gt;This is the project:&lt;br&gt;
&lt;a href="https://github.com/lechatthecat/oran"&gt;https://github.com/lechatthecat/oran&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can test it by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone https://github.com/lechatthecat/oran.git
$ cd oran
$ cargo build --release
$ ./target/release/oran -f ./examples/hello.orn
$ ./target/release/oran -f ./examples/example.orn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Motivation
&lt;/h3&gt;

&lt;h3&gt;
  
  
  1. Rust seems cool, so I wanted to make something.
&lt;/h3&gt;

&lt;p&gt;And I think it is a very nice language.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. String concatenation or addition of numbers?
&lt;/h3&gt;

&lt;p&gt;In many scripting languages, the concatenation of string is done by &lt;code&gt;"aaaa" + "bbbb"&lt;/code&gt;. This will make a value &lt;code&gt;"aaaabbbb"&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;I really don't like this syntax. Let's suppose that we just want to add up two integers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let val = 5 + 6;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and what if they happen to be String typed integers?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let val = "5" + "6";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variable &lt;code&gt;val&lt;/code&gt;'s value will end up being "56" because both of them are String, not integers.&lt;/p&gt;

&lt;p&gt;If they aren't stored in variables, it is obvious that you need to change them to numbers beforehand, but what if they are stored in variables?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let val = varfive + varsix;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value of val cannot be known until I check the value in debug mode. Even though I just wanted 11 out of &lt;code&gt;5 + 6&lt;/code&gt;, the value is actually "56". This would cause a serious bug.&lt;/p&gt;

&lt;p&gt;The problem is, in most scripting languages, you cannot know what type the variables have. In scripting languages, variable types are dynamically changed.&lt;/p&gt;

&lt;p&gt;So in my language, you have to use "&amp;lt;&amp;lt;" to concatenate string values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;test&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c"&gt;// Like this.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When "&amp;lt;&amp;lt;" is used, the variables are always treated as String. Meanwhile, when "+" is used, the variables are always treated as numbers.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Immutability
&lt;/h3&gt;

&lt;p&gt;Immutable variables are not often used in scripting languages like PHP, Python, Ruby. But immutable/mutable variables are often used in Javascript by putting const/let in front of variable names. I feel this is quite useful feature, that should be available in PHP, Python, Ruby also. And if variables are immutable by default like in Rust, it is even better.&lt;/p&gt;

&lt;p&gt;So in my language, variables are immutable by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;test&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;'hey&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;// Error!!&lt;/span&gt;
    &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have to use &lt;code&gt;mut&lt;/code&gt; to make it mutable variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;test&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;'hey&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;// Now it works.&lt;/span&gt;
    &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Rust is a great language even though I am not familiar with this language at all. The good point of Rust is, the more I learn this language, the more nice things I can get to know, like, immutable variables, option and match, memory management, difference between passing by val and by ref, functional programming style etc... &lt;/p&gt;

</description>
      <category>showdev</category>
      <category>rust</category>
      <category>programminglanguage</category>
    </item>
  </channel>
</rss>
