This repository has been archived on 2024-02-11. You can view files and clone it, but cannot push or open issues or pull requests.
sitio/cached-feeds/nexxel.xml

1344 lines
118 KiB
XML

<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss/styles.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>nexxel&apos;s blog</title><description>Writings on programming and technology.</description><link>https://www.nexxel.dev/</link><item><title>Ricing MacOS</title><link>https://www.nexxel.dev/blog/ricing-macos/</link><guid isPermaLink="true">https://www.nexxel.dev/blog/ricing-macos/</guid><description>My MacOS Rice.</description><pubDate>Wed, 01 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Link from &quot;../../components/Link.vue&quot;;
import Code from &quot;../../components/Code.vue&quot;;
import { createHeading } from &quot;../../components/Heading&quot;;&lt;/p&gt;
&lt;p&gt;export const components = {
a: Link,
code: Code,
h1: createHeading(&quot;h1&quot;),
h2: createHeading(&quot;h2&quot;),
h3: createHeading(&quot;h3&quot;),
};&lt;/p&gt;
&lt;p&gt;Recently a screenshot of my MacOS rice blew up on X (formerly Twitter), eventually becoming &lt;a href=&quot;https://x.com/nexxeln/status/1715433387337642135/&quot;&gt;my most liked post&lt;/a&gt; of all time.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I&apos;ve been asked a lot about my setup, so I decided to write a blog post about it.&lt;/p&gt;
&lt;h2&gt;Window Manager&lt;/h2&gt;
&lt;p&gt;There&apos;s only one decent tiling window manager for MacOS, and that&apos;s &lt;a href=&quot;https://github.com/koekeishiya/yabai/&quot;&gt;yabai&lt;/a&gt;. It allows you to control your windows and spaces by using a CLI, for which you can set hotkeys using &lt;a href=&quot;https://github.com/koekeishiya/skhd&quot;&gt;skhd&lt;/a&gt;. yabai is a tiling window manager, which means it automatically arranges and resizes your open application windows in a non-overlapping manner. It allows you to move and manipulate windows in various ways, including moving windows to different spaces and changing the layout of spaces along with a whole lot of other features.&lt;/p&gt;
&lt;p&gt;It&apos;s probably not as good as some of the amazing window managers available for Linux such as &lt;a href=&quot;https://madnight.github.io/bspwm&quot;&gt;bspwm&lt;/a&gt; or &lt;a href=&quot;https://hyprland.org/&quot;&gt;hyprland&lt;/a&gt; but it works and I haven&apos;t had any problems with it so far.&lt;/p&gt;
&lt;p&gt;To install yabai, go through the &lt;a href=&quot;https://github.com/koekeishiya/yabai/wiki&quot;&gt;yabai wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&apos;s my yabai config:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ~/.config/yabai/yabairc
# bsp, stack or float
yabai -m config layout bsp
yabai -m config window_placement second_child
# padding
yabai -m config window_gap 12
yabai -m config top_padding 4
yabai -m config bottom_padding 4
yabai -m config right_padding 4
yabai -m config left_padding 4
# mouse settings
yabai -m config mouse_follows_focus on
yabai -m config mouse_modifier alt
# left click and drag
yabai -m config mouse_action1 move
# right click and drag
yabai -m config mouse_action2 resize
yabai -m config mouse_drop_action swap
# disable yabai for these apps
yabai -m rule --add app=&quot;^Discord$&quot; manage=off
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Hotkey Daemon&lt;/h1&gt;
&lt;p&gt;yabai is usally paired with &lt;a href=&quot;https://github.com/koekeishiya/skhd&quot;&gt;skhd&lt;/a&gt; which is an excellent hotkey daemon for MacOS. It utilizes a very simple DSL to define hotkeys. Using skhd, you can setup hotkeys for quickly executing yabai commands.&lt;/p&gt;
&lt;p&gt;To install skhd follow &lt;a href=&quot;https://github.com/koekeishiya/skhd#install&quot;&gt;this guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&apos;s my skhd config:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ~/.config/skhd/skhdrc
# start and stop
ctrl + alt - q: yabai --stop-service
ctrl + alt - s: yabai --start-service
# changing window focus
alt - s: yabai -m window --focus south
alt - w: yabai -m window --focus north
alt - a: yabai -m window --focus west
alt - d: yabai -m window --focus east
# rotate layout clockwise
shift + alt - c: yabai -m space --rotate 270
# rotate layout anti-clockwise
shift + alt - a: yabai -m space --rotate 270
# flip alone x-axis
shift + alt - x: yabai -m space -- mirror x-axis
# flip along y-axis
shift + alt - y: yabai -m space --mirror y-axis
# toggle window float
shift + alt - t: yabai -m window --toggle float --grid 4:4:1:1:2:2
# maximize a window
shift + alt - m: yabai -m window --toggle zoom-fullscreen
# reset window size
shift + alt - e: yabai -m space --balance
# swap windows
shift + alt - h: yabai -m window --swap west
shift + alt - j: yabai -m window --swap south
shift + alt - k: yabai -m window --swap north
shift + alt - l: yabai -m window --swap east
# move window and split
ctrl + alt - h: yabai -m window --warp west
ctrl + alt - j: yabai -m window --warp south
ctrl + alt - k: yabai -m window --warp north
ctrl + alt - l: yabai -m window --warp east
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I typically use vim keybindings for most things, but here I make one execption when it comes to changing window focus. I find it more convenient to use the &lt;code&gt;wasd&lt;/code&gt; keys for this purpose because they&apos;re closer to the left &lt;code&gt;option&lt;/code&gt; key.&lt;/p&gt;
&lt;h1&gt;Terminal Emulator&lt;/h1&gt;
&lt;p&gt;I use &lt;a href=&quot;https://alacritty.org&quot;&gt;Alacritty&lt;/a&gt; as my terminal. It&apos;s super fast and customizable. I have written about it in my previous blog posts as well. Since then my configuration has udpated and now I have a pretty minimal yet aesthetic config.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ~/.config/alacritty/alacritty.yml
env:
TERM: xterm-256color
font:
size: 14
normal:
family: &quot;Dank Mono&quot;
style: Regular
bold:
style: Bold
italic:
style: Italic
bold_italic:
style: Bold Italic
window:
option_as_alt: Both
# Window padding (changes require restart)
#
# Blank space added around the window in pixels. This padding is not scaled by
# DPI and the specified value is always added at both opposing sides.
padding:
x: 12
y: 12
# Spread additional padding evenly around the terminal content.
dynamic_padding: false
# Window decorations
decorations: buttonless
#
# Startup Mode (changes require restart)
#
# Values for `startup_mode`:
# - Windowed
# - Maximized
# - Fullscreen
#
# Values for `startup_mode` (macOS only):
# - SimpleFullscreen
startup_mode: Windowed
# Background opacity
opacity: 1
# Colors (Mellow)
colors:
# Default colors
primary:
background: &quot;#161617&quot;
foreground: &quot;#c9c7cd&quot;
# Cursor colors
cursor:
text: &quot;#c9c7cd&quot;
cursor: &quot;#757581&quot;
# Normal colors
normal:
black: &quot;#27272a&quot;
red: &quot;#f5a191&quot;
green: &quot;#90b99f&quot;
yellow: &quot;#e6b99d&quot;
blue: &quot;#aca1cf&quot;
magenta: &quot;#e29eca&quot;
cyan: &quot;#ea83a5&quot;
white: &quot;#c1c0d4&quot;
# Bright colors
bright:
black: &quot;#353539&quot;
red: &quot;#ffae9f&quot;
green: &quot;#9dc6ac&quot;
yellow: &quot;#f0c5a9&quot;
blue: &quot;#b9aeda&quot;
magenta: &quot;#ecaad6&quot;
cyan: &quot;#f591b2&quot;
white: &quot;#cac9dd&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Editor&lt;/h1&gt;
&lt;p&gt;Dont&apos;t worry, I still primarily use VSCode for anything serious, but I did create a new Neovim configuration from scratch which I don&apos;t plan on updating frequently. I kept it quite minimal and used very few plugins. Here&apos;s Neovim and VSCode side by side.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nexxeln/dots/tree/main/Library/Application%20Support/Code%20-%20Insiders/User&quot;&gt;VSCode config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nexxeln/dots/tree/main/.config/nvim&quot;&gt;Neovim config&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This isn&apos;t a blog post I necessarily wanted to write but I kind of had to because the X post blew up. Hopefully it serves you as a good reference for configuring your Mac.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nexxeln/dots&quot;&gt;Dotfiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://x.com/nexxeln/status/1715433387337642135/&quot;&gt;X Post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>How I Organise My Life</title><link>https://www.nexxel.dev/blog/organising-life/</link><guid isPermaLink="true">https://www.nexxel.dev/blog/organising-life/</guid><description>In this post, I share the apps and the simplistic approach I use to organise my life.</description><pubDate>Thu, 03 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Link from &quot;../../components/Link.vue&quot;;
import Code from &quot;../../components/Code.vue&quot;;
import { createHeading } from &quot;../../components/Heading&quot;;&lt;/p&gt;
&lt;p&gt;export const components = {
a: Link,
code: Code,
h1: createHeading(&quot;h1&quot;),
h2: createHeading(&quot;h2&quot;),
h3: createHeading(&quot;h3&quot;),
};&lt;/p&gt;
&lt;p&gt;Over the last few months, I&apos;ve set out to really get my life sorted and organised so I can manage my time and thoughts better. I have explored numerous apps, and &quot;productivity setups&quot;, searching for that seamless integration that could bring a sense of order to my chaotic mind and life. But nothing quite hit the mark until recently.&lt;/p&gt;
&lt;p&gt;This is not going to be one of complex setups that you often see productivity influencers making videos and courses about. I actually rejected Obsidian once because I found it really overwhelming after watching a YouTube video setting it up so extensively, reminiscent to configuring &lt;a href=&quot;https://www.gnu.org/software/emacs/&quot;&gt;Emacs&lt;/a&gt;. In my opinion, people watch these second brain and personal knowledge management setup videos and think it&apos;s the holy grail of productivity. They fall into the trap of constantly looking for the perfect app and the perfect setup, always trying to optimise their workflow when they&apos;re actually just wasting their time without actually focusing on what&apos;s important: getting stuff done.&lt;/p&gt;
&lt;p&gt;My setup embraces simplicity. Here&apos;s what I wanted from my workflow.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Note taking app: Has to have &lt;a href=&quot;https://help.obsidian.md/Plugins/Backlinks&quot;&gt;backlinks&lt;/a&gt; and a simple way to organise notes by topics. Should sync across all devices&lt;/li&gt;
&lt;li&gt;Calendar app: Creating and editing events should be fast. Also needs to have good NLP for dates and sync with my phone&apos;s calendar widget.&lt;/li&gt;
&lt;li&gt;Tasks app: Should be easy to quickly add tasks. Has to have good NLP (Natural Language Processing) for dates Also should sync across all devices&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So here are my apps of choice and how I use them.&lt;/p&gt;
&lt;h2&gt;Note Taking App: Obsidian&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://obsidian.md&quot;&gt;Obsidian&lt;/a&gt; is my choice of app for note taking. As I mentioned in the intro, I had used it previously in a very complex and overwhelming setup for a week which just didn&apos;t feel right. Almost all videos of Obsidian on YouTube were like that. So I had rejected the app back then.&lt;/p&gt;
&lt;p&gt;Fast forward a few months and I saw Obsidian gaining popularity again on Twitter and Discord, so I decided to give it another try, only this time, I read the docs instead of videos. I soon realised the simplicity of Obsidian. It&apos;s just notes in Markdown, stored in a folder, called &quot;Vault&quot; in Obsidian. You can link to other notes using standard Markdown syntax and also group notes by topic using sub-folders or tags.&lt;/p&gt;
&lt;h3&gt;Why I Like Obsidian&lt;/h3&gt;
&lt;p&gt;Obsidian has an elegant user interface with an one of the best if not &lt;strong&gt;the&lt;/strong&gt; best Markdown editors out there which make the note-taking experience smooth and natural. My favourite part is that it supports vim keybindings in the editor! It also features a nice command palette in which all the commands can be triggered by hotkeys as well. With thousands of plugins available, it gives you tools to do pretty much anything.&lt;/p&gt;
&lt;p&gt;But where Obsidian really won me over is privacy. Notes are saved in a local folder and never go to a database. It also doesn&apos;t store notes in a weird Obsidian specific format, it&apos;s just standard Markdown! It allows you to own and control your data.&lt;/p&gt;
&lt;h3&gt;How I Take Notes&lt;/h3&gt;
&lt;p&gt;All notes live in the root of my Obsidian vault. I don&apos;t use sub-directories. Whenever I need to make a new note, I just create the file in the root. To group notes by particular topics, I use tags. For example, recently I had a very cool idea to sell canned carbonated sugarcane juice, which I&apos;m not sure will taste good by the way. So I created a note for it and put the appropriate tags for it in the frontmatter.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;It&apos;s a topic which is interesting to me and also a cool idea that I might revisit and explore in the future.&lt;/p&gt;
&lt;p&gt;I also really like links in Obsidian. A few days ago, I had been diving deep into purple coloured stones because they look really cool. So I created a note titled &quot;Purple Stones&quot; to keep track of my research. In the &quot;Purple Stones&quot; note, I made a list of all the purple stones that caught my eye with a short description of each of them. But instead of cramming detailed information for each of the stones, I created a separate note dedicated to each stone with all the information I got from my research.&lt;/p&gt;
&lt;p&gt;So now, when I click on any stone&apos;s name in the &quot;Purple Stones&quot; note, it takes me to its dedicated note where I can immerse myself in all the information about that particular stone.&lt;/p&gt;
&lt;p&gt;I was also on the hunt for cool desk decorations and created a note for it. As I was researching common desk decorations I came across the idea of using beautiful rocks as decorations. So I instantly linked my note on amethyst because raw amethyst looks stunning. Obsidian also has a really cool backlinks feature, whenever I visit my amethyst note, I can also see a list of all the other notes where amethyst was mentioned. It&apos;s like having a web of interconnected knowledge!&lt;/p&gt;
&lt;p&gt;Links have become a huge part of my Obsidian workflow. Each note leads to even more pathways of things I&apos;ve researched, ideas I&apos;ve had, or cool things I&apos;ve discovered. It&apos;s as if my notes have formed a collection of interconnected nodes, guiding me through my exploration of different topics and keeping everything neatly organised.&lt;/p&gt;
&lt;h3&gt;What I Take Notes Of&lt;/h3&gt;
&lt;p&gt;I take notes of pretty much everything.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Any idea that comes to mind&lt;/li&gt;
&lt;li&gt;Anything interesting I come across&lt;/li&gt;
&lt;li&gt;Videos or blog posts that make me think, I break down the key points&lt;/li&gt;
&lt;li&gt;Cool thoughts and random musings&lt;/li&gt;
&lt;li&gt;Research on various topics&lt;/li&gt;
&lt;li&gt;Planning blog posts and events&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also Obsidian is simply the best Markdown editor I have ever used so I just use it for writing anything.&lt;/p&gt;
&lt;h3&gt;How I Navigate Notes&lt;/h3&gt;
&lt;p&gt;As I had written in the previous section, links really help in exploring and guiding you through your notes. It&apos;s like having interconnected nodes of knowledge I had said. Well Obsidian has this really feature called &quot;Graph View&quot; which lets you visualise your entire vault. Each note becomes a node and these nodes are connected to each other using the links you create.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;In the Graph View you can easily search for everything, including notes, tags, and also visualise how your notes are linked.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I have heard some people saying that the Graph View is not useful, but I find it to be a natural and intuitive way to navigate my notes. It&apos;s much better than the regular search experience for me.&lt;/p&gt;
&lt;p&gt;To make note navigation even faster and more efficient, I use a plugin called &lt;a href=&quot;https://github.com/scambier/obsidian-omnisearch&quot;&gt;Omnisearch&lt;/a&gt;. It enhances the search functionality in Obsidian with OCR and a smart weighting algorithm. Plus, it supports vim keybindings, which I love. It reminds me of the &lt;a href=&quot;https://github.com/nvim-telescope/telescope.nvim&quot;&gt;Telescope&lt;/a&gt; plugin in Neovim.&lt;/p&gt;
&lt;h3&gt;Syncing Notes&lt;/h3&gt;
&lt;p&gt;Syncing notes across in Obsidian can be done in different ways. While Obsidian offers a paid &lt;a href=&quot;https://obsidian.md/sync&quot;&gt;Sync&lt;/a&gt; service for seamless synchronisation across devices, I personally use a different approach since I cannot afford it at the moment.&lt;/p&gt;
&lt;p&gt;Since Obsidian stores notes as local files in a folder, you can easily sync them using cloud storage services like &lt;a href=&quot;https://google.com/drive&quot;&gt;Google Drive&lt;/a&gt; or &lt;a href=&quot;https://dropbox.com&quot;&gt;Dropbox&lt;/a&gt;. Another option is using &lt;a href=&quot;https://syncthing.net/&quot;&gt;Syncthing&lt;/a&gt; which is what I use. It&apos;s an open-source, encrypted file synchronisation program. I find Syncthing convenient because it allows me to sync my files locally between my Mac and Android phone without sending data over the internet. It&apos;s a simple and secure solution for keeping my notes in sync across devices. I really like it.&lt;/p&gt;
&lt;h3&gt;Publishing Notes&lt;/h3&gt;
&lt;p&gt;When I used to use &lt;a href=&quot;https://notion.so&quot;&gt;Notion&lt;/a&gt;, I loved the publish feature that allowed me to share notes easily with a link. Obsidian also offers a similar feature through its paid &lt;a href=&quot;https://obsidian.md/publish&quot;&gt;Publish&lt;/a&gt; service, but it&apos;s not within my budget. So, I decided to create my own Obsidian publish solution using &lt;a href=&quot;https://rust-lang.org&quot;&gt;Rust&lt;/a&gt;. It&apos;s a command-line tool that scans my Obsidian vault for notes with &lt;code&gt;publish: true&lt;/code&gt; in the metadata (similar to the official Publish plugin). It then converts the Markdown notes to HTML and deploys them to the internet. While I&apos;m still refining the static site generator, my plan is to open-source it once it&apos;s ready for broader use. This way, others can benefit from it as well.&lt;/p&gt;
&lt;h3&gt;Plugins&lt;/h3&gt;
&lt;p&gt;I use just three plugins:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minimal Theme Settings, which is the plugin to configure the &lt;a href=&quot;https://minimal.guide&quot;&gt;Minimal Theme&lt;/a&gt; for a clean and minimalistic UI.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/scambier/obsidian-omnisearch&quot;&gt;OmniSearch&lt;/a&gt;, which is a better and quicker search.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/adriandersen/obsidian-fuzzytag&quot;&gt;FuzzyTag&lt;/a&gt;, which provides autocomplete for tags while writing them in the frontmatter.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hopefully this shows that you don&apos;t need ten different plugins to make Obsidian functional. It&apos;s already enough for whatever you want to do.&lt;/p&gt;
&lt;h2&gt;Tasks App: Todoist&lt;/h2&gt;
&lt;p&gt;When it comes to managing tasks, I prefer to keep my notes and tasks separate. While some people might use Obsidian for todo-lists, I find it more comfortable to use a dedicated task app.&lt;/p&gt;
&lt;p&gt;My go-to task app is &lt;a href=&quot;https://todoist.com/&quot;&gt;Todoist&lt;/a&gt;. &lt;a href=&quot;https://frantic.im/todo-for-robots/&quot;&gt;Despite todo apps being broken&lt;/a&gt;, Todoist &lt;em&gt;works fine&lt;/em&gt;. It has a nice UI which allows for adding tasks quickly, even when on the go, thanks to its convenient widget. It has excellent natural language processing, it understands dates and times in whatever broken english I use.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I particularly enjoy the satisfying sound it plays when I complete a task. Todoist&apos;s sub-tasks feature is incredibly useful for breaking down complex tasks into smaller, more manageable steps, which also happens to be perfect for shopping lists and check lists.&lt;/p&gt;
&lt;p&gt;I also use Todoist as a reminders app. A few days ago, I needed to wish a friend a safe journey for their upcoming long-distance travel, so I added a reminder in Todoist a week in advance, ensuring that I won&apos;t forget to send my well-wishes on the day.&lt;/p&gt;
&lt;h2&gt;Calendar App: Cron&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://cron.com&quot;&gt;Cron&lt;/a&gt; is my preferred Calendar app. It syncs with &lt;a href=&quot;https://calendar.google.com/calendar/u/0/r&quot;&gt;Google Calendar&lt;/a&gt; and features a clean and intuitive UI to for quickly creating and organising events. It offers all the features you&apos;d expect from a standard calendar app but with the added benefits of being keyboard-friendly, visually appealing, and it feels &lt;em&gt;fast&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;While Cron doesn&apos;t have an official Android app yet, I find that the Google Calendar app works fine. I really like the widget it provides and use it to stay updated with my schedule at a glance.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Embracing simplicity has been a great approach in organising my life so far. Let me know if you integrated something from this post in your workflow on X (ex Twitter) and if you enjoyed reading it.&lt;/p&gt;
&lt;p&gt;Thank you!&lt;/p&gt;
</content:encoded></item><item><title>Why I Switched From Neovim To VSCode</title><link>https://www.nexxel.dev/blog/neovim-to-vscode/</link><guid isPermaLink="true">https://www.nexxel.dev/blog/neovim-to-vscode/</guid><description>A few weeks ago I made the switch from Neovim to VScode as my primary code editor. Here&apos;s why.</description><pubDate>Fri, 23 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Link from &quot;../../components/Link.vue&quot;;
import Code from &quot;../../components/Code.vue&quot;;
import { createHeading } from &quot;../../components/Heading&quot;;&lt;/p&gt;
&lt;p&gt;export const components = {
a: Link,
code: Code,
h1: createHeading(&quot;h1&quot;),
h2: createHeading(&quot;h2&quot;),
h3: createHeading(&quot;h3&quot;),
};&lt;/p&gt;
&lt;p&gt;I recently switched back to VSCode from Neovim as my primary code editor. You may think this is weird because everyone seems to be going the other way around. Why would anyone want to move away from the most loved code editor? In this post, I&apos;ll explain why I made the switch and my experience so far.&lt;/p&gt;
&lt;h2&gt;Why I used Neovim in the past&lt;/h2&gt;
&lt;p&gt;When I first started to code, I used to use VSCode because that&apos;s what I saw most people use. But I noticed that on my old laptop, VSCode was too slow and laggy and pretty much unusable while running a side process like a Node server. My laptop used to get so hot that I couldn&apos;t even touch it! I was spending more time waiting for intellisense than actually writing code.&lt;/p&gt;
&lt;p&gt;I had heard of Neovim as it was the most loved editor on the Stack Overflow survey and also from YouTubers like &lt;a href=&quot;https://www.youtube.com/@ThePrimeagen&quot;&gt;ThePrimeagen&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/@teej_dv&quot;&gt;TJ DeVries&lt;/a&gt;. It seemed like a really fun community and the overall vibe was very positive. So I tried it out. I learnt vim keybindings, lua to configure Neovim, created my own config, and started using it as my primary editor.&lt;/p&gt;
&lt;p&gt;I loved it, it ran on the terminal, no Electron apps, no lag, no waiting for autocomplete. Everything was as smooth as butter and I felt &lt;em&gt;fast&lt;/em&gt;. Learning vim keybindings was one of the best decisions of my life. I know people like to meme about how vim enthusiasts are always trying to convince people to learn vim keybindings but I truly believe that learning it will not only make you faster but also rekindle your love for programming, it did for me.&lt;/p&gt;
&lt;p&gt;Neovim had a great plugin ecosystem, almost all the things that I used in VSCode were available in Neovim. It also made me realize that some things aren&apos;t necessary at all. For example, I used the file explorer extensively in VSCode but I didn&apos;t even install the plugin for it on Neovim. I started to understand the value of minimalism and how simplifying your setup can make you more productive.&lt;/p&gt;
&lt;p&gt;Configuring Neovim was also a lot of fun. It gives you full control over your editor and how it looks and behaves. It allowed to optimise my editor for &lt;em&gt;me&lt;/em&gt;, tailored to my specific needs. There&apos;s also something really satsifying about using an editor you configured yourself.&lt;/p&gt;
&lt;p&gt;All of this made me fall in love with Neovim and I can confidently say that it is my favourite editor of all the ones I&apos;ve used.&lt;/p&gt;
&lt;h2&gt;Why I Switched Back to VSCode&lt;/h2&gt;
&lt;p&gt;Here are the reasons why I switched back to VSCode in no particular order.&lt;/p&gt;
&lt;h3&gt;Copilot&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/features/copilot&quot;&gt;Copilot&lt;/a&gt; is an indispensable part of my workflow now. I can&apos;t imagine writing code without it. They have a Neovim plugin but my experience with it was not great. It was slow, and most of the time it didn&apos;t even work. The LSP used to keep crashing and I had to restart it every few minutes. Maybe this is just a problem with my setup but I couldn&apos;t find a solution to it.&lt;/p&gt;
&lt;p&gt;On the other hand, Copilot was built for VSCode. It works flawlessly and I haven&apos;t had any issues with it. There&apos;s also the new &lt;a href=&quot;https://github.com/features/preview/copilot-x&quot;&gt;GitHub Copilot X&lt;/a&gt; stuff, currently invite-only (I got an invite to test Copilot Chat) which only supports VSCode for now.&lt;/p&gt;
&lt;h3&gt;Tiring Neovim Plugin Ecosystem&lt;/h3&gt;
&lt;p&gt;Didn&apos;t I just say that Neovim has a great plugin ecosystem? Yes, it does. But it&apos;s also tiring to keep up with it. Running &lt;code&gt;:PackerSync&lt;/code&gt; was scary because you never know what plugin introduced a breaking change that you didn&apos;t notice and suddenly you can&apos;t code as your whole config breaks down.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Oh and now there&apos;s this new plugin manager that everyone is using called &lt;a href=&quot;https://github.com/folke/lazy.nvim&quot;&gt;lazy.nvim&lt;/a&gt; which is probably awesome but now I need to spend time migrating and getting used to it. It&apos;s kind of like the JavaScript ecosystem, there&apos;s always something new and shiny and you feel like you&apos;re missing out if you don&apos;t use it. It&apos;s tiring to keep up with it.&lt;/p&gt;
&lt;p&gt;At first, I was keeping up with the new plugins, trying them out, and making sure my config was up to date, but soon I was tired of it. I just wanted to code.&lt;/p&gt;
&lt;p&gt;VSCode&apos;s plugin ecosystem is great, installing extensions is a breeze and I don&apos;t have to worry about anything breaking. I can just focus on coding.&lt;/p&gt;
&lt;h3&gt;Configuration&lt;/h3&gt;
&lt;p&gt;As I mentioned earlier, configuring Neovim was fun but it was also tiring and time-consuming. As much as I loved tinkering my config everyday, I realized it was a distraction. I was spending more time configuring my editor than actually coding.&lt;/p&gt;
&lt;p&gt;I did love that I had full control over my editor though, and I think VSCode is quite configurable as well, probably not as much as Neovim but it&apos;s enough for me. I&apos;m still using vim keybindings. I have a nice theme. I choose what I want in the UI, where I want it, and how it looks. I have a few custom keybindings and snippets here and there, but overall it&apos;s pretty minimal.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;I Got a New Laptop&lt;/h3&gt;
&lt;p&gt;I recently got a new laptop, a M1 MacBook Air, and it&apos;s a beast. So running VSCode is not a problem anymore. Everything feels very smooth. Apple silicon is amazing and I&apos;m glad I switched to it.&lt;/p&gt;
&lt;p&gt;It&apos;s only gotten hot once when running some &lt;a href=&quot;https://code.visualstudio.com/docs/devcontainers/containers&quot;&gt;Docker Dev Containers&lt;/a&gt; along with Spotify, and my browser, which is understandable. But other than that, it&apos;s been great.&lt;/p&gt;
&lt;h3&gt;VSCode Only Tools&lt;/h3&gt;
&lt;p&gt;Some exceptional libraries and frameworks only support VSCode, which you could argue is a bad thing, but it makes sense, VSCode is the most popular code editor after all. For example &lt;a href=&quot;https://unocss.dev&quot;&gt;UnoCSS&lt;/a&gt; only has a VSCode extension, and it&apos;s my favourite way to write CSS. &lt;a href=&quot;https://astro.build&quot;&gt;Astro&lt;/a&gt; has a LSP but I&apos;ve found that the experience in VSCode is much better than in Neovim.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I&apos;ve also noticed that the TypeScript LSP is a bit faster in VSCode as well.&lt;/p&gt;
&lt;h2&gt;Why Not Use a Neovim Distro?&lt;/h2&gt;
&lt;p&gt;I don&apos;t like Neovim distributions. I&apos;ve tried many, and none of them had the same feel as a vanilla Neovim setup. Most of them are bloated, hard to extend, and have a lot of things I don&apos;t need. I don&apos;t want to spend time configuring a pre-configured editor. I&apos;d rather just configure it myself.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This doesn&apos;t mean that I&apos;m never going to use Neovim again. It&apos;s still my favourite editor and I&apos;ll be using it for minor editing tasks, tinkering stuff here and there on the terminal, taking notes, etc. But for my main editor, I&apos;m going to be using VSCode for now.&lt;/p&gt;
&lt;p&gt;Let me know if you enjoyed this post, and thank you for reading!&lt;/p&gt;
</content:encoded></item><item><title>Everything I Installed on My New Mac</title><link>https://www.nexxel.dev/blog/new-mac/</link><guid isPermaLink="true">https://www.nexxel.dev/blog/new-mac/</guid><description>I recently got a new Mac and decided to document everything I installed on it. This is a list of all the apps and tools I installed and will use on a daily basis.</description><pubDate>Fri, 02 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Link from &quot;../../components/Link.vue&quot;;
import Code from &quot;../../components/Code.vue&quot;;
import { createHeading } from &quot;../../components/Heading&quot;;&lt;/p&gt;
&lt;p&gt;export const components = {
a: Link,
code: Code,
h1: createHeading(&quot;h1&quot;),
h2: createHeading(&quot;h2&quot;),
h3: createHeading(&quot;h3&quot;),
};&lt;/p&gt;
&lt;p&gt;I recently got a new Mac and had to install a lot of apps and tools to get it set up. I decided to document everything I installed so I can refer back to it in the future and also share it with others who might find it useful.&lt;/p&gt;
&lt;h2&gt;Arc&lt;/h2&gt;
&lt;p&gt;I&apos;ve been recently using this pretty innovative new browser called &lt;a href=&quot;https://arc.net&quot;&gt;Arc&lt;/a&gt; and I must say, it&apos;s really cool! It is built on top of &lt;a href=&quot;https://www.chromium.org/Home/&quot;&gt;Chromium&lt;/a&gt; but what sets it apart is its unique features. Super customizable themes, &lt;a href=&quot;https://resources.arc.net/en/articles/6318861-spaces-distinct-browsing-areas&quot;&gt;Spaces&lt;/a&gt; for separating different workspaces, &lt;a href=&quot;https://resources.arc.net/en/articles/6808613-boosts-customize-any-website&quot;&gt;Boosts&lt;/a&gt; for remixing websites, and the best part is everything can be done without ever needing to touch your mouse, everything is keyboard accessible. There&apos;s still a lot for me to explore. Using Arc has been a breath of fresh air - everything feels so seamless and enjoyable, making browsing truly fun again. So if you&apos;re looking to try something different, check out Arc!&lt;/p&gt;
&lt;h2&gt;Raycast&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://raycast.com&quot;&gt;Raycast&lt;/a&gt; is a productivity tool that lets you search apps and do things just with a single keystroke. It&apos;s like Spotlight on steroids. I&apos;ve been using it for a while now and it&apos;s been a game-changer. I can&apos;t imagine using my Mac without it. I use it to open apps, search files, run scripts, and so much more. It has a vibrant ecosystem of extensions that you can install to do even more. I highly recommend checking it out.&lt;/p&gt;
&lt;h2&gt;Alacritty&lt;/h2&gt;
&lt;p&gt;Alacritty is my terminal of choice. It&apos;s super customizable and plenty fast. It doesn&apos;t get in your way and just lets you get things done. It doesn&apos;t have tabs like &lt;a href=&quot;https://iterm2.com/&quot;&gt;iTerm&lt;/a&gt; or &lt;a href=&quot;https://sw.kovidgoyal.net/kitty/&quot;&gt;Kitty&lt;/a&gt; but I don&apos;t mind that because I use it with &lt;a href=&quot;https://en.wikipedia.org/wiki/Tmux&quot;&gt;tmux&lt;/a&gt; which I have previously written about in my &lt;a href=&quot;/blog/wsl-workflow#persistent-terminal-sessions-with-tmux&quot;&gt;workflow post&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Homebrew&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://brew.sh&quot;&gt;Homebrew&lt;/a&gt; is an excellent package manager for macOS. It made installing all the tools I needed a breeze. Need node? &lt;code&gt;brew install node&lt;/code&gt;. Need neovim? &lt;code&gt;brew install neovim&lt;/code&gt;. You get the idea. It&apos;s a must- have if you&apos;re using a Mac.&lt;/p&gt;
&lt;h2&gt;Fish Shell&lt;/h2&gt;
&lt;p&gt;Since writing my &lt;a href=&quot;/blog/wsl-workflow&quot;&gt;wsl workflow post&lt;/a&gt;, I&apos;ve switched from zsh to &lt;a href=&quot;https://fishshell.com&quot;&gt;fish&lt;/a&gt;. It&apos;s a more modern shell that comes with autosuggestions, syntax highlighting and a lot more out of the box. It even has web-based configuration which makes it super easy to customize and preview your changes.&lt;/p&gt;
&lt;h2&gt;Starship&lt;/h2&gt;
&lt;p&gt;For my prompt, I still use &lt;a href=&quot;https://starship.rs&quot;&gt;Starship&lt;/a&gt; although my configuration has changed a bit. I&apos;ve switched the &lt;a href=&quot;https://starship.rs/presets/pure-preset.html&quot;&gt;pure preset&lt;/a&gt; which is a lot more minimal and less distracting.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;GitHub CLI&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://cli.github.com&quot;&gt;GitHub CLI&lt;/a&gt; has become an essential part of my workflow. I use it for creating, cloning, and managing repositories. It also makes creating a pull request a breeze. Highly recommend using it, it&apos;ll save you a lot of time. It&apos;s just a &lt;code&gt;brew install gh&lt;/code&gt; away.&lt;/p&gt;
&lt;h2&gt;Other Coding Tools&lt;/h2&gt;
&lt;h3&gt;fnm&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://fnm.vercel.app&quot;&gt;fnm&lt;/a&gt; is a fast and simple Node.js version manager. It&apos;s really easy to use and is much faster than nvm.&lt;/p&gt;
&lt;h3&gt;exa&lt;/h3&gt;
&lt;p&gt;I still use &lt;a href=&quot;https://the.exa.website&quot;&gt;exa&lt;/a&gt; for listing files in the terminal. It&apos;s a modern replacement for &lt;code&gt;ls&lt;/code&gt; with a lot of useful features. With icons, colors, and git integration, it makes listing files much nicer.&lt;/p&gt;
&lt;p&gt;I use the same aliases that I did before.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ~/.config/fish/config.fish
alias ll=&quot;exa -l -g --icons --git&quot;
alias llt=&quot;exa -1 --icons --tree --git-ignore&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;zoxide&lt;/h3&gt;
&lt;p&gt;I also still use &lt;a href=&quot;https://github.com/ajeetdsouza/zoxide&quot;&gt;zoxide&lt;/a&gt; for navigating directories. It&apos;s a smarter &lt;code&gt;cd&lt;/code&gt; command that learns your habits and makes navigating directories a breeze.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;bat&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sharkdp/bat&quot;&gt;bat&lt;/a&gt; is a modern replacement for &lt;code&gt;cat&lt;/code&gt; with syntax highlighting and themes. I use it for a lot of things, but the coolest use of it that I have is to use it to preview files while fuzzy searching using &lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;fzf&lt;/a&gt; and opening that file in neovim.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Here&apos;s the alias.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;alias search=&quot;fzf --preview &apos;bat --color=always --style=numbers --line-range=:500 {}&apos; | xargs nvim&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That&apos;s it! That&apos;s everything I installed on my new Mac. I hope you found this useful. Thanks for reading!&lt;/p&gt;
</content:encoded></item><item><title>Rust: Not Just Zoom Zoom Fast</title><link>https://www.nexxel.dev/blog/rust/</link><guid isPermaLink="true">https://www.nexxel.dev/blog/rust/</guid><description>Explore the versatility of Rust beyond performance and memory safety with its well-designed language, package manager, and ecosystem.</description><pubDate>Sat, 25 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Link from &quot;../../components/Link.vue&quot;;
import Code from &quot;../../components/Code.vue&quot;;
import { createHeading } from &quot;../../components/Heading&quot;;&lt;/p&gt;
&lt;p&gt;export const components = {
a: Link,
code: Code,
h1: createHeading(&quot;h1&quot;),
h2: createHeading(&quot;h2&quot;),
h3: createHeading(&quot;h3&quot;),
};&lt;/p&gt;
&lt;p&gt;When it comes to Rust, the first thing that usually comes to mind is its impressive performance. And while Rust certainly delivers on this front, there&apos;s so much more to the language than just raw speed. From its well-designed syntax and powerful abstractions, to its robust package manager and vibrant ecosystem, Rust is a language that truly has it all. In this post, we&apos;ll take a closer look at some of the key features that make Rust such a versatile and compelling language.&lt;/p&gt;
&lt;p&gt;While the language features discussed in this post may not be exclusive to Rust, it is the way in which they are carefully designed and integrated that sets Rust apart. Rust is the only language where these features converge seamlessly to create a coherent system, which is why it is such a captivating language.&lt;/p&gt;
&lt;h2&gt;Practical Immutability&lt;/h2&gt;
&lt;p&gt;In Rust, variables can be declared as either immutable or mutable using the &lt;code&gt;mut&lt;/code&gt; keyword. Rust embraces immutability as a default by making variables immutable by default. This means that we must explicitly declare variables as mutable if we need to change their value later. This approach makes it easier to reason about the behavior of programs and helps prevent accidental mutations.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let x = 5; // immutable
let mut y = 5; // mutable
y = 6; // ok
x = 6; // error: cannot assign twice to immutable variable `x`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In addition to mutable variables, Rust supports passing mutable references to functions. Functions must declare whether they intend to mutate their arguments or not, which further helps prevent accidental mutations. This allows us to use mutable variables in a controlled, explicit way.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn increment(num: &amp;amp;mut i32) {
*num += 1; // dereference the pointer to mutate the value
}
fn main() {
let mut x = 10; // x is mutable
increment(&amp;amp;mut x); // pass a mutable reference to x
println!(&quot;x: {}&quot;, x); // prints &quot;x: 11&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By embracing immutability as a default and using mutable variables only when necessary, Rust code becomes more robust and predictable.&lt;/p&gt;
&lt;h2&gt;Algrebraic Data Types (ADTs) and Pattern Matching&lt;/h2&gt;
&lt;p&gt;Algebraic Data Types (ADTs) are a fundamental concept in functional programming that allow for the creation of complex data types by combining simpler types. ADTs can be of two types: Sum types and Product types. Sum types combine multiple types into a single type that can hold one of the constituent types at any given time. Rust provides a powerful implementation of Sum types in the form of enums or enumerated types. Structs, on the other hand, are used to represent Product types. You&apos;ve probably already used Product types in other languages (interfaces in TypeScript, classes in Java, etc.).&lt;/p&gt;
&lt;p&gt;For example, consider a program that represents the types of shapes. We can use an enum to represent the different types of shapes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;enum Shape {
Circle(f64),
Rectangle(f64, f64),
Triangle(f64, f64, f64),
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we have defined an enum &lt;code&gt;Shape&lt;/code&gt; that has three variants: &lt;code&gt;Circle&lt;/code&gt; that takes a single &lt;code&gt;f64&lt;/code&gt; argument representing the radius, &lt;code&gt;Rectangle&lt;/code&gt; that takes two &lt;code&gt;f64&lt;/code&gt; arguments representing the length and width, and &lt;code&gt;Triangle&lt;/code&gt; that takes three f64 arguments representing the lengths of its three sides. This allows us to represent any possible shape in a single data type.&lt;/p&gt;
&lt;p&gt;Now we can use pattern matching to easily and safely parse the data of a shape. If you don&apos;t know what pattern matching is, think of it as a &lt;code&gt;switch&lt;/code&gt; statement on steroids. It allows us to match a value against a pattern and execute code based on the pattern that matches. I have a &lt;a href=&quot;/blog/pattern-matching&quot;&gt;whole blog post on pattern matching btw&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn area(shape: Shape) -&amp;gt; f64 {
match shape {
// pi * radius^2
Shape::Circle(radius) =&amp;gt; std::f64::consts::PI * radius * radius,
// length * width
Shape::Rectangle(length, width) =&amp;gt; length * width,
// Heron&apos;s formula: sqrt(s * (s - a) * (s - b) * (s - c)) where s = (a + b + c) / 2
Shape::Triangle(side1, side2, side3) =&amp;gt; {
let s = (side1 + side2 + side3) / 2.0;
(s * (s - side1) * (s - side2) * (s - side3)).sqrt()
}
}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rust&apos;s compiler also ensures that our pattern matching is exhaustive, meaning that we must handle all possible cases. This prevents us from accidentally forgetting to handle a case and causing a runtime error.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;ADTs along with pattern matching make it trivial to create and handle complex data types in a safe and concise way.&lt;/p&gt;
&lt;h2&gt;Built-In Abstractions&lt;/h2&gt;
&lt;p&gt;Rust provides powerful built-in abstractions that help in writing correct and safe code easily. Two of the most important abstractions in Rust are &lt;code&gt;Option&lt;/code&gt; and &lt;code&gt;Result&lt;/code&gt;. These types are essential for working with Rust&apos;s null-safety and error-handling systems, which help prevent bugs and improve the reliability of Rust programs. In this section, we&apos;ll explore &lt;code&gt;Option&lt;/code&gt; and &lt;code&gt;Result&lt;/code&gt; in detail, and see how they can be used to write more reliable and error-free Rust code.&lt;/p&gt;
&lt;h3&gt;No Null, No Problem (Option)&lt;/h3&gt;
&lt;p&gt;Rust replaces the concept of null with the &lt;code&gt;Option&lt;/code&gt; type, providing a safer alternative that eliminates the risks associated with null values. &lt;code&gt;Option&lt;/code&gt; is an enum that can be either &lt;code&gt;Some&lt;/code&gt; with a value or &lt;code&gt;None&lt;/code&gt; to represent absence of a value. This type-safe approach allows us to handle absence of a value without resorting to null. Here&apos;s how the &lt;code&gt;Option&lt;/code&gt; type is defined in Rust:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;enum Option&amp;lt;T&amp;gt; {
Some(T),
None,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By using &lt;code&gt;Option&lt;/code&gt;, we can ensure that our code is free from null-related bugs and errors, making it easier to reason about program behavior. You may be familiar with this pattern from other languages like Haskell&apos;s &lt;code&gt;Maybe&lt;/code&gt; monad or OCaml&apos;s &lt;code&gt;option&lt;/code&gt; type.&lt;/p&gt;
&lt;p&gt;Let&apos;s look at &lt;code&gt;Option&lt;/code&gt; in practice. Consider a function that takes a vector of integers and returns the largest integer in the vector. If the vector is empty, we want to return &lt;code&gt;None&lt;/code&gt;. Otherwise, we want to return &lt;code&gt;Some&lt;/code&gt; with the largest integer. Here&apos;s how we can implement this function in Rust:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn largest(numbers: Vec&amp;lt;i32&amp;gt;) -&amp;gt; Option&amp;lt;i32&amp;gt; {
if numbers.is_empty() {
return None;
}
let mut largest = numbers[0];
for num in numbers {
if num &amp;gt; largest {
largest = num;
}
}
Some(largest)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can use this function and use pattern matching to handle the both cases:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn main() {
let numbers = vec![1, 2, 3];
match largest(numbers) {
Some(num) =&amp;gt; println!(&quot;Largest number: {}&quot;, num),
None =&amp;gt; println!(&quot;No largest number&quot;),
}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this works!&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;But we can do better. Rust provides an extensive standard library that includes a number of useful functions. Here we can create an iterator from our &lt;code&gt;Option&lt;/code&gt; and use the &lt;code&gt;max&lt;/code&gt; function to get the largest number:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn largest(numbers: Vec&amp;lt;i32&amp;gt;) -&amp;gt; Option&amp;lt;i32&amp;gt; {
numbers.into_iter().max()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This also automatically handles the case where the vector is empty, returning &lt;code&gt;None&lt;/code&gt; for us. Rust&apos;s standard library is full of useful functions like this.&lt;/p&gt;
&lt;p&gt;Want to return the double of the largest of the even numbers but only if it&apos;s less than 100? No problem!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn largest_even_less_than_100(numbers: Vec&amp;lt;i32&amp;gt;) -&amp;gt; Option&amp;lt;i32&amp;gt; {
numbers
.into_iter() // create an iterator from the vector
.filter(|num| num % 2 == 0) // filter out only even numbers
.max() // get the largest number - returns an Option&amp;lt;i32&amp;gt;
.map(|num| num * 2) // double the Some value inside the Option, leaves None unchanged
.filter(|num| num &amp;lt; &amp;amp;100) // only return Some if the value is less than 100
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I think you get the point.&lt;/p&gt;
&lt;h3&gt;When Things Don&apos;t Go As Planned (Result)&lt;/h3&gt;
&lt;p&gt;Rust&apos;s &lt;code&gt;Result&lt;/code&gt; type is another built-in abstraction that is often used to handle errors in Rust programs. It represents the success or failure of an operation. &lt;code&gt;Result&lt;/code&gt; is an enum with two possible variants - &lt;code&gt;Ok&lt;/code&gt; and &lt;code&gt;Err&lt;/code&gt;. &lt;code&gt;Ok&lt;/code&gt; represents the successful result of an operation, while &lt;code&gt;Err&lt;/code&gt; represents an error that occurred during the operation. Here&apos;s how the &lt;code&gt;Result&lt;/code&gt; type is defined in Rust:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;enum Result&amp;lt;T, E&amp;gt; {
Ok(T),
Err(E),
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might be familiar with this pattern from other languages like Haskell&apos;s &lt;code&gt;Either&lt;/code&gt; monad or OCaml&apos;s &lt;code&gt;result&lt;/code&gt; type.&lt;/p&gt;
&lt;p&gt;Let&apos;s look at an example of how &lt;code&gt;Result&lt;/code&gt; can be used to handle errors. Let&apos;s say we have a function that takes two integers as arguments and returns the result of dividing the first integer by the second. However, division by zero is not allowed and will result in an error. We can use the &lt;code&gt;Result&lt;/code&gt; type to handle the possible error case:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn divide(x: i32, y: i32) -&amp;gt; Result&amp;lt;i32, &amp;amp;&apos;static str&amp;gt; {
if y == 0 {
return Err(&quot;Cannot divide by zero&quot;);
}
Ok(x / y)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can use this function and handle the success and error cases:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn main() {
match divide(10, 2) {
Ok(result) =&amp;gt; println!(&quot;Result: {}&quot;, result),
Err(error) =&amp;gt; println!(&quot;Error: {}&quot;, error),
}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty simple, right? Let&apos;s look at some functions Rust provides to make working with &lt;code&gt;Result&lt;/code&gt; a breeze.&lt;/p&gt;
&lt;p&gt;Say we wanted to add 10 to the result of a chained division operation. We could use nested &lt;code&gt;match&lt;/code&gt; statements but that&apos;s a bit ugly and verbose. Rust has us covered with the &lt;code&gt;and_then&lt;/code&gt; and &lt;code&gt;map&lt;/code&gt; functions:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn main() {
let result = divide(10, 2)
.and_then(|x| divide(x, 2))
.map(|x| x + 10);
match result {
Ok(result) =&amp;gt; println!(&quot;Result: {}&quot;, result),
Err(error) =&amp;gt; println!(&quot;Error: {}&quot;, error),
}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a lot more concise than using nested &lt;code&gt;match&lt;/code&gt; statements. Rust&apos;s standard library provides a lot more functions for working with &lt;code&gt;Result&lt;/code&gt; and &lt;code&gt;Option&lt;/code&gt;, so be sure to check them out.&lt;/p&gt;
&lt;h2&gt;Vibrant Community and Ecosystem&lt;/h2&gt;
&lt;p&gt;Rust is more than just a language; it has a thriving ecosystem and community. This community is supported by a robust ecosystem of libraries, tools, and resources that make it easy to build, test, and deploy Rust applications.&lt;/p&gt;
&lt;p&gt;Here are some key aspects of Rust&apos;s ecosystem and community:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rustup&lt;/strong&gt; - Rustup is the official tool for installing and managing Rust. It makes it easy to install and update Rust and its associated tools. It also makes it easy to install and manage multiple versions of Rust on the same system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cargo&lt;/strong&gt; - Cargo is Rust&apos;s package manager. It&apos;s used to build, test, and run Rust applications. It also makes it easy to manage dependencies and avoid dependency hell. It also allows publishing libraries and binaries to &lt;a href=&quot;https://crates.io&quot;&gt;crates.io&lt;/a&gt;, Rust&apos;s official package registry. It can also do benchmarks, and even manage multiple projects in the same repository using workspaces.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Libraries&lt;/strong&gt; - Rust has a large and growing collection of open-source libraries and frameworks that can be easily integrated into your projects. This includes everything from low-level system libraries to high-level web frameworks and game engines.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tooling&lt;/strong&gt; - Rust has a strong focus on developer tools. Tools like Rustfmt, Clippy, and Rust Analyzer that help with code formatting, linting, and analysis.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Community&lt;/strong&gt; - The Rust community is known for being welcoming and supportive, with many resources available to help new users get started with the language. This includes online forums, chat rooms, and meetups, as well as a growing collection of Rust books and tutorials. I particurlarly love &lt;a href=&quot;https://discord.gg/rust-lang-community&quot;&gt;Rust&apos;s community discord server&lt;/a&gt;. It&apos;s a great place to get help with Rust and meet other Rustaceans.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;These are some of my favourite features of Rust. If I go on, this article will be too long, so I&apos;m linking some resources for Rust coolness below. I highly recommend checking them out.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Some Other Cool Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stephencoakley.com/2019/04/24/how-rust-solved-dependency-hell&quot;&gt;How Cargo solved dependency hell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://youtu.be/MWRPYBoCEaY&quot;&gt;Rust Macros&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://youtu.be/CJtvnepMVAU&quot;&gt;Rust&apos;s insanely helpful compiler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.rust-lang.org/2015/05/11/traits.html&quot;&gt;Rust traits&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Implementing the Pipe Operator in TypeScript</title><link>https://www.nexxel.dev/blog/pipe/</link><guid isPermaLink="true">https://www.nexxel.dev/blog/pipe/</guid><description>The pipe operator is one of my favourite features in functional languages like Elixir and OCaml. Let&apos;s implement it in TypeScript!</description><pubDate>Sat, 21 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Link from &quot;../../components/Link.vue&quot;;
import Code from &quot;../../components/Code.vue&quot;;
import { createHeading } from &quot;../../components/Heading&quot;;&lt;/p&gt;
&lt;p&gt;export const components = {
a: Link,
code: Code,
h1: createHeading(&quot;h1&quot;),
h2: createHeading(&quot;h2&quot;),
h3: createHeading(&quot;h3&quot;),
};&lt;/p&gt;
&lt;h2&gt;What is the pipe operator?&lt;/h2&gt;
&lt;p&gt;The pipe operator is used to chain function calls together in a more readable and concise way. The operator takes the output of one function as the input for the next function in the chain. Here&apos;s an example of pipes in &lt;a href=&quot;https://elixir-lang.org/&quot;&gt;Elixir&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;hello&quot;
|&amp;gt; String.upcase() # turn string into uppercase
|&amp;gt; String.reverse() # reverse the string returned from `String.upcase()`
|&amp;gt; IO.puts() # print the output from `String.reverse()`
# &quot;OLLEH&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, the pipe operator &lt;code&gt;|&amp;gt;&lt;/code&gt; takes the output of the previous function and passes it as the input for the next function. Here&apos;s a more complex example. It&apos;s my solution to &lt;a href=&quot;https://adventofcode.com/2022/&quot;&gt;Advent of Code 2022&lt;/a&gt; &lt;a href=&quot;https://adventofcode.com/2022/day/1&quot;&gt;day 1 pt.2&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;File.read!(&quot;./input.txt&quot;)
|&amp;gt; String.split(&quot;\n\n&quot;)
|&amp;gt; Enum.map(fn elf -&amp;gt;
elf
|&amp;gt; String.split(&quot;\n&quot;)
|&amp;gt; Enum.map(fn e -&amp;gt; e |&amp;gt; String.to_integer() end)
|&amp;gt; Enum.sum()
end)
|&amp;gt; Enum.sort(:desc)
|&amp;gt; Enum.slice(0..2)
|&amp;gt; Enum.sum()
|&amp;gt; IO.inspect()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see how the pipe operator really helps in improving the readability of the code. The code reads like a sentence. Pipes also eliminate the need to create temporary variables to store the output of each function call or using nested function calls. As a result developers also don&apos;t have to worry about naming variables which is my least liked part of programming.&lt;/p&gt;
&lt;h2&gt;Implementing the pipe operator in TypeScript&lt;/h2&gt;
&lt;p&gt;After watching &lt;a href=&quot;https://youtu.be/h1FvtIJ6ecE&quot;&gt;Theo&apos;s video on the proposal for adding pipes in JavaScript&lt;/a&gt;, I was inspired to implement the pipe operator as a function that composes functions together. Here is what I set out to achieve.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const len = (s: string): number =&amp;gt; s.length;
const double = (n: number): number =&amp;gt; n * 2;
const square = (n: number): number =&amp;gt; n ** 2;
console.log(pipe(&quot;hi&quot;, len, double, square)); // 16
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Initial implementation&lt;/h3&gt;
&lt;p&gt;This was my first iteration of the &lt;code&gt;pipe&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const pipe = (value: any, ...fns: Function[]) =&amp;gt;
fns.reduce((acc, fn) =&amp;gt; fn(acc), value);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&apos;s what this code is doing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The function takes two arguments: &lt;code&gt;value&lt;/code&gt; of any type, and &lt;code&gt;fns&lt;/code&gt; which is an array of functions. The spread operator &lt;code&gt;...&lt;/code&gt; allows for any number of functions to be passed in.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce&quot;&gt;&lt;code&gt;reduce&lt;/code&gt;&lt;/a&gt; function is used to iterate over the array of functions and pass the output of the previous function as the input for the next function.&lt;/li&gt;
&lt;li&gt;The callback function passed to &lt;code&gt;reduce&lt;/code&gt; takes two arguments: &lt;code&gt;acc&lt;/code&gt; which is the accumulator, and &lt;code&gt;fn&lt;/code&gt; which is the current function in the array. The first function in the array is applied to the initial value, which is the &lt;code&gt;value&lt;/code&gt; argument passed to the function. Each subsequent function is applied to the output of the previous function, chaining them together.&lt;/li&gt;
&lt;li&gt;It then returns the output of the last function in the array.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And this works!&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;Problems with the initial implementation&lt;/h3&gt;
&lt;p&gt;There are a few problems with this implementation. The first problem that I immediately noticed is that the type of the returned value from the function is &lt;code&gt;any&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Obviously this is not good. Ideally this type should be inferred by the TypeScript compiler. I got some help from Reddit and a user there suggested this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Fn = (...args: any[]) =&amp;gt; any;
type LastReturnType&amp;lt;L extends Fn[]&amp;gt; = L extends [...any, infer Last extends Fn]
? ReturnType&amp;lt;Last&amp;gt;
: never;
const pipe = &amp;lt;Funcs extends Fn[]&amp;gt;(value: any, ...fns: Funcs) =&amp;gt;
fns.reduce((acc, fn) =&amp;gt; fn(acc), value) as LastReturnType&amp;lt;Funcs&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is definitely some crazy TypeScript. Let&apos;s break it down.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Fn&lt;/code&gt; is a type alias for a function that takes any number of arguments of &lt;code&gt;any&lt;/code&gt; type and returns &lt;code&gt;any&lt;/code&gt; type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LastReturnType&lt;/code&gt; is a generic type that takes an array of functions and returns the return type of the last function in the array. The &lt;code&gt;infer&lt;/code&gt; keyword is used to infer the type of the last function in the array.&lt;/li&gt;
&lt;li&gt;It uses &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-0.html#variadic-tuple-types&quot;&gt;variadic tuple types&lt;/a&gt; to know what the last function in the tuple is and then uses the &lt;code&gt;ReturnType&lt;/code&gt; type utility to get the return type of the last function.&lt;/li&gt;
&lt;li&gt;Then the &lt;code&gt;pipe&lt;/code&gt; function is defined as a generic function that takes an initial value of any type and an arbitrary number of functions of the &lt;code&gt;Fn&lt;/code&gt; type. It then casts the return value of the function to the return type of the last function in the array.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So now the type of the returned value is inferred correctly.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;But there&apos;s still a problem. Let me demonstrate it with an example.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// does not show an error
const result = pipe(&quot;hi&quot;, double, len, square);
// Argument of type &apos;number&apos; is not assignable to parameter of type &apos;string&apos;.
const result2 = square(len(double(&quot;hi&quot;)));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we&apos;re trying to double the string &quot;hi&quot;, which is impossible as we&apos;re passing a string to a function that expects a number. You can see we get the appropriate error when we try to do this by nesting the function calls. But our &lt;code&gt;pipe&lt;/code&gt; function does not show any errors.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;This is a perfect use case for &lt;a href=&quot;https://en.m.wikipedia.org/wiki/Kind_(type_theory)&quot;&gt;Higher Kinded Types&lt;/a&gt;. Unfortunately, TypeScript does not support Higher Kinded Types yet. There isn&apos;t a way to say &quot;for all these functions, the input type is &lt;a href=&quot;https://en.m.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)&quot;&gt;contravariant&lt;/a&gt; to the output type of the previous function&quot;.&lt;/p&gt;
&lt;h3&gt;So what&apos;s the solution?&lt;/h3&gt;
&lt;p&gt;Turns out, the easiest and most straightforward solution is to set an upper bound on the number of functions that can be passed to the &lt;code&gt;pipe&lt;/code&gt; function and use &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads&quot;&gt;function overloading&lt;/a&gt; to define the type of the returned value.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function pipe&amp;lt;A&amp;gt;(value: A): A;
function pipe&amp;lt;A, B&amp;gt;(value: A, fn1: (input: A) =&amp;gt; B): B;
function pipe&amp;lt;A, B, C&amp;gt;(value: A, fn1: (input: A) =&amp;gt; B, fn2: (input: B) =&amp;gt; C): C;
function pipe&amp;lt;A, B, C, D&amp;gt;(
value: A,
fn1: (input: A) =&amp;gt; B,
fn2: (input: B) =&amp;gt; C,
fn3: (input: C) =&amp;gt; D,
): D;
function pipe&amp;lt;A, B, C, D, E&amp;gt;(
value: A,
fn1: (input: A) =&amp;gt; B,
fn2: (input: B) =&amp;gt; C,
fn3: (input: C) =&amp;gt; D,
fn4: (input: D) =&amp;gt; E,
): E;
// ... and so on
function pipe(value: any, ...fns: Function[]): unknown {
return fns.reduce((acc, fn) =&amp;gt; fn(acc), value);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This might seem very manual but it&apos;s definitely the best way to do this. It works very well and also gives fairly easy to understand type errors for the user. Let&apos;s see how it works.&lt;/p&gt;
&lt;p&gt;The first five function declarations are overloads of the &lt;code&gt;pipe&lt;/code&gt; function, each one of them has a different set of parameters, each overload corresponds to a different number of functions that can be passed to the &lt;code&gt;pipe&lt;/code&gt; function.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first overload takes a single argument of generic type &lt;code&gt;A&lt;/code&gt; and returns the same value without applying any function to it.&lt;/li&gt;
&lt;li&gt;The second overload takes two arguments, value of type &lt;code&gt;A&lt;/code&gt;, and &lt;code&gt;fn1&lt;/code&gt; a function that takes an argument of type &lt;code&gt;A&lt;/code&gt; and returns a value of type &lt;code&gt;B&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The third overload takes three arguments, value of type &lt;code&gt;A&lt;/code&gt;, &lt;code&gt;fn1&lt;/code&gt; a function that takes an argument of type &lt;code&gt;A&lt;/code&gt; and returns a value of type &lt;code&gt;B&lt;/code&gt;, and &lt;code&gt;fn2&lt;/code&gt; a function that takes an argument of type &lt;code&gt;B&lt;/code&gt; and returns a value of type &lt;code&gt;C&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;There can be any number of overloads, but I&apos;ve only defined five for demonstration purposes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each overload corresponds to a different number of functions, and each function&apos;s input type is the output of the previous function, this way the &lt;code&gt;pipe&lt;/code&gt; function will not only return the output type of the last function passed but also type check the input and output types of each function in the pipeline.&lt;/p&gt;
&lt;p&gt;The last function declaration is the actual implementation of the &lt;code&gt;pipe&lt;/code&gt; function. It takes an initial value of any type and an arbitrary number of functions and applies them to the initial value in the order they are passed. The logic is the same as before.&lt;/p&gt;
&lt;p&gt;The advantage of this implementation is that it allows the &lt;code&gt;pipe&lt;/code&gt; function to be more type-safe as it ensures that the input and output types of each function in the pipeline are consistent and match the type of the initial value, and it also ensures that the functions passed to the &lt;code&gt;pipe&lt;/code&gt; function have the correct signature.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;Overloading without using the function keyword&lt;/h3&gt;
&lt;p&gt;I love my arrow functions and almost never use the &lt;code&gt;fuction&lt;/code&gt; keyword. Unfortunately, we can&apos;t use arrow functions for overloading. We can only use the &lt;code&gt;function&lt;/code&gt; keyword for overloading. But what we can do is implement the overloads in an interface and then implement the actual function as a function of that interface.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface Pipe {
&amp;lt;A&amp;gt;(value: A): A;
&amp;lt;A, B&amp;gt;(value: A, fn1: (input: A) =&amp;gt; B): B;
&amp;lt;A, B, C&amp;gt;(value: A, fn1: (input: A) =&amp;gt; B, fn2: (input: B) =&amp;gt; C): C;
&amp;lt;A, B, C, D&amp;gt;(
value: A,
fn1: (input: A) =&amp;gt; B,
fn2: (input: B) =&amp;gt; C,
fn3: (input: C) =&amp;gt; D,
): D;
&amp;lt;A, B, C, D, E&amp;gt;(
value: A,
fn1: (input: A) =&amp;gt; B,
fn2: (input: B) =&amp;gt; C,
fn3: (input: C) =&amp;gt; D,
fn4: (input: D) =&amp;gt; E,
): E;
// ... and so on
}
const pipe: Pipe = (value: any, ...fns: Function[]): unknown =&amp;gt; {
return fns.reduce((acc, fn) =&amp;gt; fn(acc), value);
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is same as the previous implementation, but we&apos;re using an interface to implement the overloads instead of using the &lt;code&gt;function&lt;/code&gt; keyword. This way we can use arrow functions for the actual implementation. Pretty neat, right? Everything still works!&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope you enjoyed this article. I&apos;ve learned a lot while writing it, and I hope you did too. Thanks for reading!&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/intro.html&quot;&gt;TypeScript Handbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/play?#code/PTAECcFMBcFdwHamgTwA6VAewGagDYCGAztKDrAgMbQCWWStSh44hKAUKhqAGJOF8AJRjwEANUGxIAHl6hIAD2iQEAE2J9KNeggDaAXQB8AXj4LlqjaD0A6e0xyRwoAKoAaUI+egAMgdAAfj8LFXVNAAp7WxYAc2IALlBCBBQASlATIy8EJxchINACpIRIADcfEvLnDi50TABBTL4BYVFESXxpGT0IjKzQAEYAJgBmY1qqBlJQNFoeMzkETSUw615tOgZDIwiyqUgklJRPaJxlpN5ltMvWkTgOg6XibIGOUA-yZdsoNVgqSARCKEKhUTznfrZc7A0FpTz7LqQNIAbg+k2mZHwqmaEUSoFI4CYsRuoAQsAAtgAjHwDYi2LEIWLQAAWyI4U2WZDUWFglKxOIQJQp1PAJLJVJp2SQACpQMNUeyMfiAI6wFiYMwRQWk4XOMW6lwDGWy+WgdGciCQYiwfBkMxzDARABEzNoTvcDM83N5WM8xFV6pRoBAluttq8mmOHBDnwAeoFFcssFj6VhYhEoGHoBkQ4MAGwcIA&quot;&gt;&lt;code&gt;LastReturnType&lt;/code&gt; implementation&lt;/a&gt; by u/i_fucking_hate_money&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/remeda/remeda/blob/master/src/pipe.ts&quot;&gt;Remeda&apos;s &lt;code&gt;pipe&lt;/code&gt; implementation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/bluesky-llc/open-source/blob/main/packages/utils/src/pipe.ts&quot;&gt;u/GoodnessManifest&apos;s &lt;code&gt;pipe&lt;/code&gt; implementation&lt;/a&gt; with overloads in an interface&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tc39/proposal-pipeline-operator&quot;&gt;Proposal&lt;/a&gt; for adding the pipe operator to JavaScript&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Expressive Code with Pattern Matching</title><link>https://www.nexxel.dev/blog/pattern-matching/</link><guid isPermaLink="true">https://www.nexxel.dev/blog/pattern-matching/</guid><description>Elevate your code by writing declarative, and easy-to-read code with pattern matching.</description><pubDate>Thu, 29 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Link from &quot;../../components/Link.vue&quot;;
import Code from &quot;../../components/Code.vue&quot;;
import { createHeading } from &quot;../../components/Heading&quot;;&lt;/p&gt;
&lt;p&gt;export const components = {
a: Link,
code: Code,
h1: createHeading(&quot;h1&quot;),
h2: createHeading(&quot;h2&quot;),
h3: createHeading(&quot;h3&quot;),
};&lt;/p&gt;
&lt;p&gt;Have you ever found yourself writing long, cumbersome if-else chains in your code, just to handle a few different cases? If so, you&apos;ll want to learn about pattern matching. In this post, we&apos;ll explore the basics of pattern matching and how it can help you write cleaner, more concise code. We&apos;ll also look at some examples of how pattern matching can be used to solve common problems in programming.&lt;/p&gt;
&lt;h2&gt;What is Pattern Matching?&lt;/h2&gt;
&lt;p&gt;Pattern matching is a mechanism for checking a value against a pattern and, based on the match, performing some kind of action. It is a fundamental feature of many programming languages, such as Haskell, Rust and ML languages including OCaml.&lt;/p&gt;
&lt;p&gt;The basic idea behind pattern matching is simple: you define a pattern and provide some code to be executed if the pattern matches. All of the code examples in this post are in OCaml syntax because it is very readable and easy to understand. Consider the following example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(* basic.ml *)
let greet name =
match name with
| &quot;nexxel&quot; -&amp;gt; print_string &quot;Hi, nexxel!&quot;
| &quot;Ludwig&quot; -&amp;gt; print_string &quot;Crazy how you look exactly like Mogul Mail&quot;
| _ -&amp;gt; print_string &quot;Who are you?&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we have defined a function called &lt;code&gt;greet&lt;/code&gt; that takes a single argument&lt;code&gt;name&lt;/code&gt;. The &lt;code&gt;match&lt;/code&gt; keyword is used to define a pattern match, and the &lt;code&gt;with&lt;/code&gt; keyword is used to specify the different patterns to be matched.&lt;/p&gt;
&lt;p&gt;The first pattern is &lt;code&gt;&quot;nexxel&quot; -&amp;gt; print_string &quot;Hi, nexxel!&quot;&lt;/code&gt;, which means that if &lt;code&gt;name&lt;/code&gt; is equal to &lt;code&gt;&quot;nexxel&quot;&lt;/code&gt;, it will execute the print statement. Similarly, if &lt;code&gt;name&lt;/code&gt; is equal to &lt;code&gt;&quot;Ludwig&quot;&lt;/code&gt; it will execute the respective print statement. The last pattern is &lt;code&gt;_ -&amp;gt; print_string &quot;Who are you?&quot;&lt;/code&gt;, which means that if &lt;code&gt;name&lt;/code&gt; is anything other than &quot;nexxel&quot; or &quot;Ludwig&quot;, it will print &quot;Who are you?&quot;.&lt;/p&gt;
&lt;p&gt;This is a very basic example of pattern matching, but it illustrates the core concept: you define a pattern and provide some code to be executed if the pattern matches. You might think how is this better than using an if-else statement? We&apos;ll see how pattern matching helps in simplifying complex conditional logic with less mental effort.&lt;/p&gt;
&lt;h2&gt;Why Use Pattern Matching?&lt;/h2&gt;
&lt;p&gt;Pattern matching allows you to express complex conditionals in a concise and declarative way. Let&apos;s look at another example which is a function to calculate the &lt;a href=&quot;https://en.wikipedia.org/wiki/Factorial&quot;&gt;factorial&lt;/a&gt; of a number.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(* factorial.ml *)
let rec factorial n =
match n with
| 0 -&amp;gt; 1
| n -&amp;gt; n * factorial (n - 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code uses a recursive function (&lt;code&gt;rec&lt;/code&gt; is used to define recursive functions) and pattern matching to calculate the factorial of a given number. The pattern &lt;code&gt;0&lt;/code&gt; is matched if &lt;code&gt;n&lt;/code&gt; is equal to &lt;code&gt;0&lt;/code&gt;, in which case the function returns &lt;code&gt;1&lt;/code&gt;. Otherwise, the pattern &lt;code&gt;n&lt;/code&gt; is matched, and the function calls itself with &lt;code&gt;n - 1&lt;/code&gt; as the argument.&lt;/p&gt;
&lt;p&gt;This code is much simpler and easier to understand than an equivalent implementation using an imperative loop. In addition, it is more declarative, as it specifies what should be done rather than how it should be done. Here&apos;s an imperative implementation of the same function in Python:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# factorial.py
def factorial(n):
def loop(i, acc):
if i &amp;gt; n:
return acc
else:
return loop(i + 1, acc * i)
return loop(1, 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The declarative way of doing things is much more concise and easier to reason. Let&apos;s explore some more examples to see how pattern matching is used in practice.&lt;/p&gt;
&lt;h2&gt;Pattern Matching in Practice&lt;/h2&gt;
&lt;h3&gt;Conditionals&lt;/h3&gt;
&lt;p&gt;We already saw the factorial example, but let&apos;s take another example to calculate the nth term of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Fibonacci_number&quot;&gt;Fibonacci sequence&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(* fibonacci.ml *)
let rec fib n =
match n with
| 0 -&amp;gt; 0
| 1 -&amp;gt; 1
| n -&amp;gt; fib (n - 1) + fib (n - 2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the &lt;code&gt;fib&lt;/code&gt; function uses pattern matching to define three cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;n&lt;/code&gt; is equal to &lt;code&gt;0&lt;/code&gt;, it returns &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;n&lt;/code&gt; is equal to &lt;code&gt;1&lt;/code&gt;, it returns &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;n&lt;/code&gt; is neither &lt;code&gt;0&lt;/code&gt; nor &lt;code&gt;1&lt;/code&gt;, the function calls itself with &lt;code&gt;n - 1&lt;/code&gt; and &lt;code&gt;n - 2&lt;/code&gt; as arguments and returns the sum of the two results.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&apos;s an imperative implementation of the same function in TypeScript:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// fibonacci.ts
const fib = (n: number): number =&amp;gt; {
if (n === 0) {
return 0;
} else if (n === 1) {
return 1;
} else {
let a = 0;
let b = 1;
for (let i = 2; i &amp;lt;= n; i++) {
[a, b] = [b, a + b];
}
return b;
}
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you look at the code, you&apos;ll see that it is much more verbose than the declarative version. It also uses mutable variables, which can be error-prone. Moreover, it is not very easy to understand what the code is doing. Although this can be improved and be written in a declarative way using recursion.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// fibonacci.ts
const fib = (n: number): number =&amp;gt; {
if (n === 0) {
return 0;
} else if (n === 1) {
return 1;
} else {
return fib(n - 1) + fib(n - 2);
}
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This version is much more readable and concise, but it is still not as concise and satisfying to read and write as the pattern matching version.&lt;/p&gt;
&lt;h3&gt;Usage with Algebraic Data Types&lt;/h3&gt;
&lt;p&gt;Pattern matching is also used with &lt;a href=&quot;https://en.wikipedia.org/wiki/Algebraic_data_type&quot;&gt;algebraic data types&lt;/a&gt;, which are composite data types that are built up from simpler data types using a set of constructors.. Consider the following example to represent a &lt;a href=&quot;https://en.wikipedia.org/wiki/Binary_tree&quot;&gt;binary tree&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(* binary_tree.ml *)
type tree =
| Leaf
| Node of int * tree * tree
let binary_tree = Node(1, Node(2, Leaf, Leaf), Node(3, Leaf, Leaf))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;tree&lt;/code&gt; type is an ADT, where the value of type &lt;code&gt;tree&lt;/code&gt; can either be a &lt;code&gt;Leaf&lt;/code&gt; or &lt;code&gt;Node&lt;/code&gt;. This ADT has two constructors: &lt;code&gt;Leaf&lt;/code&gt; and &lt;code&gt;Node&lt;/code&gt;. The &lt;code&gt;Leaf&lt;/code&gt; constructor takes no arguments and represents a leaf node, i.e. a node with no subtrees. The &lt;code&gt;Node&lt;/code&gt; constructor takes three arguments: an integer value, and two subtrees.&lt;/p&gt;
&lt;p&gt;Now that we have defined the &lt;code&gt;tree&lt;/code&gt; ADT, we can use it to create a binary tree. The &lt;code&gt;binary_tree&lt;/code&gt; variable is a &lt;code&gt;tree&lt;/code&gt; value that represents the following binary tree:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 1
/ \
2 3
/ \ / \
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can use pattern matching to deconstruct the &lt;code&gt;tree&lt;/code&gt; value and perform different actions based on its structure. For example, we can write a function that sums the values of all leaf nodes in a tree:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(* binary_tree.ml *)
let rec sum_tree tree =
match tree with
| Leaf -&amp;gt; 0
| Node(value, left, right) -&amp;gt; value + sum_tree left + sum_tree right
(* let () = print_int (sum_tree binary_tree) *)
(* 6 *)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;sum_tree&lt;/code&gt; function takes a &lt;code&gt;tree&lt;/code&gt; value as an argument and uses pattern matching to deconstruct it. If the tree is a &lt;code&gt;Leaf&lt;/code&gt;, it returns &lt;code&gt;0&lt;/code&gt;. Otherwise, it returns the value of the node plus the sum of the values of the left and right subtrees.&lt;/p&gt;
&lt;p&gt;You can see the benefits of using pattern matching here. The code is very concise and much easier to understand because it reads like what you would say in plain English.&lt;/p&gt;
&lt;h3&gt;Navigating Complex Data Structures&lt;/h3&gt;
&lt;p&gt;Pattern matching allows us to navigate complex data structures in a very flexbile and concise way without a lot of mental overhead. Consider the following &lt;a href=&quot;https://en.wikipedia.org/wiki/Tagged_union&quot;&gt;variant type&lt;/a&gt; to represent a &lt;a href=&quot;https://en.wikipedia.org/wiki/Polynomial&quot;&gt;polynomial&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(* polynomial.ml *)
type &apos;a polynomial =
| Zero
| Const of &apos;a
| Var
| Sum of &apos;a polynomial * &apos;a polynomial
| Prod of &apos;a polynomial * &apos;a polynomial
| Power of &apos;a polynomial * int
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;polynomial&lt;/code&gt; type is a generic type that takes in a type parameter &lt;code&gt;&apos;a&lt;/code&gt;. It is a placeholder for a type that will be specified later when the type is used. &lt;code&gt;polynomial&lt;/code&gt; and has six variants. The &lt;code&gt;Zero&lt;/code&gt; variant represents the polynomial &lt;code&gt;0&lt;/code&gt;, the &lt;code&gt;Const&lt;/code&gt; variant represents a constant polynomia, the &lt;code&gt;Var&lt;/code&gt; variant represents the polynomial &lt;code&gt;x&lt;/code&gt;. The &lt;code&gt;Sum&lt;/code&gt; variant represents the sum of two polynomials. The &lt;code&gt;Prod&lt;/code&gt; variant represents the product of two polynomials. The &lt;code&gt;Power&lt;/code&gt; variant represents the polynomial raised to a power.&lt;/p&gt;
&lt;p&gt;We can now use pattern matching to define a function that evaluates a polynomial at a given value of &lt;code&gt;x&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(* polynomial.ml *)
(* `function` is just syntatic sugar for `match x with` *)
let rec eval x = function
| Zero -&amp;gt; 0
| Const c -&amp;gt; c
| Var -&amp;gt; x
| Sum (p1, p2) -&amp;gt; eval x p1 + eval x p2
| Prod (p1, p2) -&amp;gt; eval x p1 * eval x p2
| Power (p, n) -&amp;gt; int_of_float (float_of_int (eval x p) ** float_of_int n)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;eval&lt;/code&gt; is a recursive function which uses pattern matching to define the cases for the different variants of the &lt;code&gt;polynomial&lt;/code&gt; type.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the polynomial is &lt;code&gt;Zero&lt;/code&gt;, the function returns &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If the polynomial is &lt;code&gt;Const&lt;/code&gt;, the function returns the constant value.&lt;/li&gt;
&lt;li&gt;If the polynomial is &lt;code&gt;Var&lt;/code&gt;, the function returns the value of &lt;code&gt;x&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If the polynomial is an &lt;code&gt;Sum&lt;/code&gt;, the function deconstructs the polynomial into its two operands and evaluates them using the &lt;code&gt;eval&lt;/code&gt; function. It then returns the sum of the two results.&lt;/li&gt;
&lt;li&gt;If the polynomial is a &lt;code&gt;Prod&lt;/code&gt;, the function again deconstructs the polynomial, evaluates them and returns the product of the two results.&lt;/li&gt;
&lt;li&gt;If the polynomial is a &lt;code&gt;Power&lt;/code&gt;, the function deconstructs the polynomial into its base and exponent, evaluates the base and returns the base raised to the power of the exponent.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This allows us to easily calculate the value of a polynomial of any complexity at a given value of x by destructuring it into its constituent parts and recursively evaluating each part. For example, here&apos;s how we can use the &lt;code&gt;eval&lt;/code&gt; function to evaluate the polynomial &lt;code&gt;x^2 + 2x + 1&lt;/code&gt; at &lt;code&gt;x = 2&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(* x^2 + 2x + 1 *)
let p = Sum(Power(Var, 2), Sum(Prod(Const 2, Var), Const 1))
let result = eval 2 p
(* let () = print_int result *)
(* 9 *)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another benefit to use pattern matching in complex structures like this is that the compiler will make sure your pattern matching is exhaustive so you won&apos;t ever miss a case.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;Handling Errors&lt;/h3&gt;
&lt;p&gt;Pattern matching can also be a useful technique for error handling. Consider the following to divide two integers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let div x y =
if y = 0 then Error &quot;Division by zero&quot;
else Ok (x / y)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;div&lt;/code&gt; function takes two integers as arguments and returns an &lt;code&gt;int&lt;/code&gt; value wrapped in an result type. If the second argument is &lt;code&gt;0&lt;/code&gt;, the function returns an &lt;code&gt;Error&lt;/code&gt;. Otherwise, it returns &lt;code&gt;Ok (x / y)&lt;/code&gt;. Now we can use pattern matching to handle the result of the &lt;code&gt;div&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let () =
let result = div 10 0 in
match result with
| Ok x -&amp;gt; print_endline (string_of_int x)
| Error msg -&amp;gt; print_endline msg
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a pretty simple example. In OCaml there are also option types which have two variants: &lt;code&gt;Some&lt;/code&gt; and &lt;code&gt;None&lt;/code&gt;. The &lt;code&gt;Some&lt;/code&gt; variant is used to wrap a value and the &lt;code&gt;None&lt;/code&gt; variant is used to represent the absence of a values.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In conclusion, pattern matching is a versatile and useful technique that can simplify and improve many aspects of your code. Whether its a simple script or a complex application, pattern matching can help you write code that is more correct, concise, expressive, and maintainable.&lt;/p&gt;
&lt;p&gt;Thanks for reading!&lt;/p&gt;
&lt;h2&gt;Credits&lt;/h2&gt;
&lt;p&gt;Thank you to the following people for proofreading and giving ideas for this article:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/Zain_Wania&quot;&gt;Zain Wania&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.brendonovich.dev/&quot;&gt;Brendan Allan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yxshv&quot;&gt;Yash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nsttt&quot;&gt;Néstor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Pattern_matching&quot;&gt;Pattern Matching - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Algebraic_data_type&quot;&gt;Algebraic Data Types - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Typesafe Database Queries on the Edge</title><link>https://www.nexxel.dev/blog/typesafe-database/</link><guid isPermaLink="true">https://www.nexxel.dev/blog/typesafe-database/</guid><description>Edge computing is all the rage. Learn how to get typesafe access to data on the edge using Kysely, Prisma and PlanetScale.</description><pubDate>Sat, 12 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Link from &quot;../../components/Link.vue&quot;;
import Code from &quot;../../components/Code.vue&quot;;
import { createHeading } from &quot;../../components/Heading&quot;;&lt;/p&gt;
&lt;p&gt;export const components = {
a: Link,
code: Code,
h1: createHeading(&quot;h1&quot;),
h2: createHeading(&quot;h2&quot;),
h3: createHeading(&quot;h3&quot;),
};&lt;/p&gt;
&lt;h2&gt;What is the Edge?&lt;/h2&gt;
&lt;p&gt;Edge computing is the new hottest thing in the web dev ecosystem, and rightfully so. If you don&apos;t know what the edge computing is, it&apos;s a way to run your code as close to your users as possible through globally distributed edge servers. This results in really low latency and no cold starts. But to stay performant, they have a limited runtime and code size limitations (1 MB on &lt;a href=&quot;https://developers.cloudflare.com/workers/platform/limits/#worker-size&quot;&gt;Workers&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;Prisma&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://prisma.io&quot;&gt;Prisma&lt;/a&gt; is an ORM that lets you write your database schema in it&apos;s special &lt;code&gt;.prisma&lt;/code&gt; syntax.&lt;/p&gt;
&lt;p&gt;It has first-class support for PostgreSQL, MySQL, SQLite, SQL Server, CockroachDB and even MongoDB. Prisma then generates TypeScript types based on the schema, which lets your query your database using the &lt;a href=&quot;https://prisma.io/client&quot;&gt;Prisma Client&lt;/a&gt; in a typesafe manner. It&apos;s fantastic.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://prisma.io/migrate&quot;&gt;Prisma Migrate&lt;/a&gt; is another great tool from the Prisma team to run database migrations without hassle.&lt;/p&gt;
&lt;p&gt;But it also has a lot of problems. The &lt;a href=&quot;https://rust-lang.org&quot;&gt;Rust&lt;/a&gt; based core of Prisma is approximately a 13 MB binary. Which means in serverless environments, the cold start times are awful because it takes a lot of time to spin up the Prisma binary. And you can pretty much forget running Prisma on the edge.&lt;/p&gt;
&lt;h2&gt;PlanetScale&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://planetscale.com&quot;&gt;PlanetScale&lt;/a&gt; is a serverless MySQL database provider which is based on &lt;a href=&quot;https://vitess.io&quot;&gt;Vitess&lt;/a&gt;. You get the scaling benefits of Vitess without the need to manage it yourself.&lt;/p&gt;
&lt;p&gt;The PlanetScale team recently released their &lt;a href=&quot;https://github.com/planetscale/database-js&quot;&gt;database driver&lt;/a&gt; which lets your query your PlanetScale database using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/fetch&quot;&gt;Fetch API&lt;/a&gt;. This means you can use this library to query your database in edge environments which is HUGE.&lt;/p&gt;
&lt;p&gt;Although it&apos;s a great library, it doesn&apos;t provide an typesafety.&lt;/p&gt;
&lt;h2&gt;Kysely&lt;/h2&gt;
&lt;p&gt;Enter &lt;a href=&quot;https://github.com/koskimas/kysely&quot;&gt;Kysely&lt;/a&gt;. It&apos;s a typesafe SQL query builder. You give it your schema as a TypeScript type and you can get wonderful typesafety and autocomplete while using the query builder. Take a look at this GIF from the Kysely Readme.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;It works in serverless and edge environments, even on &lt;a href=&quot;https://deno.land&quot;&gt;Deno&lt;/a&gt;! It also has support for using the PlanetScale database driver using &lt;a href=&quot;https://github.com/depot/kysely-planetscale&quot;&gt;kysely-planetscale&lt;/a&gt;. This is perfect.&lt;/p&gt;
&lt;p&gt;The only problem is that defining schemas in TypeScript is rough. It also doesn&apos;t have anything like &lt;a href=&quot;https://prisma.io/migrate&quot;&gt;Prisma Migrate&lt;/a&gt; to manage database migrations.&lt;/p&gt;
&lt;h2&gt;The Idea&lt;/h2&gt;
&lt;p&gt;Prisma is good at defining schemas, generating TypeScript types, and handling database migrations.&lt;/p&gt;
&lt;p&gt;Kysely along with the PlanetScale database driver are good for writing SQL in a typesafe manner on the edge.&lt;/p&gt;
&lt;p&gt;What if we combine both of these?&lt;/p&gt;
&lt;h2&gt;Implementing the Idea&lt;/h2&gt;
&lt;p&gt;Enough talking let&apos;s get to some actual code.&lt;/p&gt;
&lt;h3&gt;Setting Up a Database on PlanetScale&lt;/h3&gt;
&lt;p&gt;First create an account on PlanetScale and create a database. You can just sign in with your GitHub account and you&apos;re good to go.&lt;/p&gt;
&lt;h3&gt;Setting Up Prisma&lt;/h3&gt;
&lt;p&gt;I&apos;ll be using the newly released &lt;a href=&quot;https://start.solidjs.com&quot;&gt;SolidStart&lt;/a&gt; but this should work in all frameworks that support edge environments such as &lt;a href=&quot;https://nextjs.org&quot;&gt;Next.js&lt;/a&gt;, &lt;a href=&quot;https://remix.run&quot;&gt;Remix&lt;/a&gt;, &lt;a href=&quot;https://kit.svelte.dev/&quot;&gt;SvelteKit&lt;/a&gt;, etc.&lt;/p&gt;
&lt;p&gt;Install Prisma and the Prisma Client.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install -D prisma &amp;amp;&amp;amp; npm install @prisma/client
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now generate a &lt;code&gt;.env&lt;/code&gt; file and a starter schema using &lt;code&gt;prisma init&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx prisma init --datasouce-provider mysql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will create a &lt;code&gt;schema.prisma&lt;/code&gt; file inside a &lt;code&gt;prisma&lt;/code&gt; folder. It will also create a &lt;code&gt;.env&lt;/code&gt; file. Add your connection string from PlanetScale in the &lt;code&gt;DATABASE_URL&lt;/code&gt; variable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// prisma/schema.prisma
generator client {
provider = &quot;prisma-client-js&quot;
}
datasource db {
provider = &quot;mysql&quot;
url = env(&quot;DATABASE_URL&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since PlanetScale, rather &lt;a href=&quot;https://vitess.io/blog/2021-06-15-online-ddl-why-no-fk/&quot;&gt;Vitess doesn&apos;t support foreign key constraints&lt;/a&gt;, we need to set the &lt;code&gt;referentialIntegrity&lt;/code&gt; property in prisma.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// prisma/schema.prisma
generator client {
provider = &quot;prisma-client-js&quot;
previewFeatures = [&quot;referentialIntegrity&quot;]
}
datasource db {
provider = &quot;mysql&quot;
url = env(&quot;DATABASE_URL&quot;)
relationMode = &quot;prisma&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now make an &lt;code&gt;Example&lt;/code&gt; model. Models in Prisma represent the tables in a SQL database.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// prisma/schema.prisma
generator client {
provider = &quot;prisma-client-js&quot;
previewFeatures = [&quot;referentialIntegrity&quot;]
}
datasource db {
provider = &quot;mysql&quot;
url = env(&quot;DATABASE_URL&quot;)
relationMode = &quot;prisma&quot;
}
model Example {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
text String
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Push this schema to PlanetScale using &lt;code&gt;prisma db push&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx prisma db push
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will also run &lt;code&gt;prisma generate&lt;/code&gt; which generates the TypeScript types based on your schema. It is also recommended to add &lt;code&gt;prisma generate&lt;/code&gt; as a &lt;code&gt;postinstall&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt; so that whenever you install the dependencies, it will generate the types for you.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// package.json
&quot;scripts&quot;: {
&quot;postinstall&quot;: &quot;prisma generate&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is it for the Prisma setup.&lt;/p&gt;
&lt;h3&gt;Setting Up Kysely&lt;/h3&gt;
&lt;p&gt;Make sure you add the &lt;code&gt;DATABASE_USERNAME&lt;/code&gt; and &lt;code&gt;DATABASE_PASSWORD&lt;/code&gt; environment variables from PlanetScale.&lt;/p&gt;
&lt;p&gt;Install Kysely, the Kysely PlanetScale Dialect, and the PlanetScale databse driver.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install kysely kysely-planetscale @planetscale/database
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create a &lt;code&gt;src/server/db.ts&lt;/code&gt; or whatever file makes sense to you and add the following code.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// src/server/db.ts
import type { Example } from &quot;@prisma/client/edge&quot;;
import { Kysely } from &quot;kysely&quot;;
import { PlanetScaleDialect } from &quot;kysely-planetscale&quot;;
interface Database {
Example: Example;
}
export const db = new Kysely&amp;lt;Database&amp;gt;({
dialect: new PlanetScaleDialect({
host: &quot;aws.connect.psdb.cloud&quot;,
username: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD,
}),
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we&apos;re importing the &lt;code&gt;Example&lt;/code&gt; type that we had defined in our schema. If you go to definition of that type, you will see that that type has all the fields we had defined in our schema correctly typed.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export type Example = {
id: string;
createdAt: Date;
updatedAt: Date;
text: string;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Database&lt;/code&gt; interface will contain all our types. So let&apos;s say we also have a &lt;code&gt;SecondExample&lt;/code&gt; field in our database, we will have to import that type and add it in the &lt;code&gt;Database&lt;/code&gt; interface. This is one of the limitations of this approach, it requires you to add new types manually.&lt;/p&gt;
&lt;p&gt;Then we&apos;re exporting a Kysely instance that takes the &lt;code&gt;Database&lt;/code&gt; interface as a generic. The &lt;code&gt;PlanetScaleDialect&lt;/code&gt; tells Kysely to use the PlanetScale database driver to run the SQL queries.&lt;/p&gt;
&lt;h3&gt;Using Kysely&lt;/h3&gt;
&lt;p&gt;Note: This might look different in your framework but the Kysely code will be the same.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// src/routes/index.tsx
import { db } from &quot;~/server/db&quot;;
export const routeData = () =&amp;gt; {
return createServerData$(async () =&amp;gt; {
const examples = await db
.selectFrom(&quot;Example&quot;)
.selectAll()
.orderBy(&quot;createdAt&quot;, &quot;desc&quot;)
.execute();
console.log(examples);
return examples;
});
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will notice which typing this is that it&apos;s all beautifully autocompleted for you. Everything is fully typesafe.&lt;/p&gt;
&lt;p&gt;SolidStart also has end-to-end typesafety, so even in the UI code, the typesafety is maintained. This is similar to Remix patterns. I&apos;m also using &lt;a href=&quot;https://github.com/unocss/unocss&quot;&gt;UnoCSS&lt;/a&gt; in this example.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// src/routes/index.tsx
export default function Home() {
const examples = useRouteData&amp;lt;typeof routeData&amp;gt;();
return (
&amp;lt;main class=&quot;flex flex-col items-center h-screen bg-#050505 font-sans&quot;&amp;gt;
&amp;lt;div class=&quot;flex flex-col gap-y-2&quot;&amp;gt;
&amp;lt;For each={examples()}&amp;gt;
{(example) =&amp;gt; {
return &amp;lt;p class=&quot;text-white&quot;&amp;gt;{example.text}&amp;lt;/p&amp;gt;;
}}
&amp;lt;/For&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/main&amp;gt;
);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will notice that we didn&apos;t have to write any types ourselves for this. Everything is typesafe and we didn&apos;t even write any TypeScript. It&apos;s all inferred.&lt;/p&gt;
&lt;h3&gt;Limitations&lt;/h3&gt;
&lt;p&gt;This way of doing things can break when using &lt;a href=&quot;https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map&quot;&gt;&lt;code&gt;@map&lt;/code&gt;&lt;/a&gt; because the casing is different in the types. It also doesn&apos;t support &lt;a href=&quot;https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields#working-with-decimal&quot;&gt;&lt;code&gt;Prisma.Decimal&lt;/code&gt;&lt;/a&gt; because you have to use the special Prisma object to use it. &lt;a href=&quot;https://github.com/marklawlor&quot;&gt;Mark Lawlor&lt;/a&gt; has some insane TypeScript code to work around this problem but it&apos;s still very &quot;hacky&quot;. You can see his gist &lt;a href=&quot;https://gist.github.com/marklawlor/b1c26eefba43539c6611a508e67ee02f&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Update: A wonderful package called &lt;a href=&quot;https://github.com/valtyr/prisma-kysely&quot;&gt;&lt;code&gt;prisma-kysely&lt;/code&gt;&lt;/a&gt; created by &lt;a href=&quot;https://valtyr.is/&quot;&gt;Valtýr&lt;/a&gt; does all of this for you. You should probably use it instead of the approach I&apos;ve shown here.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Hopefully that all made sense. I think it is pretty cool. That&apos;s it really. Thanks for reading!&lt;/p&gt;
</content:encoded></item><item><title>My Developer Workflow Using WSL, tmux and Neovim</title><link>https://www.nexxel.dev/blog/wsl-workflow/</link><guid isPermaLink="true">https://www.nexxel.dev/blog/wsl-workflow/</guid><description>I live on the terminal now. Learn about the tools I use set up a productive developer environment.</description><pubDate>Tue, 16 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Link from &quot;../../components/Link.vue&quot;;
import Code from &quot;../../components/Code.vue&quot;;
import { createHeading } from &quot;../../components/Heading&quot;;&lt;/p&gt;
&lt;p&gt;export const components = {
a: Link,
code: Code,
h1: createHeading(&quot;h1&quot;),
h2: createHeading(&quot;h2&quot;),
h3: createHeading(&quot;h3&quot;),
};&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Hi! Today I&apos;m gonna talk about my daily developer workflow and all the tools I use to set up a productive enviroment for coding. I think having a nice looking terminal and some tools to save time are really helpful to keep you productive in daily coding sessions.&lt;/p&gt;
&lt;h2&gt;Operating System&lt;/h2&gt;
&lt;p&gt;I use Windows and it&apos;s pretty much unusable for programming. Thankfully Microsoft understood that and made &lt;a href=&quot;https://docs.microsoft.com/en-us/windows/wsl/&quot;&gt;Windows Subsystem for Linux&lt;/a&gt; also known as &lt;code&gt;WSL&lt;/code&gt; in short. It lets you run a Linux distribution inside of Windows.&lt;/p&gt;
&lt;p&gt;I use &lt;a href=&quot;https://ubuntu.com/&quot;&gt;Ubuntu&lt;/a&gt;, it&apos;s the default distribution that is installed with &lt;code&gt;WSL&lt;/code&gt;. Ubuntu is really simple to use and has a huge community so getting support is very easy. I highly recommend it for anyone who wants to start using Linux and get familiar with basic Linux commands.&lt;/p&gt;
&lt;h2&gt;Shell&lt;/h2&gt;
&lt;p&gt;Ubuntu by default comes with the bash shell. Bash is great but I personally find it harder to customize. That is why I use &lt;a href=&quot;https://zsh.org/&quot;&gt;Z shell&lt;/a&gt;, more commonly known as &lt;code&gt;zsh&lt;/code&gt;. To manage my &lt;code&gt;zsh&lt;/code&gt; configuration, I use &lt;a href=&quot;https://ohmyz.sh/&quot;&gt;Oh My Zsh&lt;/a&gt;. It has a huge community and makes it trivial to install and use plugins.&lt;/p&gt;
&lt;p&gt;I used to use &lt;a href=&quot;https://fishshell.com/&quot;&gt;fish&lt;/a&gt; which is also a great shell. It has very sensible defaults and comes with a lot of cool features like autosuggestions, tab completions, etc. out of the box without the need to set up anything. The only problem with fish is that it is not &lt;code&gt;POSIX-compliant&lt;/code&gt;. &lt;a href=&quot;https://en.wikipedia.org/wiki/POSIX&quot;&gt;POSIX&lt;/a&gt; is a set of standards that define how to develop programs for UNIX based operating systems. So in fish, things like bash scripts do not work. They have their own scripting language.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;zsh&lt;/code&gt; on the other hand is fully POSIX-compliant. This is why I switched to &lt;code&gt;zsh&lt;/code&gt; and I&apos;m quite happy with it so far.&lt;/p&gt;
&lt;h2&gt;Prompt&lt;/h2&gt;
&lt;p&gt;I use &lt;a href=&quot;https://starship.rs/&quot;&gt;Starship&lt;/a&gt; for my prompt and it is AMAZING. Written in &lt;a href=&quot;https://rust-lang.org/&quot;&gt;Rust&lt;/a&gt;, Starship is a minimal, highly customizable and super fast prompt. The default look of it is really good but literally every little detail is customizable to your liking. To install Starship refer to these &lt;a href=&quot;https://starship.rs/guide/#%F0%9F%9A%80-installation&quot;&gt;docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The configuration file for Starship lives in &lt;code&gt;~/.config/starship.toml&lt;/code&gt;. Here&apos;s my &lt;code&gt;starship.toml&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ~/.config/starship.toml
[aws]
symbol = &quot;&quot;
[conda]
symbol = &quot;&quot;
[dart]
symbol = &quot;&quot;
format = &quot;via [$symbol]($style)&quot;
[directory]
read_only = &quot;&quot;
truncation_length = 1
[docker_context]
symbol = &quot;&quot;
[elixir]
symbol = &quot;&quot;
format = &apos;via [$symbol]($style)&apos;
[elm]
symbol = &quot;&quot;
[git_branch]
symbol = &quot;&quot;
[golang]
symbol = &quot;&quot;
format = &apos;via [$symbol]($style)&apos;
[hg_branch]
symbol = &quot;&quot;
[java]
symbol = &quot;&quot;
format = &apos;via [$symbol]($style)&apos;
[julia]
symbol = &quot;&quot;
[memory_usage]
symbol = &quot;&quot;
[nim]
symbol = &quot;&quot;
[nix_shell]
symbol = &quot;&quot;
[nodejs]
symbol = &quot;&quot;
format = &apos;via [$symbol]($style)&apos;
[package]
symbol = &quot;&quot;
[perl]
symbol = &quot;&quot;
[php]
symbol = &quot;&quot;
[python]
symbol = &quot;&quot;
format = &apos;via [$symbol]($style)&apos;
[ruby]
symbol = &quot;&quot;
[rust]
format = &apos;via [$symbol]($style)&apos;
[scala]
symbol = &quot;&quot;
[shlvl]
symbol = &quot;&quot;
[swift]
symbol = &quot;&quot;
format = &apos;via [$symbol]($style)&apos;
[git_status]
disabled = true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The icons aren&apos;t showing up here because you need a &lt;a href=&quot;https://github.com/ryanoasis/nerd-fonts&quot;&gt;nerd font&lt;/a&gt; for that. If you set up a Nerd Font (I recommend &lt;a href=&quot;https://github.com/ryanoasis/nerd-fonts/tree/master/patched-fonts/Hack&quot;&gt;Hack&lt;/a&gt;), and copy this configuration, you&apos;ll get a very minimal looking prompt like this. For more information on configuring Starship, you can look at the docs &lt;a href=&quot;https://starship.rs/config/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Having a nice looking terminal always helps!&lt;/p&gt;
&lt;h2&gt;Persistent Terminal Sessions with tmux&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Tmux&quot;&gt;tmux&lt;/a&gt; is a terminal multiplexer. It lets you have multiple persistent terminal sessions and come back to them without terminating the existing running processes. So you can return to a workspace, exactly where you left it. It also allows you to manage multiple windows and panes inside a session.&lt;/p&gt;
&lt;p&gt;For example, to go to my website&apos;s workspace, I just have to type &lt;code&gt;website&lt;/code&gt; and I&apos;m there.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Here &lt;code&gt;website&lt;/code&gt; is an alias I&apos;ve set up to open the &lt;code&gt;website&lt;/code&gt; tmux session.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# .zshrc
alias website=&quot;tmux attach-session -t website&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way I can jump into any one of my workspaces really quickly and start coding. It also helps that I&apos;m exactly where I left off. I highly recommend tmux for local development, it has changed how I work and increased my productivity by a massive amount.&lt;/p&gt;
&lt;h2&gt;Neovim&lt;/h2&gt;
&lt;p&gt;I had been using &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;VSCode&lt;/a&gt; as my code editor since the first day I started learning programming, but recently I have switched to &lt;a href=&quot;https://neovim.io/&quot;&gt;Neovim&lt;/a&gt;. It is a modern version of &lt;a href=&quot;https://www.vim.org/&quot;&gt;Vim&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Neovim is the best code editor for me because of its speed and ease of customization. All the configuration is written in &lt;a href=&quot;https://www.lua.org/&quot;&gt;Lua&lt;/a&gt;, which is very easy to learn and write. It helps me be really fast and productive because I never have to take my hands off of my keyboard.&lt;/p&gt;
&lt;p&gt;You can find my Neovim configuration &lt;a href=&quot;https://github.com/nexxeln/nvim&quot;&gt;here&lt;/a&gt;. It&apos;s just a fork of &lt;a href=&quot;https://github.com/craftzdog/dotfiles-public&quot;&gt;craftzdog&apos;s configuration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;zoxide&lt;/h2&gt;
&lt;p&gt;You might have seen in some of the screenshots that I just have to run &lt;code&gt;z license-generator&lt;/code&gt; to jump to that directory. That is &lt;a href=&quot;https://github.com/ajeetdsouza/zoxide&quot;&gt;&lt;code&gt;zoxide&lt;/code&gt;&lt;/a&gt;. Also written in &lt;a href=&quot;https://rust-lang.org/&quot;&gt;Rust&lt;/a&gt;, it&apos;s a smarted &lt;code&gt;cd&lt;/code&gt; command that remembers which directories you visit frequently, so you can jump to those directories with just one command.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;The above GIF is from the &lt;a href=&quot;https://github.com/ajeetdsouza/zoxide&quot;&gt;zoxide GitHub repository&lt;/a&gt;. Use &lt;code&gt;zoxide&lt;/code&gt; to never go back to &lt;code&gt;cd&lt;/code&gt; hell again.&lt;/p&gt;
&lt;h2&gt;exa&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ogham/exa&quot;&gt;&lt;code&gt;exa&lt;/code&gt;&lt;/a&gt; is a modern replacement of the &lt;code&gt;ls&lt;/code&gt; command. I always find myself using &lt;code&gt;exa&lt;/code&gt; to get familiar with the files in a new codebase.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;As you can see in the screenshot, &lt;code&gt;exa&lt;/code&gt; has a more readable output with colors and icons which you can look at and instantly know the filetypes of different files. It is also noticeably faster than &lt;code&gt;ls&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It also has a &lt;a href=&quot;https://github.com/ogham/exa#command-line-options&quot;&gt;lot of flags&lt;/a&gt; which display the data is different formats. Here are the aliases I&apos;ve set up for &lt;code&gt;exa&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# .zshrc
alias ll=&quot;exa -l -g --icons --git&quot;
alias llt=&quot;exa -1 --icons --tree --git-ignore&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That was a quick overview of all the tools I use on a day-to-day basis for coding. I think it&apos;s really important to spend some time working on your workflow and coding setup, it will make you faster over time. I hope you found the tools I listed useful and will incorporate them in your workflow too!&lt;/p&gt;
&lt;p&gt;Thanks for reading!&lt;/p&gt;
</content:encoded></item><item><title>T3 Stack and My Most Popular Open Source Project Ever</title><link>https://www.nexxel.dev/blog/ct3a/</link><guid isPermaLink="true">https://www.nexxel.dev/blog/ct3a/</guid><description>create-t3-app recently reached 100 stars on GitHub and is my most popular open source project. Learn more about it!</description><pubDate>Mon, 27 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Link from &quot;../../components/Link.vue&quot;;
import Code from &quot;../../components/Code.vue&quot;;
import { createHeading } from &quot;../../components/Heading&quot;;&lt;/p&gt;
&lt;p&gt;export const components = {
a: Link,
code: Code,
h1: createHeading(&quot;h1&quot;),
h2: createHeading(&quot;h2&quot;),
h3: createHeading(&quot;h3&quot;),
};&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nexxeln/create-t3-app&quot;&gt;create-t3-app&lt;/a&gt; recently reached 90 stars on GitHub and is my most popular open source project with a lot of people contributing. Now you may be wondering, what the hell is it? Let&apos;s take a look at the t3 stack and how you can use create-t3-app.&lt;/p&gt;
&lt;h2&gt;T3 stack&lt;/h2&gt;
&lt;p&gt;The T3 stack was made by &lt;a href=&quot;https://www.youtube.com/c/TheoBrowne1017&quot;&gt;Theo&lt;/a&gt; who is a really cool dev and makes awesome content on YouTube. The stack consists of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nextjs.org&quot;&gt;Next.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trpc.io&quot;&gt;tRPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tailwindcss.com&quot;&gt;TailwindCSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://typescriptlang.org&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prisma.io&quot;&gt;Prisma&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I love this stack, if you want to know more about them checkout &lt;a href=&quot;https://init.tips&quot;&gt;init.tips&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/DhravyaShah/status/1540589276810711040&quot;&gt;this twitter thread&lt;/a&gt; from @dhravya.&lt;/p&gt;
&lt;p&gt;The only downside of this stack is the boilerplate, I had to open the docs, install all the packages, create a bunch of files just to set it up.&lt;/p&gt;
&lt;p&gt;Theo had also mentioned on stream how it would be very convenient to set up a project just by running &lt;code&gt;npx create-t3-app&lt;/code&gt;. So I did just that!&lt;/p&gt;
&lt;h2&gt;create-t3-app&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;create-t3-app&lt;/code&gt; makes it really convenient to scaffold a starter project using the T3 stack.&lt;/p&gt;
&lt;h3&gt;Usage&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;npx create-t3-app@latest
# or
yarn create t3-app
# or
pnpm create t3-app@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will let you select the packages you want and install them and create all the files those packages need.&lt;/p&gt;
&lt;p&gt;I started working on the CLI in May and back then I had no experience with Node CLIs, but it was definitely a great learning experience for me.&lt;/p&gt;
&lt;p&gt;Now the project has matured a lot and it&apos;s amazing to see Theo&apos;s community opening issues and contributing everyday, it&apos;s really great.&lt;/p&gt;
&lt;h2&gt;Maintaining Open Source&lt;/h2&gt;
&lt;p&gt;I have a lot of respect for OSS maintainers now because honestly, it is a really hard job. Looking at issues, reviewing and discussing PRs, it&apos;s definitely a bit tiring.&lt;/p&gt;
&lt;p&gt;I recently had burnout from this and took a 2 day break and just built a bunch of static sites. Theo&apos;s community is awesome though, we agree on most things and I rarely write code for the CLI now, people just open issues and make PRs, I just have to review and merge them.&lt;/p&gt;
&lt;p&gt;Overall this project has been a really great experience, I learnt so many things, from node CLIs to maintaining open source. Please do try the CLI out and open issues if you find bugs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Github: &lt;a href=&quot;https://github.com/nexxeln/create-t3-app&quot;&gt;nexxeln/create-t3-app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Website: &lt;a href=&quot;https://create.t3.gg&quot;&gt;create.t3.gg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;T3 Stack: &lt;a href=&quot;https://init.tips&quot;&gt;init.tips&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Theo: &lt;a href=&quot;https://twitter.com/t3dotgg&quot;&gt;twitter.com/t3dotgg&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thank you for reading!&lt;/p&gt;
</content:encoded></item><item><title>Create Licenses for Your Projects Right from the Terminal</title><link>https://www.nexxel.dev/blog/gen-license/</link><guid isPermaLink="true">https://www.nexxel.dev/blog/gen-license/</guid><description>I made a CLI in Rust to generate licenses for open source projects.</description><pubDate>Fri, 25 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Link from &quot;../../components/Link.vue&quot;;
import Code from &quot;../../components/Code.vue&quot;;
import { createHeading } from &quot;../../components/Heading&quot;;&lt;/p&gt;
&lt;p&gt;export const components = {
a: Link,
code: Code,
h1: createHeading(&quot;h1&quot;),
h2: createHeading(&quot;h2&quot;),
h3: createHeading(&quot;h3&quot;),
};&lt;/p&gt;
&lt;p&gt;I&apos;m the type of person who is constantly working on open source projects. But whenever I create a new repository, I haven&apos;t yet decided what license I should put the code under. So, I always had to add it at the end when I have pushed all the code. But it was just too much work: go to GitHub, click &lt;code&gt;Create File&lt;/code&gt;, type &lt;code&gt;LICENSE&lt;/code&gt;, choose the license and then push it and finally pull the changes locally. So I decided to make a CLI License Generator, in Rust.&lt;/p&gt;
&lt;p&gt;This was a nice project to build since I hadn&apos;t written Rust code in a while, so it was a good refresher.&lt;/p&gt;
&lt;h2&gt;Introducing gen-license&lt;/h2&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;It&apos;s as simple as that, it even automatically gets your username from your global git config file!&lt;/p&gt;
&lt;p&gt;Here&apos;s the source code: &lt;a href=&quot;https://github.com/nexxeln/license-generator&quot;&gt;nexxeln/license-generator&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;cargo install gen-license
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don&apos;t have cargo installed, you can download the executable from the &lt;a href=&quot;https://github.com/nexxeln/license-generator/releases&quot;&gt;releases&lt;/a&gt; section of the GitHub repository.&lt;/p&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;gen-license
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&apos;s pretty much it! Thank you for reading this far. If you want me to explain some of the code behind this, feel free to ask in the comment section.&lt;/p&gt;
&lt;p&gt;Please do give your feedback and leave a star on &lt;a href=&quot;https://github.com/nexxeln/license-generator&quot;&gt;GitHub&lt;/a&gt; if you liked it!&lt;/p&gt;
</content:encoded></item><item><title>I Made a Wordle Clone</title><link>https://www.nexxel.dev/blog/nexdle/</link><guid isPermaLink="true">https://www.nexxel.dev/blog/nexdle/</guid><description>Nexdle is a wordle clone made with React, TypeScript, TailwindCSS, Vite, Zustand and tested with Vitest.</description><pubDate>Mon, 21 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Link from &quot;../../components/Link.vue&quot;;
import Code from &quot;../../components/Code.vue&quot;;&lt;/p&gt;
&lt;p&gt;export const components = { a: Link, code: Code };&lt;/p&gt;
&lt;p&gt;Yes that&apos;s right, another wordle clone. You can play it &lt;a href=&quot;https://nexdle.nexxel.dev/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nexdle.nexxel.dev/&quot;&gt;nexdle&lt;/a&gt; is a &lt;a href=&quot;https://www.nytimes.com/games/wordle/index.html&quot;&gt;wordle&lt;/a&gt; clone made with &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt;, &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt;, &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;TailwindCSS&lt;/a&gt;, &lt;a href=&quot;https://vitejs.dev/&quot;&gt;Vite&lt;/a&gt;, &lt;a href=&quot;https://github.com/pmndrs/zustand&quot;&gt;Zustand&lt;/a&gt; and tested with &lt;a href=&quot;https://vitest.dev/&quot;&gt;Vitest&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This project was a great learning experience for me. Things I learnt while making nexdle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CSS Grids&lt;/li&gt;
&lt;li&gt;Using state management libraries (&lt;a href=&quot;https://github.com/pmndrs/zustand&quot;&gt;Zustand&lt;/a&gt; in this case)&lt;/li&gt;
&lt;li&gt;Using testing tools like Jest (&lt;a href=&quot;https://vitest.dev/&quot;&gt;Vitest&lt;/a&gt; in this case)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before this I had made a simple &lt;a href=&quot;https://github.com/nexxeln/todo-app&quot;&gt;todo-app&lt;/a&gt; to get comfortable with using TypeScript in React projects. Now after using it for 2 projects, I&apos;m absolutely in love with it. TypeScript is just so good for catching errors before shipping the app to production, and the autocomplete you get is just crazy. It takes the developer experience to a whole another level.&lt;/p&gt;
&lt;p&gt;I used TailwindCSS for all the styling because lets face it, CSS is really
fricking hard. Tailwind just makes it really simple and quick to make a stunning
ui. Just add pre-built CSS utility classes and you&apos;re good to go!&lt;/p&gt;
&lt;p&gt;I didn&apos;t use &lt;code&gt;create-react-app&lt;/code&gt; for this project. Instead I used Vite.
Vite is a module bundler, just like webpack. Since I&apos;ve come across Vite, I
haven&apos;t gone back to &lt;code&gt;create-react-app&lt;/code&gt;. It&apos;s just faster, has less dependencies
so the build size is less. If you haven&apos;t tried it yet, I highly recommend you
do!&lt;/p&gt;
&lt;p&gt;I finally learnt how to use state management libraries. In this project I used Zustand,
which is like a bare bones version of &lt;a href=&quot;https://redux.js.org/&quot;&gt;Redux&lt;/a&gt;. It&apos;s better
than using the Context API as its less boilerplatey. I figured for a small project
I don&apos;t really need to use a heavy library like Redux.&lt;/p&gt;
&lt;p&gt;A few weeks ago I learnt how to use &lt;a href=&quot;https://jestjs.io/&quot;&gt;Jest&lt;/a&gt; and I was really excited to try it out here. But I found out that it wasn&apos;t compatible with Vite. So I found this really awesome library called Vitest. Honestly, testing was the most fun part of the whole project. It helps you catch bugs before production and is just really fun to do.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Vitest also has this crazy ui testing option, I haven&apos;t explored it a lot but it&apos;s just insane. Check this out:&lt;/p&gt;
&lt;p&gt;
I also uploaded this gif to &lt;a href=&quot;https://youtu.be/2GLYNV5cQ-Y&quot;&gt;YouTube&lt;/a&gt; since it&apos;s kind
of long. You can watch it there if you prefer that.&lt;/p&gt;
&lt;p&gt;So that&apos;s it for this blog. All the code for nexdle can be found &lt;a href=&quot;https://github.com/nexxeln/nexdle/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you made it this far thanks for reading!&lt;/p&gt;
</content:encoded></item></channel></rss>