[{"content":" We\u0026#39;ve already crossed into the new year so it\u0026#39;s a little late, but regardless 2024 was an interesting year when thinking back.\nPersonal I went from fiancé -\u0026gt; husband -\u0026gt; father. That\u0026#39;s quite some amount of transition within a year, though each new phase is as exciting as the last.\nBoth Astrid and Jennifer are well and healthy after child birth, nothing more I can wish for. 2025 will be a fun year watching Astrid grow.\nProfessional Work wise, it has also been a blast. The amount of usage at Inngest has probably grown \u0026gt; 30x, I kinda lost track mid-year so honestly that number might be way higher.\nSome technical decisions we made earlier in the year already no longer stand very well, so we\u0026#39;ll be looking into a couple of rearchitectures to make sure we can continue the same pace of growth for 2025. And some systems, notably Redis can no longer bear the weight of what we need it to do.\nMy main theme for 2025 will be reliability and scalability, which will be interesting as we also need to be changing systems while handling rearchitecture. And as systems need to handle scale, some things will inevitably get more complex. While we\u0026#39;ll be hiring more in 2025, the balance of team size, deliverables, and complexity will need more consideration.\nLast I\u0026#39;d like to thank everyone involved, and I wish you a great 2025.\n","date":"2025-01-03","href":"/blog/2025-01-03-2024-in-review/","id":"a936572d4398db52d586ace30b27b1c9","summary":" We\u0026#39;ve already crossed into the new year so it\u0026#39;s a little late, but regardless 2024 was an interesting year when thinking back.\nPersonal I went from fiancé -\u0026gt; husband -\u0026gt; father. That\u0026#39;s quite some amount of transition within a year, though each new phase is as exciting as the last.\nBoth Astrid and Jennifer are well and healthy after child birth, nothing more I can wish for. 2025 will be a fun year watching Astrid grow.\n","title":"2024 in review","type":"blog"},{"content":" For the last couple of months, I\u0026#39;ve been trying out NixOS on my old 2015 Dell XPS 15.\nIt\u0026#39;s one of those laptops that are old enough that you can\u0026#39;t do much on it because the CPU is pretty slow at this point, but still good enough to test some stuff with.\n❯ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 39 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 8 On-line CPU(s) list: 0-7 Vendor ID: GenuineIntel Model name: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz CPU family: 6 Model: 94 Thread(s) per core: 2 Core(s) per socket: 4 Socket(s): 1 Stepping: 3 CPU(s) scaling MHz: 23% CPU max MHz: 3500.0000 CPU min MHz: 800.0000 BogoMIPS: 5199.98 It shouldn\u0026#39;t be that slow, but not sure what\u0026#39;s up with it The installation experience has been pretty smooth. After using Arch Linux for 5+ years, it\u0026#39;s definitely refreshing to be greeted by GNOME\u0026#39;s installer again. Click some buttons here and there, and the OS is installed, wiping whatever that was previously there.\nWhy NixOS? Nix itself has been on my radar for a while, but I didn\u0026#39;t interact with it for the longest time. The idea behind Nix is to make builds and configurations declarable and immutable, this makes it easy to package and distribute software in a consistent way.\nExpanding this idea to the operating system level means that system level packages and configurations can also be declarable and immutable.\nThere are some huge benefits for running systems in this way, but for me personally, the biggest appeal was to be able to rollback the OS when something went wrong, and there\u0026#39;s a bit of a history till I get here.\nUbuntu I started using Linux with Ubuntu around 2015, prior to that was OSX during college.\nThe initial intention was to get a better understanding of Linux by using it as a daily driver. It also helps a poor recent college grad for not having to pay for an Apple device which is not cheap, especially after moving from Japan to the U.S and there are a lot of other things to take care of financially.\nThis turned out great. For someone who didn\u0026#39;t major in Computer Science, messing around with a Linux laptop helped me gained a lot of insights into how a systems work in general. Ubuntu has put a lot of work into their graphical user interface so it also didn\u0026#39;t feel overwhelming diving into it.\nHowever this is where I started to feel the pain of package management systems, OS upgrades and system dependency messes. I remember very well around 2016, I upgraded Ubuntu to 16.04 and the system was pretty much broken, and I had to spend a day or so trying to figure how to revert it back to 14.04. I experienced this again at 18.04 and that\u0026#39;s when I started to think about ways to mitigate disruptions during upgrades.\nArch When I joined Cloudflare at 2019, that\u0026#39;s where I got a lot more exposure to Arch because there were quite a few SREs using them. I was also aware of Nix at the time, but I didn\u0026#39;t have a lot of time to invest into something fundamentally different, and the idea of a rolling release model was appealing.\nTo me, it\u0026#39;s just like how you would release software in a company. Not a giant batch every year or two, but incrementally, minimizing the changes you need, therefore reducing the risk of breaking the system entirely.\nThere was another interesting aspect to Arch, where you\u0026#39;re even more exposed to the system itself. While it was a little daunting at first, Arch has one of the best documentations in Linux distros, so that gave me confidence to jump in.\nArch has been my daily driver since then, both for my personal devices and work devices. Throughout this 4-5 year period, there was probably only once the system was broken to an extend that the OS can\u0026#39;t boot, but fixing it was pretty straightforward with the help of the documentations.\nOS upgrades are no longer a problem anymore, but another problem starts to catch my attention more. User space packages, and programming language installations are getting messy.\nNix, Home Manager I left oVice in February 2023, and was taking a couple months off to recharge. One day, when I was trying to do a system update of my device, I notice the installation failed with a weird error. After digging around a little, I realized asdf was messing with paths in a way that\u0026#39;s confusing the system package installation, and causing the process to fail.\nSince then, whenever I\u0026#39;m doing a system upgrade, I got into a habit of updating the PATH to exclude certain binaries prior to the upgrade itself, which felt wrong. That\u0026#39;s when Nix start resurfacing on my radar again.\nSince I\u0026#39;m on a break, I have the luxury of diving into something completely new, and I did the usual reading documentations end to end to get a good understanding of what I\u0026#39;m looking at.\nStarting with nix-shell to isolate dependencies in repositories, as I grew more comfortable, I started to utilizing home-manager to handle my user space config files and package installation. This allowed me to entirely remove asdf for managing runtime, and has cleared up my user space mess a lot.\nAs I put more configurations and dependencies under the control of home-manager, the more hacky scripts I wrote throughout the years were able to be thrown out the window. This felt great, a lot of times I don\u0026#39;t even remember the scripts themselves and what they do because I only needed them during laptop setup. This include a couple small Ansible playbooks I made for handling typical dependencies I need for the tools I use.\nWhat if I can apply this principle to the OS itself as well…?\nThoughts Fast forward to today, I\u0026#39;ve made the decision to completely switch my daily driver over to NixOS as mentioned at the start.\nA couple of things I learned in the past couple of months is, thanks to the replicable nature of Nix, a lot of system configurations can be shared. There has been a couple of occasions where by just following some of the Nix documentations and references, it end up creating the system a lot better I ever did.\nThe setup on my Desktop was extremely smooth as well. After logging into the terminal (no GUI installation), it was basically just\npull down my configurations from GitHub make a couple of tweaks and replace /etc/nixos/configuration.nix run sudo nixos-rebuild switch reboot And everything is ready to go.\nLearning flakes has also been interesting. I won\u0026#39;t say I\u0026#39;ve fully got the hang of it yet, but I\u0026#39;m definitely getting there bit by bit. It feels very nice to have some kind of lockfile specifying the system depenedencies, just like how you\u0026#39;d lock down the dependencies of projects in a repository.\nIt gives me the peace of mind that what I need for the repo will always be there so I don\u0026#39;t have to worry about weird system issues caused because of some kind of runtime manager messing with things without me knowing.\nThis was what I was looking for for a long time, and I\u0026#39;m glad I finally made the decision to switch. I\u0026#39;ve heard from friends before that they decided to leave Linux behind because they don\u0026#39;t have the time to spend to fix things anymore when they break.\nI\u0026#39;m hoping that trade-off is no longer necesary with what NixOS has to offer.\n","date":"2024-04-27","href":"/blog/2024-04-28-nixos/","id":"00ec82541dbc0299cc8efc57acac5b6f","summary":" For the last couple of months, I\u0026#39;ve been trying out NixOS on my old 2015 Dell XPS 15.\nIt\u0026#39;s one of those laptops that are old enough that you can\u0026#39;t do much on it because the CPU is pretty slow at this point, but still good enough to test some stuff with.\n❯ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 39 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 8 On-line CPU(s) list: 0-7 Vendor ID: GenuineIntel Model name: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz CPU family: 6 Model: 94 Thread(s) per core: 2 Core(s) per socket: 4 Socket(s): 1 Stepping: 3 CPU(s) scaling MHz: 23% CPU max MHz: 3500.0000 CPU min MHz: 800.0000 BogoMIPS: 5199.98 It shouldn\u0026#39;t be that slow, but not sure what\u0026#39;s up with it The installation experience has been pretty smooth. After using Arch Linux for 5+ years, it\u0026#39;s definitely refreshing to be greeted by GNOME\u0026#39;s installer again. Click some buttons here and there, and the OS is installed, wiping whatever that was previously there.\n","title":"Moving to NixOS","type":"blog"},{"content":" What are your impressions of Japan? Great food? Clean? Safe? Polite people? Great service?\nThese are all true. It’s no doubt that Japan is a great place to visit for vacations, but how about working at a Japanese company? Specifically, at a tech startup?\nThis was a question I asked myself 2 years ago before I joined oVice as their Head of Engineering. I’ve lived in Japan for 12 years, but that was mainly my higher education years, and I’ve never worked there full-time before, so I was genuinely curious.\nAfter 18 months at a Japanese tech startup, here are some learnings.\nContext Before I go into some details, I want to ensure I set the ground to avoid misunderstandings. While Japan is one of the largest countries when it comes to IT spending, the way business is done is inherently different from the US.\nMeaning, you should see it from a mindset of “they just do things differently from us.”\nIf you’re a company considering expanding into the Japanese market, I hope this can help you set some expectations before diving in.\nEnglish speakers are rare English is a defacto language in the world of business you’d assume? Well, not in Japan. It’s estimated roughly 2% of the population are fluent English speakers.\nWhy? There are 2 reasons from my perspective.\nEducation Japan’s education focuses heavily on exams and memorization. This is nothing unique as eastern Asian countries are all somewhat similar including South Korea and China. However, the key point here is that English curriculums in Japan generally lack any kind of interaction.\nIf you’ve tried to learn a new language before, you’ll probably know that the best way to get better at that language is to talk to people. Hang out, chit chat, and talk about random/serious stuff. There are a ton of information included in face to face interactions, and you can pick up a lot of vocabulary and social context in those conversations, but that’s never really part of the curriculum when it comes to English education.\nUnfortunately, it’s all about memorizing grammar and vocabulary, but they’re rarely put to use. Everything needs practice, and obviously if it isn’t, then there’s nothing that can come out of it.\nPerfectionism People are generally afraid to speak unless they think their English is Good.\nAnd Good in Japan means close to a native speaker level. That’s a very high bar for someone who hasn\u0026#39;t spoken that language before, and it causes folks to go into a negative loop of not wanting to speak, hence losing the chances to improve their communication skills.\nWhat does this mean? It’s extremely hard to communicate intentions.\nA Japanese startup obviously and justly will have Japanese employees. However, an unknown fact about tech startups (and even large enterprises) in Japan is that many of their engineering teams are not Japanese, and my organization was not an exception either.\nSo while myself is fluent in Japanese, a large portion of my team is not, and finding someone that can bridge that gap is difficult simply because of language requirements.\nAnd language is just the beginning when it comes to communication. There are different social norms, assumptions, biases, expectations based on racial and even individual backgrounds. And on top of that, Japanese are not well known for being vocal, so with all these as compounding factors, it makes communication between teams, and cross department collaboration very hard.\nEnterprise heavy As a startup, you want to be nimble while continuing to grow. If you’re a BtoB SaaS, your initial customers are more likely to be fellow startups, SMBs, or Mid-market businesses that can be early adopters, provide you feedback and be customers that grow with you.\nClosing enterprise deals are always exciting, but they’re usually not the customers you want to onboard in an early stage. Sales cycles are long, due diligence and compliance (SOC2, ISO27001, GDPR, and whatever local) requirements take too long, and are too resource intensive for a startup to handle.\nIf you attempt that same strategy in Japan, you’re likely going nowhere when it comes to deal closing. Historically, Japan does business primarily with relationships and distributors, it’s still pretty much the same these days.\nWhile I do start seeing some changes, the majority of the businesses, including SMBs will only sign up for a service if\nA famous enterprise in Japan uses the service A distributor they have a relationship with recommends the service Meaning cold outreach or ads won’t get you very far. Possibly not even through the door. So in order to be able to sell to anyone, you’ll need to either close a deal with a well-known Japanese enterprise or partner with a distributor.\nClosing an enterprise deal If you were able to close an enterprise deal, great! Things are going to be smooth moving forward!\nWell, not so fast. As with any enterprise customers, their demands are (rightfully) high. Accommodating their needs after closing the deal is just as resource intensive as trying to close the deal itself.\nSome of the enterprise companies we’ve worked with have been very understanding, a lot more than I’d expected and they were extremely reasonable. Some, I just have no idea what to do with them.\nAnother interesting learning is that SLA means pretty much nothing to enterprise customers.\nThis is probably true universally, as I’ve seen the VP of Engineering having to go on a trip to apologize to customers whenever we had a large outage at Cloudflare.\nPartnering with distributors Finding a local partner that will distribute your service can be a lot faster than trying to close an enterprise deal. Depending on your partner, they might also actively help you sell your service and provide some amount of customer support.\nIf you don’t have anyone on your team that speaks Japanese, these are all great deals. But like everything in life, there is a tradeoff.\nThe way it’s sold might not align with your brand: Unless you have stringent brand guidelines, how your product gets sold might not be what you expect. They also might not be sold to your target customers either. Your partners are not your sales team, meaning they won’t know what you want them to know and sell how you want them to sell. Partnerships are generally revenue share or commission based, so the incentive is to sell to as many customers as possible regardless of the demographics. Customer support won’t get you the details you want: If your partner helps with providing customer support, it can be a lifesaver for you, especially without a Japanese speaking team. However, they might not have an English speaking team that can communicate with you either. Even if they do, they’re unlikely to help dig into issues that can result in actionable items to be passed on to product and engineering. This is especially true if your partner has a lot of other partners, so they simply won’t have the time or incentive to give you the white glove support. And if you’re a fast moving startup, any changes you make could be their potential nightmare as support procedures could change frequently, and eventually, they’ll want to stop dealing with you because you’re too much work for them.\nWhat does this mean? Your headwind for making changes to the system will get stronger over time. Unless you have a system that can segment customers and provide different release schedules, this is generally true.\nWe’ve done things like,\nproviding feature flags for managing feature releases an on-demand release schedule staging =\u0026gt; RC =\u0026gt; production environment release flow and even providing a very simple canary environment to mitigate risks while balancing the speed of changes but still push backs for releasing changes never decreased.\nProduct philosophy is different Building a startup in the US generally means starting small and focused. It’s rare to find companies doing many things, as it goes against what we consider best practices. This is rightfully so since startups don’t have the resources to be it all. There are a lot of SaaS these days, so being a wide and shallow service generally doesn’t give you much of an edge when customers are more likely to be doing research themselves and looking for a specific solution to a problem they have.\nThis is not the case for Japan. First, SaaS is not a thing in Japan yet. Even though the market is undoubtedly growing, the idea of using a service provider is still a minority when it comes to making business decisions.\nA lot of IT systems in Japan are built by companies categorized as SIers (system integrators).\nThey’re essentially a development agency that will build whatever the customer asks for, even if it might not make sense technically, and on a very very tight deadline.\nBeing used to having white glove service from SIers means Japanese companies expect to get everything they ask for. So it’s not uncommon to need a lot of (potentially unrelated) features in order to close a deal.\nAlso, fundamentally there are just not many providers to choose from. Meaning making choices to combine services to fit a company\u0026#39;s needs in Japan is very limited. And due to the historical systems built by Slers, the cost of moving to a service provider that only does a fraction of what they want is pretty high.\nIt’s not hard to imagine why companies are reluctant to buy into SaaS if you know that context, but this becomes a chicken or egg problem. Which goes first?\nWhat does this mean? The last thing you want to do as a startup is to stretch yourself thin. Features are usually never deprecated once they’re released, and it’s one more thing you need to maintain. Unless of course, you’re the type of person that always tracks the usage of your product features.\nEven then, scope creep is pretty much inevitable when you’re working with potential customers in Japan. In order for them to make the switch, it’s a requirement for them to make sure things continue to work smoothly and without disruptions. Because many of their systems are custom made, there are no good ways to just deactivate certain portions of their system and expect things to continue to work well because who knows how those systems are built.\nPotential customers will ask a lot from you, and rightfully so due to how their current system works. It will sound unreasonable if you don’t understand the context. Well, on second thought, it’s quite unreasonable even if you do.\nAs the SaaS market (hopefully) grows, these issues could be resolved over time.\nIs Japan a good market? If you’re a startup looking to expand internationally, and you’re considering Japan, my recommendation is, don’t do it until you have closed some Enterprise customers already in the US or EU. Get some experience there under your belt first, it\u0026#39;s likely a lot easier.\nJapan can be a significant market opportunity, and companies can have large budgets, but you should always treat any customers there as an Enterprise level client regardless of their size.\nThere is a general sentiment that people want to increase productivity, but they don’t really know how. Technology literacy is surprisingly low, so expect to get A LOT of support requests, including how to use the service itself. Some customers will expect you to provide some kind of guidebook for them called 仕様書 (shiyousyo) with all the features listed in it.\nThis is a non-starter for a startup, or probably ever for any tech company unless you’re only going to make releases every 6 months or something.\nSecurity One more thing. People generally forget about security until the very last minute, so here are some observations when it comes to deal closing.\nJapan doesn’t really have a security or compliance standard like SOC2 or ISO27001. There’s a thing recently introduced by the Japanese government called ISMAP but it’s a joke so unless you have the resource level like Amazon, Google, or Microsoft, don’t try to even get certification since it’s just not worth the effort and cost - we were quoted around $300k-$400k equivalent when we checked with auditors last time.\nHaving said that, any large enterprise usually has some kind of single sign-on implementation. Either it be SAML or LDAP. If you’re going to persuade Japanese companies, make sure you have those systems implemented so it’ll make the conversation a lot smoother. The last thing you want is a deal falling through because of security concerns.\nAnother interesting thing a lot of companies love to do is IP address whitelisting. As a startup operating on AWS, it was close to impossible trying to comply with that while also making improvements to things like caching and CDNs.\nThere are ways to do this using Elastic IPs, and if you own an IP CIDR already (which we end up securing an CIDR with APNIC), there’s the BYOIP service by AWS (I assume there’s something similar in GCP and Azure).\nIt’s likely a lot easier as well if your product is a TCP based request/response type of service, because you know, the servers accepting traffic should be stateless. We unfortunately, were a WebRTC based service built on UDP so it was very challenging when it comes to releasing changes while making sure IP addresses don\u0026#39;t change after deployments.\n","date":"2023-07-12","href":"/blog/2023-07-12-learnings-from-jp-startup/","id":"f022e2816a07d478faf6518aa519e3ce","summary":" What are your impressions of Japan? Great food? Clean? Safe? Polite people? Great service?\nThese are all true. It’s no doubt that Japan is a great place to visit for vacations, but how about working at a Japanese company? Specifically, at a tech startup?\nThis was a question I asked myself 2 years ago before I joined oVice as their Head of Engineering. I’ve lived in Japan for 12 years, but that was mainly my higher education years, and I’ve never worked there full-time before, so I was genuinely curious.\n","title":"Learnings from working at a Japanese startup","type":"blog"},{"content":" A quick setup guide for .heex files on Emacs. At the time of writing, Doom Emacs only supports up to 28, and 29+ are not supported yet. This guide could become irrelevent once Emacs 29 becomes stable.\nSince I\u0026#39;m using Doom Emacs, this will provide steps to get .heex working on it as well.\nWe\u0026#39;ll need to install the tree-sitter-cli before proceeding.\nRust version\ngit clone https://github.com/tree-sitter/tree-sitter cd tree-sitter/cli cargo build --release # Build tree-sitter in release mode cd ../ cp ./target/release/tree-sitter /path/for/bin NOTE: You\u0026#39;ll need the v0.19.5 since v0.20 has some breaking changes There\u0026#39;s a NPM package as well so this can be used if Rust is not installed in your system.\nNPM version\nnpm i -g tree-sitter-cli@19 NOTE: I did not try this but it should work Verify with the following command.\n\u0026gt; ~/bin/tree-sitter tree-sitter 0.19.5 (8d8690538ef0029885c7ef1f163b0e32f256a5aa) Max Brunsfeld \u0026lt;maxbrunsfeld@gmail.com\u0026gt; Generates and tests parsers USAGE: tree-sitter \u0026lt;SUBCOMMAND\u0026gt; FLAGS: -h, --help Prints help information -V, --version Prints version information SUBCOMMANDS: build-wasm Compile a parser to WASM dump-languages Print info about all known language parsers generate Generate a parser help Prints this message or the help of the given subcommand(s) highlight Highlight a file init-config Generate a default config file parse Parse files query Search files using a syntax tree query tags test Run a parser\u0026#39;s tests web-ui Test a parser interactively in the browser Check if tree-sitter-cli is installed properly Build Let\u0026#39;s start with retrieving the tree-sitter code for heex.\nThe repo for tree-sitter-heex is provided by the Phoenix team and is available at phoenixframework/tree-sitter-heex.\ngit clone https://github.com/phoenixframework/tree-sitter-heex.git Clone repository to local workstation At the time of writting, tree-sitter-heex comes with src/parser.c, but since it was generated with v0.20 of the CLI, we\u0026#39;ll need to use the v0.19 version to regenerate it.\ntree-sitter generate Generate parser.c with tree-sitter-cli You should see some diffs after the command which you can ignore.\n\u0026gt; git status On branch main Your branch is up to date with \u0026#39;origin/main\u0026#39;. Changes not staged for commit: (use \u0026#34;git add \u0026lt;file\u0026gt;...\u0026#34; to update what will be committed) (use \u0026#34;git restore \u0026lt;file\u0026gt;...\u0026#34; to discard changes in working directory) modified: src/parser.c modified: src/tree_sitter/parser.h no changes added to commit (use \u0026#34;git add\u0026#34; and/or \u0026#34;git commit -a\u0026#34;) cc -shared -fPIC -fno-exceptions -g -I src src/parser.c -o ./heex.so -O2 You should see a heex.so file now.\nEmacs Now that heex.so is available, it\u0026#39;s time to get it loaded into Emacs.\nTree-sitter Emacs looks for custom built libraries in tree-sitter-load-path, which is a list of strings. You can run Alt x =\u0026gt; describe-variable in Emacs to check for the current values. In my case, $HOME/.tree-sitter-/bin was already included in the variable so I\u0026#39;ll be placing the built heex.so there.\nmkdir -p ~/.tree-sitter/bin mv ./heex.so ~/.tree-sitter/bin/ Next step will be to instruct Emacs to load heex.so when it opened a file with .heex extension.\nAdd the following to ~/.doom.d/config.el\n;; Elixir ;; Add heex-mode for modifying .heex files (define-derived-mode heex-mode web-mode \u0026#34;HEEx\u0026#34; \u0026#34;Major mode for editing HEEx files\u0026#34;) (add-to-list \u0026#39;auto-mode-alist \u0026#39;(\u0026#34;\\\\.heex?\\\\\u0026#39;\u0026#34; . heex-mode)) (add-to-list \u0026#39;tree-sitter-major-mode-language-alist \u0026#39;(heex-mode . heex)) (add-hook \u0026#39;heex-mode-hook #\u0026#39;tree-sitter-hl-mode) (add-hook \u0026#39;heex-mode-hook (lambda() ;; Ask tree-sitter to load \u0026#39;heex.so\u0026#39; (tree-sitter-load \u0026#39;heex) ;; Auto format .heex files on save, requires liveview 0.18+ (add-hook \u0026#39;before-save-hook \u0026#39;elixir-format nil t))) Add a new heex mode and load it with .heex files Restart/reload Emacs and this should now show up.\nHEEx mode activated for .heex files Notes Syntax highlighting itself is not really working for me at the moment, so will probably update this post after I figure that out. Might have to deal with web-mode directly.\nReferences https://github.com/tree-sitter/tree-sitter/tree/master/cli https://tree-sitter.github.io/tree-sitter/creating-parsers#command-generate https://github.com/doomemacs/doomemacs/blob/master/modules/tools/tree-sitter/README.org ","date":"2023-04-05","href":"/blog/2023-04-05-doom-emacs-heex-tree-sitter/","id":"be91c147ddb08b9d79943648ca8c32b4","summary":" A quick setup guide for .heex files on Emacs. At the time of writing, Doom Emacs only supports up to 28, and 29+ are not supported yet. This guide could become irrelevent once Emacs 29 becomes stable.\nSince I\u0026#39;m using Doom Emacs, this will provide steps to get .heex working on it as well.\nWe\u0026#39;ll need to install the tree-sitter-cli before proceeding.\nRust version\ngit clone https://github.com/tree-sitter/tree-sitter cd tree-sitter/cli cargo build --release # Build tree-sitter in release mode cd ../ cp ./target/release/tree-sitter /path/for/bin NOTE: You\u0026#39;ll need the v0.19.5 since v0.20 has some breaking changes There\u0026#39;s a NPM package as well so this can be used if Rust is not installed in your system.\n","title":"HEEx on Doom Emacs","type":"blog"},{"content":" Command palettes are generally cool, at least I think so. Not sure if it\u0026#39;s the original, but the first one I recall seeing it in use was Macintosh\u0026#39;s search bar feature.\nAlfred then became a pretty popular app as to fill the gap, and lately we\u0026#39;re seeing more apps also implementing command palettes like Slack, Linear, GitHub and probably thousands more that I\u0026#39;m not aware of.\nI\u0026#39;m proud to say that this little website of mine has also implmented one for search purposes. Mainly to help me find things in the future since I generally only remember the reference points, and not the content itself. As long as I know roughly what I want to find, search should be able to narrow the candidates for me.\nEnough of the reasonings for my self satisfaction and let\u0026#39;s take a look at how it\u0026#39;s built.\nWhat are we looking at Expectations are important so I\u0026#39;m setting it beforehand.\nThis blog post is merely going to share how to build a command palette UI, but won\u0026#39;t be providing any sort of data.\nIf you\u0026#39;re using Hugo as well, there are custom outputs that can generate the site data into formats like JSON, which then can be consumed by the UI code. That\u0026#39;s how this website is made. How the search should work is up to you so feel free to customize and tweak it to your liking.\nWhat the search palette looks like at the time of writing. Setup walkover There\u0026#39;s nothing more annoying than to ask someone to read another person\u0026#39;s random code out of the blue. So here\u0026#39;s a rough walk through of the setup to give you a better idea of what\u0026#39;s going on.\nStructure of the code For the sake of my sanity, and also showcasing a working version, the code being referenced will be the one that\u0026#39;s currently being used on this website.\nThere are 2 components in the search file.\nA nice search input like button that opens up the command palette The actual command palette itself You can see the full version on GitHub. The footer is separated as a partial file but since it\u0026#39;s rather irrelevant for this post, we can ignore it.\n*Latest version might look different\nAlpine.js integration Since this sample is based on Alpine, make sure to have it installed. I recommend to use the CDN distributed version initially for simplicity.\n\u0026lt;script defer src=\u0026#34;https://cdn.jsdelivr.net/npm/@alpinejs/focus@3.x.x/dist/cdn.min.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;script defer src=\u0026#34;https://cdn.jsdelivr.net/npm/alpinejs@3.12.0/dist/cdn.min.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; Source is available here on GitHub This code includes the Focus plugin for Alpine and Alpine itself. I\u0026#39;ll explain why we want the plugin later.\nFlexSearch The search functionality will be supported via FlexSearch. Similar to Alpine, I recommend to use the CDN distributed version for simplicity.\n\u0026lt;script defer src=\u0026#34;https://cdn.jsdelivr.net/gh/nextapps-de/flexsearch@0.7.31/dist/flexsearch.bundle.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; Source is available here on GitHub Data When searching something, you obviously need to provide the content to be searched for. Hugo by default generates HTML, AMP and RSS pages out of the box. However, it also has a way to generate custom data as well via custom outputs.\nSince this website is using FlexSearch which is a JavaScript library, providing data as JSON makes it easier to feed it into FlexSearch.\noutputFormats: SearchIndex: mediaType: application/json baseName: searchindex isPlainText: true isHTML: false notAlternative: true outputs: home: - HTML - RSS - SearchIndex configuration for settings up JSON custom output in Hugo This config declares a new output format called SearchIndex, that\u0026#39;s data type is JSON and the filename for Hugo to reference is searchindex. Hugo will expect there to be a template file at /layouts/_default/list.searchindex.json which will be used to generate the JSON data content.\nIn order for Hugo to actually generate the data file, make sure to add SearchIndex to the outputs list. Once generated, the data can be seen at /searchindex.json. Feel free to take a look at the JSON data of this website to get an idea of what I\u0026#39;m talking about.\nHere\u0026#39;s an example of how the template will look like.\n{{- $.Scratch.Add \u0026#34;searchindex\u0026#34; slice -}} {{- range (where .Site.RegularPages \u0026#34;Type\u0026#34; \u0026#34;in\u0026#34; .Site.Params.mainSections) -}} {{- $.Scratch.Add \u0026#34;searchindex\u0026#34; (dict \u0026#34;id\u0026#34; .Params.uuid \u0026#34;type\u0026#34; .Type \u0026#34;title\u0026#34; .Title \u0026#34;href\u0026#34; .RelPermalink \u0026#34;summary\u0026#34; (.Summary | plainify) \u0026#34;content\u0026#34; .Plain) -}} {{- end -}} {{- $.Scratch.Get \u0026#34;searchindex\u0026#34; | jsonify -}} Template is available on GitHub. You can see more details regarding Hugo\u0026#39;s custom outputs here.\nImplementation Now that the foundation is set, let\u0026#39;s take a look at the implmentation itself.\nData initialization \u0026lt;div x-data=\u0026#34;{ searchbar: false, searchterm: \u0026#39;\u0026#39;, searchresults: [], index: createIndex() }\u0026#34; \u0026gt; ... \u0026lt;/div\u0026gt; Source is available here on GitHub The data being used for searching are initialized at the top DOM object of the file.\nsearchbar decides if the palette can be shown or not searchterm is the term that\u0026#39;s being searched searchresults is a list that contains the results that matches searchterm index is the Document object initialized from FlexSearch The index object is a rather unique one compared the other rather self explanatory variables. It basically holds and indexes the list of contents, and will be the one used during searching as well.\n// Initiate and register all contents from \u0026#34;/searchindex.json\u0026#34; const createIndex = () =\u0026gt; { const index = new FlexSearch.Document({ tokenize: \u0026#34;forward\u0026#34;, cache: 100, document: { id: \u0026#34;id\u0026#34;, store: [\u0026#34;href\u0026#34;, \u0026#34;title\u0026#34;, \u0026#34;summary\u0026#34;, \u0026#34;type\u0026#34;], index: [\u0026#34;title\u0026#34;, \u0026#34;summary\u0026#34;, \u0026#34;content\u0026#34;], }, }) // built by template /layouts/_default/list.searchindex.json fetch(\u0026#34;/searchindex.json\u0026#34;) .then(resp =\u0026gt; resp.json()) .then(contentList =\u0026gt; { contentList.forEach(content =\u0026gt; { // console.log(content) index.add(content) }) console.log(\u0026#34;Indexed contents\u0026#34;) }) .catch(err =\u0026gt; console.error(err)) return index } Initializing FlexSearch document and index contents You should see something like the code above at the end of the file. It\u0026#39;s basically telling FlexSearch to,\nWhich method to use for indexing – e.g. forward, there\u0026#39;s a direct memory usage tradeoff here The capacity of cached entries Document structure – which field to use as ID, which fields to store and which to use as indices And then retrieve the generated content data from /searchindex.json and insert each of them into the index.\nYou can see more details of FlexSearch\u0026#39;s Document object here – v0.7.31.\nActivating the command palette There are a 2 ways to show the command palette.\nClicking on the search input like button Type Ctrl k or Cmd k if you\u0026#39;re on macOS or Windows The hidden HTML class is used as the way to hide the command palette, and the searchbar variable is the one determining if the hidden class will be assigned or not.\n\u0026lt;div :class=\u0026#34;searchbar ? \u0026#39;\u0026#39; : \u0026#39;hidden\u0026#39;\u0026#34; x-cloak \u0026gt; ... \u0026lt;/div Source is available here on GitHub So when the button is clicked, searchbar is set to true.\n\u0026lt;button @click=\u0026#34;searchbar = true\u0026#34;\u0026gt; ... \u0026lt;/button\u0026gt; Source is available here on GitHub The other way using Ctrl k or Cmd k is done like this.\n\u0026lt;div @keydown.ctrl.k.prevent.document=\u0026#34;searchbar = true\u0026#34; @keydown.meta.k.prevent.document=\u0026#34;searchbar = true\u0026#34; \u0026gt; ... \u0026lt;/div\u0026gt; Source is available here on GitHub Which is basically the same as\ndocument.addEventListener(\u0026#34;keydown\u0026#34;, (e) =\u0026gt; { e.preventDefault() if ((e.ctrlKey \u0026amp;\u0026amp; e.key === \u0026#34;k\u0026#34;) || (e.metaKey \u0026amp;\u0026amp; e.key === \u0026#34;k\u0026#34;)) this.searchbar = true; }) Trapping focus When the command palette appears, it\u0026#39;s best to keep all interactions against the command palette until you close it. This is where the Focus plugin comes in.\nx-trap can be used for restraining the focus within the specified DOM object based on a JS expression. In this base, searchbar will be the expression for activating x-trap.\n\u0026lt;div x-trap.inert.noscroll.noreturn=\u0026#34;searchbar\u0026#34;\u0026gt; ... \u0026lt;/div\u0026gt; Source is available here on GitHub .inert, .noscroll, .noreturn are all modifiers of x-trap. You can learn more about them in the documentation.\nThe main reason for using x-trap here is to utilize $focus. It makes traversing UI components easier to implement.\n\u0026lt;ul @keydown.tab.document=\u0026#34;$focus.wrap().next()\u0026#34; \u0026gt; ... \u0026lt;/ul\u0026gt; Source is available here on GitHub Which is equivalent to something like the following\ndocument.addEventListener(\u0026#34;keydown\u0026#34;, (e) =\u0026gt; { e.preventDefault() if (e.key !== \u0026#34;Tab\u0026#34;) return; const focusables = document.querySelectorAll(\u0026#34;a\u0026#34;) const currentItemIdx = focusables.indexOf(document.activeElement) const nextItemIdx = currentItemIdx + 1 \u0026lt; focusables.length ? currentItemIdx + 1 : 0 focusables[nextItemIdx].focus() }) Rough raw JS implementation of $focus.wrap().next() Closing the command palette If you can open something, you should be able to close it as well. Assuming you have been following, the closing of the command palette should be rather straightforward.\n\u0026lt;div @keydown.escape.document=\u0026#34;searchbar = false\u0026#34; \u0026gt; ... \u0026lt;/div\u0026gt; Source is available here on GitHub Yes, it\u0026#39;s just assigning searchbar to false, and the hidden HTML class will be added back to the DOM object, which will result in hiding it completely.\nSearch That was a lot of thing to go through but we\u0026#39;re finally at the search step. There\u0026#39;ll be a couple of things to look into at this step.\nExecuting the search Show the results of the search Show No Results when nothing matches the search term Executing the search Search is done using the index object that was initialized at the beginning. Here\u0026#39;s the function for running a search.\nconst SEARCH_LIMIT = 5 const searchItems = (term, index) =\u0026gt; { const results = index.search(term, SEARCH_LIMIT, { enrich: true }) // De-duplicate the results as search can match multiple fields // e.g. title, description const dedup = {} for (const result of results.flatMap(r =\u0026gt; r.result)) { if (!dedup[result.id]) dedup[result.id] = result.doc } return Object.values(dedup) || [] } Source is available here on GitHub The result of this function should return a list of objects like the following.\n{ \u0026#34;id\u0026#34;: \u0026#34;\u0026lt;UUID\u0026gt;\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;some title\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;blog | note | project\u0026#34;, \u0026#34;href\u0026#34;: \u0026#34;link to the content\u0026#34;, \u0026#34;summary\u0026#34;: \u0026#34;short summary of the content\u0026#34;, \u0026#34;content\u0026#34;: \u0026#34;full text of the content\u0026#34; } With that, let\u0026#39;s take a look at how the searchItems function is called.\n\u0026lt;input type=\u0026#34;text\u0026#34; placeholder=\u0026#34;Search...\u0026#34; autocomplete=\u0026#34;off\u0026#34; @keydown.debounce=\u0026#34;searchterm = $event.target.value; searchresults = searchItems($event.target.value, index)\u0026#34; /\u0026gt; Source is available here on GitHub 3 things are happening here.\nAdd debounce so functions are not triggered on every single key stroke Assign the value of the input field to searchterm Assign the results of searchItems function to searchresults #1 is generally a nice to have. If the search computation is not light, you don\u0026#39;t want it to run on every key stroke and debounce will delay the execution. By default, Alpine\u0026#39;s debounce will delay the execution for 250 ms.\nThe reasoning for #2 is more apparent in the following sections so I\u0026#39;ll be skipping the explanation for now.\nWhat you\u0026#39;re seeing here is a rough equivalent to this JS code.\nconst debounce = (fn, timeout = 2500) =\u0026gt; { let timer return (..args) =\u0026gt; { clearTimeout(timer) timer = setTimeout(() =\u0026gt; fn.apply(this, args), timeout) } } document.addEventListener(\u0026#34;keydown\u0026#34;, (e) =\u0026gt; { debounce(() =\u0026gt; { searchterm = e.target.value // string input searchresults = searchItems(searchterm, index) }) }) Show the results of the search Now that the searchterm and searchresults stores the values we care about, it\u0026#39;s time to show it to the users.\n\u0026lt;ul :class=\u0026#34;searchresults.length === 0 \u0026amp;\u0026amp; searchterm.length \u0026gt; 0 ? \u0026#39;hidden\u0026#39; : \u0026#39;\u0026#39;\u0026#34; @keydown.tab.document=\u0026#34;$focus.wrap().next()\u0026#34; \u0026gt; \u0026lt;template x-for=\u0026#34;item in searchresults\u0026#34;\u0026gt; \u0026lt;li :key=\u0026#34;item.id\u0026#34;\u0026gt; \u0026lt;a :href=\u0026#34;item.href\u0026#34;\u0026gt; \u0026lt;icon /\u0026gt; \u0026lt;div x-text=\u0026#34;item.title\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;div x-text=\u0026#34;item.summary\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/a\u0026gt; \u0026lt;/li\u0026gt; \u0026lt;/template\u0026gt; \u0026lt;ul\u0026gt; Source is available here on GitHub A section of this code probably looks familiar. Similar to some elements shared previously, the visibility of the ul DOM element is based on the hidden HTML class. How it\u0026#39;s determined to be shown or not depends on both searchterm and searchresults not being empty.\nThe reason for also using searchterm here is to make sure that the list UI is not shown on initial rendering where there\u0026#39;re no inputs.\ntemplate is a way for Alpine to use for modifying the DOM and replacing similar elements, and is common when used with some kind of condition logic.\nNo results available Similar to determining when the results are shown, there should also be a way to show that there is nothing found for the specified search term.\n\u0026lt;div :class=\u0026#34;searchresults.length === 0 \u0026amp;\u0026amp; searchterm.length \u0026gt; 0 ? \u0026#39;\u0026#39; : \u0026#39;hidden\u0026#39;\u0026#34; \u0026gt; \u0026lt;p\u0026gt;No results found\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;We couldn’t find anything with that term. Please try again.\u0026lt;/p\u0026gt; \u0026lt;/div\u0026gt; Source is available here on GitHub The logic is mostly similar with a slight twist, searchresults should be an empty list. This will result in the following UI.\nUI indicating nothing matches the term being searched Food for thought That was a brief run through of how to implement a command palette with Alpine and FlexSearch. The functioning version of the code is also accessible here on GitHub with the TailwindCSS classes to make it look like the screenshots.\nA couple things worth thinking of if you\u0026#39;re considering going with this approach.\nHow data is provided This example is based on having a static JSON data that can be read by FlexSearch when the page loads. This might not be the case for you, depending on where your data is coming from.\nObviously if you have some kind of remote data source based on the kind of search infrastructure like Elasticsearch or Typesense, retrieving that data will need to be more involved.\nThe provided solution in this article will work a lot better for static content than dynamic content. For example, company blogs, or documentation websites where the content is generally static.\nScalability and resource consumption However, even with just static contents, it\u0026#39;s unclear how performant this solution can be. The cache option for FlexSearch initialization can be pretty influential when it comes to resource consumption of the user\u0026#39;s laptop.\nAlso, since I\u0026#39;ve not done any real load testing, it\u0026#39;s unclear how much resources FlexSearch might require if there\u0026#39;s a somewhat large data set.\nHaving said all that, it\u0026#39;s very unlikely that you\u0026#39;ll have millions of contents for company blogs or documentation websites so my rough educated guess is that this solution should work mostly fine.\n","date":"2023-04-03","href":"/blog/2023-04-03-command-palette-with-alpinejs-and-flexsearch/","id":"fdec6c3cf1b576f0bb40f04ac8e9e004","summary":" Command palettes are generally cool, at least I think so. Not sure if it\u0026#39;s the original, but the first one I recall seeing it in use was Macintosh\u0026#39;s search bar feature.\nAlfred then became a pretty popular app as to fill the gap, and lately we\u0026#39;re seeing more apps also implementing command palettes like Slack, Linear, GitHub and probably thousands more that I\u0026#39;m not aware of.\nI\u0026#39;m proud to say that this little website of mine has also implmented one for search purposes. Mainly to help me find things in the future since I generally only remember the reference points, and not the content itself. As long as I know roughly what I want to find, search should be able to narrow the candidates for me.\n","title":"Command palette with Alpine.js and FlexSearch","type":"blog"},{"content":" If you\u0026#39;ve visited my personal website before, you can see that it looks completely different now.\nAfter leaving oVice at Feb 2023 – which I\u0026#39;m thinking of maybe writing about the learnings in the near future –, I\u0026#39;ve been taking some time off, working on some side projects, including redoing this very website you\u0026#39;re looking at right now.\nFor people who have never visited, and for the sake of my own memory plus historical references, here\u0026#39;s a before and after comparison.\nPrevious version based on Jykell and the Moonwalk theme The current version based on Hugo and the Gruvbox theme For the longest time, I was never really interested in building or maintaining a personal website. If I remember correctly, the first version was pretty much based on a homework back in college, and I don\u0026#39;t think I ever published it.\nEven after started working, I\u0026#39;ve always viewed personal websites as more of something that designers will do for showcasing their portfolios. As an engineer, I always felt there wasn\u0026#39;t really much I have to show the world , especially when working more on backend related systems that are mostly proprietary.\nAs time passes, there were periods that I felt like I want to write something but didn\u0026#39;t really have a platform to do so. And every time I\u0026#39;ll try out some services of that\u0026#39;s popular then like Wordpress, Medium and a couple more that I\u0026#39;m blanking on. However, every time it felt like I didn\u0026#39;t really have control over the content, and the writing experience is honestly not something I liked.\nAt some point, keeping a personal website started growing on me again but it wasn\u0026#39;t enough to spend the effort to actually try to build something – also for various other reasons with life and work. That urge slowly continued to grow as I start using Emacs\u0026#39; org-mode more for keeping notes, and enjoying the comfort of doing so in my editor. Making writing and expressing thoughts feel less…, cumbersome. Also having a couple of side projects I have in mind and want to work on, and wanted a place to be able to share and showcase them became a good reasoning too.\nSo roughly a few weeks ago, the thought came to me.\nSince I\u0026#39;m taking a little break anyways, why not actually sit down and spend some time to build out something that I\u0026#39;ll be satisfied of?\nAnd that\u0026#39;s the beginning for a week long rabbit hole.\nComposition Foundation\nSite generator: Hugo Theme: Gruvbox The site is built on top of Hugo. The main reason for Hugo is that it has native support for using org-mode for writing content. I honestly don\u0026#39;t mind using Markdown too but if something can support org-mode better, I\u0026#39;d rather use that. Markdown is more of a fallback in case certain custom syntax doesn\u0026#39;t get parsed well – e.g. shortcodes.\nThe choice of a theme is really more of a personal preference. I\u0026#39;m using the Zenburn theme for my editor so I was looking for something that\u0026#39;s similar or close to it when it comes to color scheme. While skimming over some available themes online, Gruvbox caught my eye. It looks pretty close to what Zenburn is and I like the designs in general. Kudos to Michael Schnerring for creating something so nice looking.\nThe default Gruvbox theme came with the following:\nFlexSearch: Indexing and searching through contents in the website Simple Icons: Free icons for well known brands and logos Tabler Icons: Great wide range of icons perfect for most needs Prism: JavaScript library for code syntax highlighting Hugo JSON resume module: A module for rendering JSON resume in Hugo – made by Michael Hugo GitHub README stats: A module for rendering GitHub repository statistics in Hugo – made by Michael It\u0026#39;s pretty impressive the amount of stuff Michael has made to be honest.\nCustomization The majority of the changes were re-organizing the theme to my liking. Here\u0026#39;s the list of PRs if anyone is interested.\nMainly the work can be categorized into\nChanging the layouts for certain types of content Replacing CSS files with Tailwind CSS Removing unused modules and libraries: Prism, JSON resume module, GH README stats Layout changes This website has 3 types of contents,\nBlog posts Personal notes Project pages Since each of them is used in a slightly different context, I\u0026#39;ve created a layout for each of the content types. For example, Blog post types have a Table of Contents sidebar that doesn\u0026#39;t exist in other content layouts. That kind of small things here and there.\nCSS file replacements I\u0026#39;m not very good at front end development and creating nice looking UIs – something I\u0026#39;m working on. That\u0026#39;s because CSS has always been something that I can\u0026#39;t fully get my head around. I know enough to be able to get things look like how I want them to look, but why sometimes something don\u0026#39;t align well – e.g. vertically, it always doesn\u0026#39;t look obvious without understanding the DOM in depth.\nTailwind CSS has changed my life in this regard. Being able to compose classes and shape things up with a simple approach has been an amazing developer experience. While there\u0026#39;s nothing wrong with the CSS that came with the theme, in order to fully own it and be able to customize the theme as I see fit, converting it over to use Tailwind was essential.\nMaking a tweak here and there is so much more simple now…, personally.\nCleaning up unused stuff While there are a lots of nice things that came with the theme, the majority of them I\u0026#39;m not utilizing. For example, JSON resume is nice but I rather control how I want to render the data. Also Prism seems kinda unnecessary when Hugo already comes with syntax highlighting built-in.\nIt always felt good to see thousands of lines removed from package-lock.json. :tada: :tada: :tada:\nEnhancements There were some improvements – personal preferences – made as well.\nAll JavaScript were converted to TypeScript for easier maintenance Added Alpine.js for UI simple interactions There aren\u0026#39;t a lot of JS in the original version, basically just a file for changing the site\u0026#39;s theme from dark to light and vice versa, and another one that implements FlexSearch onto the website.\nThe conversion over to TS was fairly straightforward. The more interesting one is converting the FlexSearch implementation to use Alpine.\nBy using Alpine, I was able to simplified a lot of the dance happening between JS and the DOM, and I was able to contain all search related logic in this search.html partial file now. The only functions I needed to declare in a script tag were,\nInitialization/indexing of the content – createIndex Search and return the results – searchItems Over engineering With Alpine simplifying the UI interaction logic, I decided to go one step further and reimplment the search bar as a command palette. I\u0026#39;m actually a big fan of it ever since seeing it in Slack and Linear. But obviously, not a lot of people will need to do search on other people\u0026#39;s personal website.\nThe excuse is, it\u0026#39;s a good practice for me since I have a couple side projects I have in mind that might make use of a command palette for search or simply just executing commands.\nThis is what it looks like when you type Ctrl K on this website now.\nCommand palette for searching the website Honestly I think it looks pretty neat. :grin:\nThe command palette was a pretty fun implementation so I\u0026#39;ll probably do a separate blog post for it.\nConclusion? None really, except maybe diving into rabbit holes every once in a while is actually pretty fun. Enjoying being in that rabbit hole is one of the reasons why I became an engineer in the first place.\nI was also able to learn about some interesting libraries like FlexSearch, and icon libraries like Tabler Icons and Simple Icons, all are good things to use when working on other projects in the future.\nAs for this website, there are still some tweaks I\u0026#39;m planning to make but overall I\u0026#39;m pretty satisfied with what I have right now. I expect I\u0026#39;ll be doing more writing with the shiny new site, but let\u0026#39;s see how that goes. :stuck_out_tongue:\n","date":"2023-03-31","href":"/blog/2023-03-31-over-engineering-a-website-overhaul/","id":"de3872c3897defe22e0b5a9fbe7a5f75","summary":" If you\u0026#39;ve visited my personal website before, you can see that it looks completely different now.\nAfter leaving oVice at Feb 2023 – which I\u0026#39;m thinking of maybe writing about the learnings in the near future –, I\u0026#39;ve been taking some time off, working on some side projects, including redoing this very website you\u0026#39;re looking at right now.\nFor people who have never visited, and for the sake of my own memory plus historical references, here\u0026#39;s a before and after comparison.\n","title":"Over engineering a website overhaul","type":"blog"},{"content":" https://emacsdocs.com\nAn attempt to modernize Emacs\u0026#39; documentation\nEmacs\u0026#39; documentation is not the most friendly in the world. Especially in terms for searching for things.\nAn attempt to parse the existing docs and generate a site that is more accessible, and user friendly so both new and existing users can benefit from it.\nThis is still WIP.\n","date":"2023-01-01","href":"/projects/emacs-docs/","id":"e52ddaaaf4d3869cb930ab6000f97110","summary":" https://emacsdocs.com\nAn attempt to modernize Emacs\u0026#39; documentation\nEmacs\u0026#39; documentation is not the most friendly in the world. Especially in terms for searching for things.\nAn attempt to parse the existing docs and generate a site that is more accessible, and user friendly so both new and existing users can benefit from it.\nThis is still WIP.\n","title":"Emacs Docs","type":"projects"},{"content":" Poker estimation app for async teams.\nStarted as a side project to help with ticket estimations for Agile teams.\nEstimation sessions usually takes a lot longer than necessary and team members regularly checkout mentally after some amount of time. Especially when certain tickets that either they\u0026#39;re not part of, or have no context on.\nPlanning sessions can be used more productively if the initial estimation itself can be done beforehand, people getting context prior, and during each individual\u0026#39;s free time.\nDeprecated as of 2024.\n","date":"2023-01-01","href":"/projects/pokerasync/","id":"8204e537a5375578d4af4c88800d4c71","summary":" Poker estimation app for async teams.\nStarted as a side project to help with ticket estimations for Agile teams.\nEstimation sessions usually takes a lot longer than necessary and team members regularly checkout mentally after some amount of time. Especially when certain tickets that either they\u0026#39;re not part of, or have no context on.\nPlanning sessions can be used more productively if the initial estimation itself can be done beforehand, people getting context prior, and during each individual\u0026#39;s free time.\n","title":"PokerAsync","type":"projects"},{"content":" https://github.com/oviceinc/ecto-ulid\nA fork of the Ecto ULID repo from the RealReal and added support for things like ULID/UUID compatibility.\nRefactored the code a little for better readability.\nAlso added better support for ULID/UUID conversation.\n","date":"2022-01-01","href":"/projects/ecto-ulid/","id":"c1e54508ad67e2f7eced9f72f598777b","summary":" https://github.com/oviceinc/ecto-ulid\nA fork of the Ecto ULID repo from the RealReal and added support for things like ULID/UUID compatibility.\nRefactored the code a little for better readability.\nAlso added better support for ULID/UUID conversation.\n","title":"Ecto ULID","type":"projects"},{"content":" Cloudflare\u0026#39;s office at 101 Townsend San Francisco September 3rd, 2021 was my last day at Cloudflare. It was an exciting 2 years, being in the front seat of a fast-growing company.\nI was part of an SWE/SRE team within the Infrastructure organization that builds out automation for data center and hardware operations, helping the company to handle its ever-growing numbers of servers. The work was fun and fulfilling, and the team is great - people you can truly trust and know that they will have your back is not an environment you often find.\nAlso, it was an eye-opening experience being able to see how certain things get done from the inside. For example, Cloudflare\u0026#39;s blog is a well-known and highly rated content in the industry. One of the main reasons is its transparency and the sophistication of the content itself. A lot of folks will agree that they\u0026#39;ve learned a lot just by reading through Cloudflare\u0026#39;s technical blogs. If there\u0026#39;s an incident or something went wrong, you\u0026#39;ll also be able to know what exactly went wrong and how does Cloudflare makes sure it doesn\u0026#39;t happen again. This creates trust for customers and eventually led to better business.\nDuring my final executive interview with Matthew (CEO), I asked him, \u0026#34;what does trust mean to you?\u0026#34;. To this day, his answer still sticks with me.\nThere are 3 types of trust:\nTrust from customers\nLetting them know you have their backs and will always be there for them. Making sure issues are transparently communicated and how they\u0026#39;re handled to make sure it doesn\u0026#39;t happen again.\nTrust from your team (employees)\nA corporation is ultimately just a group of people. Without them, you can\u0026#39;t operate. As a company, we should all be heading to the same direction, so making sure that there\u0026#39;s trust within the company will result in more happy people, which will ultimately lead to having more happy customers.\nTrust from society (and communities)\nA company with happy employees can\u0026#39;t operate on it\u0026#39;s own. It\u0026#39;s built on top of layers of infrastructure and communities. While making money is a priority for a profit organization, we need to make sure we fulfill our share of responsibilities and give back to the communities we build our business on. Without them, there\u0026#39;s no us, so having that trust between Cloudflare and our communities is also very important.\nPretty insightful, right? His answer was the ultimate push for me to decide to join Cloudflare 2 years ago and I can tell you he has been true to his words even by observing from afar.\nWhile the company is doing extremely well with a 600%+ value growth for the past 2 years, I\u0026#39;m pretty sure it won\u0026#39;t stop there and it will continue to do well in the coming years.\nCloudflare\u0026#39;s stock growth in the past 2 years You can tell how much I like being at Cloudflare, so leaving was a very hard decision to make, including the financial incentives. But having said that, I\u0026#39;m quite excited about my next opportunity.\nWhy oVice? The title pretty much speaks for itself. I\u0026#39;ll be joining oVice (headquartered in Japan) as the VP of Engineering starting September 27th, 2021.\nSo what is oVice and why I made the jump from a successful public company to a startup?\nObviously, it\u0026#39;s the Metaverse!!\nThat\u0026#39;s going to be next big thing!!!\nJokes aside, the actual reasons for me to join oVice are,\nBeing to be able to provide options for a more flexible work-life balance Solving the technical challenges to provide for #1 The offline/online hybrid work style After we all went into lockdown with COVID-19, I\u0026#39;ve got nothing much to do after work so I started helping out other companies as a technical advisor. oVice was one of them.\noVice\u0026#39;s service concept The product was extremely interesting. The company positions itself as a service provider for virtual real estate. Meaning you can sign up for spaces with oVice, customize it to your liking and then network and connect with people there, or do whatever you want to do like how you would with a piece of land in the real world.\nWhile I love the idea of being able to work remotely and not having to commute to the office — the traffic around San Francisco is just pure horror and on top of that, you might get your car\u0026#39;s window smashed. Why in the world would someone want to go pay for parking in the city for 8 hours and head home with a $500 bill? Just doesn\u0026#39;t make sense —, one of the major pain points has been the loss of human interactions when people are present in a physical space.\nReplicating human interactions online There are numerous times we\u0026#39;ve overheard some other interesting conversations happening nearby, jumping in, and then lead to ideas and cross-team collaboration efforts you wouldn\u0026#39;t have come up with if you\u0026#39;ve just been sitting by your own in a little box.\nBeing all by yourself in an isolated space 24/7 can be pretty lonely as well. Humans are social animals so being able to chit-chat and talk with people can be good for one\u0026#39;s mental health. Zoom and Google Meet are not helping in that sense, and they are not designed to be used that way so you really can\u0026#39;t blame them for it.\noVice tries to solve that problem digitally. The avatar that represents you can move around freely within each space, and there\u0026#39;s a concept of direction and distance built into the app. Meaning, there\u0026#39;s only so far your voice can travel. So if you\u0026#39;re too far away from one another, you\u0026#39;ll no longer be able to hear what other people are saying, which is pretty close to what you\u0026#39;ll expect in the real world.\nThis means that you can virtually sneak up to a group of people and start eavesdropping on them, like how you\u0026#39;ll do it in the real world!! I mean, that\u0026#39;s how you network with other folks, right? :P\nAs time passes, it can get harder to keep in touch with folks that were once part of our lives, due to physical reasons or maybe other responsibilities. While most existing customers use oVice for work or school, it can be also used for all kinds of other gatherings, like one-time events and class reunions, etc.\nHow will work look in the future? Reducing the need or requirement to be at a physical location could help people lead a lifestyle they want as well. Perhaps you don\u0026#39;t like to live in crowded places like New York City or San Francisco (or Tokyo) but still want to be able to work for a company located there. oVice can help achieve that, and can still make you feel like you\u0026#39;re close to the people you work with regardless of the physical distance apart.\nOn the other hand, if you\u0026#39;re a company looking to access talent globally, oVice can help you make sure employees in remote locations feels like they\u0026#39;re part of the team regardless of where they live. Having that sense of belonging can be a crucial part of both the company\u0026#39;s and the hire\u0026#39;s success.\nWhen I see technology having the potential to help bridge the gaps, and provide alternatives to the traditional ways of doing things, that\u0026#39;s when I get most excited.\nNOTE: We can\u0026#39;t solve time zones just in case if you\u0026#39;re wondering so you\u0026#39;ll need to figure that part out yourself\nTechnical challenges I\u0026#39;m an engineer at heart, and solving problems are what I enjoy doing most.\nFor oVice to fulfill its full potential, there are a tremendous amount of technical challenges to solve. While WebRTC technology is not something new, the major difference between oVice and other existing video collaboration tools like Zoom or Google Meets is that you have the extra layer of real-time visual interactions on top. That adds a new set of complexity for human-machine interactions and making this work will be something quite interesting to solve.\nWhat would mobile interactions look like? How do we allow other people to develop on top of oVice and create their own experience? How do we make sure things scale and handle connections well even with 10s of thousands of connections in certain spaces? How do we make sure the people working in an office and people working remotely can still collaborate well together? These are all interesting problems to solve, both complexity-wise and scalability-wise. And being one of the early companies in this space, our solutions could have the potential to become the next norm of how people interact with each other moving forward.\nJust to be clear, we\u0026#39;re not trying to make you ditch the real world and make you throw yourself completely into the digital world like some companies are. We\u0026#39;re merely trying to extend what\u0026#39;s possible, and allow people to choose the best options for themselves and how they want to live their lives.\nTechnologies have evolved a lot in the last 2 decades, and I believe we\u0026#39;re at a turning point that we can achieve what our predecessors couldn\u0026#39;t.\nSounds interesting?\nWe\u0026#39;ve just closed on our Series A and we\u0026#39;re expanding globally (Will share English press once released).\nhttps://thebridge.jp/2021/09/ovice-series-a-round-funding\nCome join us!!\nProduct Designer Software Engineer (Backend) Software Engineer (WebRTC) Site Reliability Engineer The location is fully remote. The job description is set to the US because LinkedIn won\u0026#39;t let me just set it as remote.\n","date":"2021-09-23","href":"/blog/2021-09-23-joining-ovice-as-vp-of-engineering/","id":"89d6beac9ff773f394c3fbc2ef9d4be5","summary":" Cloudflare\u0026#39;s office at 101 Townsend San Francisco September 3rd, 2021 was my last day at Cloudflare. It was an exciting 2 years, being in the front seat of a fast-growing company.\nI was part of an SWE/SRE team within the Infrastructure organization that builds out automation for data center and hardware operations, helping the company to handle its ever-growing numbers of servers. The work was fun and fulfilling, and the team is great - people you can truly trust and know that they will have your back is not an environment you often find.\n","title":"Joining oVice as VP of Engineering","type":"blog"},{"content":" LivePing started as a side project in early 2019.\nAt first, I was just trying to deal with the pain handling Cron tasks and offline workers, and looking into existing solutions wasn\u0026#39;t very satisfying. Building a prototype was relatively easy since the concept itself was simple.\nThe foundation of the project was done in a couple days, a couple evenings after work and BOOM! 💥 MVP completed. After that, it was just adding a small feature here and there every week or two.\nMistakes 🈲 A few weeks later, after talking to a colleague which I don\u0026#39;t recall what the exact conversations were, I got excited and thought it was a good idea to launch it as a service and make it publicly available.\nI know how to launch a service. What could possibly go wrong, right?\nAllow me to share some of the mistakes I\u0026#39;ve made.\nPre-Optimization After deciding to publicly launch the product, a ton of engineering work suddenly showed up.\nSign up / Login Authentication Authorization Access Controls API designs etc.\nSo far in my career, I\u0026#39;m lucky to have been able to work with and learn from engineers that would try to do things \u0026#34;the right way\u0026#34;. Which is extremely important when working with multiple engineering teams on an established product. However, that\u0026#39;s not the right approach for a product in an early stage.\nMy mind has been so biased towards the \u0026#34;right engineering approaches\u0026#34; that I\u0026#39;ve been ignoring what actually matters.\nJust get it out of the door, talk to people and iterate\nAs a result, it cost me months instead of weeks before putting the product before people\u0026#39;s eyes, just because I wanted to do a fancy Typescript React Front-End with a Rails API and using Procotol Buffers for communication, because I don\u0026#39;t want to maintain the API schema. I over engineered the infrastructure as well and while it can scale well, it has become a financial burden because doing things the right way is not cheap.\nTo be honest, it did help catch a lot of issues when doing some major schema changes. Oh, and did I mentioned that my colleague actually tried to DDoS the service and it withhold? Pretty impressive right? But it doesn\u0026#39;t matter, it\u0026#39;s still solving the wrong problems at the stage it was in.\nUnderestimating the amount of work outside of engineering Being an engineer and knowing engineers, we tend to think that building a good product will automatically get us customers and the rest will be history. While there are some portion of truth to it, having a good product will likely give you some advantages over your competitors, it\u0026#39;s definitely not going to take over the world just like that.\nAfter making LivePing public, I started looking into landing pages, marketing, SEOs, in-corporation, accounting, etc..\nThere\u0026#39;s a lot of work besides just coding something out and throwing it on the internet, and I\u0026#39;ve seriously underestimated that. And critically enough, I\u0026#39;ve done it in the wrong order. Building a product, then market it was a complete waste of effort and time, especially when there\u0026#39;s not even a close to guarantee that the product will be what you think it would become.\nPositive side, while I\u0026#39;ve never really thought that other jobs would be easier than mine (maybe a little bit :P), I\u0026#39;ve learned to really appreciate the work of the people in marketing, sales and all the other departments that operates and runs a company. Experiences like this makes you more humble and I think I understand why a lot of successful CEOs have a humble mindset now.\nNot verifying the market size Business is about people and solving their problems. Verifying the needs and pains your product solve is the first step which most people knows, clearly. However, another important portion that tends to get overlooked is the size of the market.\nSure, the product is solving a pain, I\u0026#39;ve conducted user interviews before deciding to make it an actual product, and there already are competitors in the field so that helps me verify that there are need for such a tool. But if the market is not big enough, it might not be worth the effort pursuing.\nTrying to make $1000 in a $10,000 market vs a $1,000,000 market is a huge difference. Neither will be easy, but the effort required for the former could be way higher than the latter, resulting in the cost and effort of trying to grow the product becoming higher than the rewards.\nIn the past couple months, I\u0026#39;ve learned that the market LivePing is in are one of those markets that efforts can be greater than rewards, hence making it harder justifying the additional effort to be put into the service.\nYou might be thinking, \u0026#34;Clearly you\u0026#39;re not doing a good enough job of researching the market beforehand, otherwise you\u0026#39;ve known\u0026#34;.\nWhile I do admit that I did ran with optimism, it\u0026#39;s also hard to know when and what is \u0026#34;good enough\u0026#34;. I\u0026#39;ve come to learn that, there\u0026#39;s never going to be a \u0026#34;good enough\u0026#34; because at some point, you\u0026#39;ll just have to run with it and learn while doing so. Knowing the border between research vs action is kind of an art, and it\u0026#39;s different for everyone. On top of that, knowing when to withdraw is even harder because there will always be some level of emotional attachment to your product. Hence, knowing those borders requires experience, and LivePing had taught me that in the hard way.\nIn hindsight, even though I knew all these principles from reading famous startup books, I still committed the same mistakes that people tell you not to. And because of the mistakes, I\u0026#39;ve wasted a lot of time and money which otherwise, I didn\u0026#39;t have to.\nAnother interesting aspect was that mistakes can have compounding effects on your motivation, and will put your passion to the test. Turns out, I don\u0026#39;t have as much passion as I thought I had for developer tooling after all and it was a precious insight that I would not have known unless having been put on the spot.\nEnd of Life 🌆 LivePing will be shutting down at the end of February 2020.\nAny active subscriptions will be cancelled and payments that extends beyond the end date will be refunded on a pro rata basis.\nIf you\u0026#39;re looking for alternatives for your workloads, here are some options available.\nhttps://cronitor.io/ https://healthchecks.io/ I apologies for the inconvenience, and like to thank you for trying out LivePing. One of the positives that came out of this experience was being able to experience the joy of seeing someone else using something I\u0026#39;ve built from scratch, and receiving feedback for it. It\u0026#39;s fulfilling in a different kind of way compared to having a full time job working on an established product.\nWhile there\u0026#39;s nothing specific on the pipeline for the next project, I\u0026#39;m likely not going to be working on developer tooling for business anymore, and will be looking at other industries where I\u0026#39;ve confirmed my passion.\n","date":"2020-01-18","href":"/blog/2020-01-18-shutting-down-liveping/","id":"8dd754fdd4bb311f8e767a75b65d5b60","summary":" LivePing started as a side project in early 2019.\nAt first, I was just trying to deal with the pain handling Cron tasks and offline workers, and looking into existing solutions wasn\u0026#39;t very satisfying. Building a prototype was relatively easy since the concept itself was simple.\nThe foundation of the project was done in a couple days, a couple evenings after work and BOOM! 💥 MVP completed. After that, it was just adding a small feature here and there every week or two.\n","title":"Shutting down LivePing","type":"blog"},{"content":" https://github.com/madebyoz/figma-exporter-plugin\nA Figma exporter that will rename the files to a selected convention.\nA little side project with a friend to create a file exporter for Figma.\nSupports the following file name formats:\nkebab-case snake_case camelCase Plugin is accessible from the community page.\n","date":"2020-01-01","href":"/projects/figma-exporter-plugin/","id":"af9d76420fb5114a69d572c1ccf39e7f","summary":" https://github.com/madebyoz/figma-exporter-plugin\nA Figma exporter that will rename the files to a selected convention.\nA little side project with a friend to create a file exporter for Figma.\nSupports the following file name formats:\nkebab-case snake_case camelCase Plugin is accessible from the community page.\n","title":"Figma exporter plugin","type":"projects"},{"content":" Cron, the time-based scheduler available on any modern-day operating system which runs predefined jobs, or scripts in a consistent manner. Cron is a simple but excellent piece of software that most software companies in the world rely on. But what happens when the job or script cron fails during execution…?\nSilence failure I have been working on a side project of mine and was using it for a little while. I have now made it available as a service, and it is accessible here.\nhttps://www.liveping.io/\nHome page of LivePing Cron and heartbeat monitoring for cron tasks, background workers, services, and many more. Get instant alerts with…www.liveping.io Landing page of LivePingLivePing is a heartbeat monitoring tool that helps check workloads that don\u0026#39;t accept HTTP requests, like Cron and background workloads.\nSo, what\u0026#39;s the big deal about cron anyway? There\u0026#39;s a tweet that jokes about the importance of cron in the economy, but the impact it has is no joke. While cron is something a lot of companies rely on, there is also a problem that needs consideration when operating them.\nHow do you know when they are not doing their job?\nBackground workloads like cron tended to fail silently and had led to multiple issues in the past for me:\nDatabase backups were not running External facing SSL/TLS certificates did not get updated and caused a site outage Retrained machine learning models did not get deployed Internal services went down silently (related to internal TLS), creating a cascading effect on other services Monthly email reports for customers did not get generated and sent out these were merely some of the numerous examples.\nCertain times, they might not even cause any side effects and only found out that the workloads have not been working for some extended amount of time.\nAttempts in the past I\u0026#39;ve solved this problem a couple of times in the past as an internal tool, but it always comes back to the same maintenance priority.\nSince it\u0026#39;s a monitoring system, it needs to have a decent amount of uptime, but guaranteeing that is typically not something you do single-handedly. At least, not if you\u0026#39;re the solo, or maybe one of the few members of a small SRE team when you have a thousand other things to handle and automate. Don\u0026#39;t mention unexpected incidents too.\nEven with an internal tooling team at a larger company, that team is likely to be dealing with other projects, maybe language frameworks, CI/CD pipeline, and have other responsibilities. When trying to support more visible and direct tooling for other engineers, handling of a heartbeat monitoring system tends to get de-prioritized.\nAnother problem is ownership of the system. This is not a problem while you\u0026#39;re still with the company, but it emerges likely after you left.\nDevelopers are not necessarily good writers, and there are always gaps between documentation and the running systems. I\u0026#39;m guilty of that too. So things get missed, and systems can reach critical states without being noticed after a certain amount of time.\nAnd last but not least, you get into the \u0026#34;who\u0026#39;s going to watch the watchdog\u0026#34; problem. :)\nSo you might be thinking now, \u0026#34;I can see operating as an internal tool can be burdensome for people, then why don\u0026#39;t just use Cronitor or Dead Man\u0026#39;s Snitch?\u0026#34;\nYup, I\u0026#39;ve tried those, and yes, they do fulfill the bare minimum requirements I need. But they have their own set of problems, and I might touch-base on that in the future.\nProblems LivePing solves (for now) First and foremost, LivePing solves my problem of not needing to create another monitoring system that doesn\u0026#39;t age well. And the issue of doing roughly the same thing over and over again at different places. ;)\nAlso, maybe providing something that I\u0026#39;m good at, which is reliability and scalability to a broader audience.\nEnough of my issues, let\u0026#39;s see what LivePing can do for you.\nEliminating silent failures that can lead to disastrous situations Provides alerts before problems start to snowball Preventing the issues I\u0026#39;ve listed earlier like DB backups and TLS certificate updates, etc. LivePing can also help you make sure these scheduled tasks are running and working as expected:\nData synchronization pipelines Data aggregation, garbage collection System/vulnerability scans List of pings registered Details of a monitored ping While LivePing is functional at this point with Email and Slack as alerting targets, there are still a lot of lacking features and integrations.\nSome of the stuff on the near term roadmap would be:\nPagerDuty alert integration Custom webhooks Grace period before alerting -Temporarily silencing alerts\nAPI access and documentation OAuth2 authentication and there are many more to come.\nI\u0026#39;m working hard to improve and automate the system overall to provide a high SLA uptime and a reliable system and would appreciate your feedback using it. You can find other various forms like feedback and feature request on the contact page.\nIn effects to make it accessible, LivePing comes with 5 pings for free and doesn\u0026#39;t require credit card information to sign up. Any plans going forward will have a 14 day trial period. You can see the pricing details on the pricing page.\nWhat\u0026#39;s next? In the short term, I\u0026#39;m planning to be focusing on adding features to solve problems I\u0026#39;ve encountered in the past, including scalability issues.\nBut in the long term, I want to create a system that can grow with the team\u0026#39;s needs. Initially, maybe just simple cron monitoring for the small number of jobs the company has. Then, moving up to dividing up jobs between teams, access controls, and dashboarding. Eventually, to a system that is easy to integrate into the automation of services.\nWhen it comes to the observability of systems, monitoring is just a subset of it. And monitoring uptime vs. a distributed scheduling system requires a different approach. That\u0026#39;s why even Prometheus has a push gateway.\nIf you\u0026#39;re familiar with Prometheus, which is an excellent piece of software, by all means, go with it. If not, or you don\u0026#39;t have the resources to set up such a team, give LivePing a try!\nIf you have any questions or simply just want to chat, please reach out!\nThanks for reading! :)\n","date":"2019-11-10","href":"/blog/2019-11-10-launching-liveping/","id":"cdac5d1dadfe127f55e2084b226193f1","summary":" Cron, the time-based scheduler available on any modern-day operating system which runs predefined jobs, or scripts in a consistent manner. Cron is a simple but excellent piece of software that most software companies in the world rely on. But what happens when the job or script cron fails during execution…?\nSilence failure I have been working on a side project of mine and was using it for a little while. I have now made it available as a service, and it is accessible here.\n","title":"Launching LivePing","type":"blog"},{"content":" Cron and system heartbeat monitoring system as a service.\nA project that came out of frustration to provide better monitoring for cron and background jobs.\nProject was launched in 2019-11-10 and shut down at 2020-01-18, with an incredibly short life span.\nRelated blog posts Launching LivePing Shutting down LivePing ","date":"2019-11-10","href":"/projects/liveping/","id":"91378d706abd2672ae59d7246b3cdfb6","summary":" Cron and system heartbeat monitoring system as a service.\nA project that came out of frustration to provide better monitoring for cron and background jobs.\nProject was launched in 2019-11-10 and shut down at 2020-01-18, with an incredibly short life span.\nRelated blog posts Launching LivePing Shutting down LivePing ","title":"LivePing","type":"projects"},{"content":" Web development technologies, especially front-end related ones are changing rapidly in the past few years.\nOne of the unexpected areas they have entered (personally) are the text editor space. The well known ones these days built from web technologies are Atom and Visual Studio Code.\nI consistently get questions regarding Emacs from people considering switching to it but are not sure what kind of horror stories are awaiting them so hopefully this would shed some light.\nWhat is Emacs? In case for people who are not familiar, Emacs is an editor that was released in 1976, which is around 43 years ago at the time of writing this article.\nIt’s built from Lisp and C, and is cross platform till this day. Meaning you won’t have issues running it in Apple, Linux or Windows (actually I don’t use Windows so not sure :P) devices.\nSample look of Emacs with LSP as code completion for Golang and Rust So like everything in life, there are always some kind of opportunity cost to decisions and everything is a trade-off. Here are some hopefully unbiased Pros \u0026amp; Cons if you’re considering something like Emacs.\nPros Fast\nYes, that’s right. It’s actually fast and doesn\u0026#39;t take like 16ms to render text on your bloody screen. So you can actually have a pleasant experience if you are used to doing blind touch typing and not get irritated every time when latency happens from your keystroke until when it shows up on the screen.\nIt can also be extremely fast to setup, since configurations are just dot files which makes synchronizing configurations between computers extremely easy. Download the dot file, boot up Emacs and you’re ready to go!\nWide list of plugins and support\nSince it has been around for over 40 years at this point, you can basically find a plugin for almost anything you want to do.\nProgramming language support, git operations, google search, you name it. I bet it’s actually harder to find something it can’t do.\nYou can also go pretty crazy with it, like view, compose, send emails, even browse the internet with Emacs. If you’re using the GUI version of Emacs, HTML can actually render so it’s a pretty interesting experience, literally having code and browser side by side.\nTo be honest, I figured that I just want to see text on my editor so I don’t do the those crazy things anymore. You know, A Mistake of Youth.\nKeyboard only navigation\nTo be accurate, you can still click around in Emacs, but you don’t need to. Everything can be handled with your keyboard and this actually contributes a lot to the speed of editing too. It doesn’t mean that writing fast is always good. What good is there if you produce s**t 10x faster, you know like (my) definition of a 10x engineer? But if you can express your thoughts in a shorter amount of time, why not? That small amount of time will add up and you can get hours back per day. Like literally.\nIt’s always kind of funny to hear a fellow Emacs user who have to use a different editor temporarily and complains that using a mouse just slows them down tremendously.\nNo offense to anyone who uses a mouse, it just feels very weird to have to use one when you got use to handle everything with your keyboard. It’s like, “wait, where is my hand supposed to go now?” and have to pause for a few seconds deciding on your hands’ next move.\nOh and it also makes file editing in servers easier too.\nMultiple files in one screen\nThis is actually unique to Emacs (and Vim) where each file is a buffer and the concept of a frame and buffer is different so you can have a loooooooot of buffers in one frame.\nThis work very well if you have a very short memory span. Like literally have your memory wiped while switching screens and you have no idea what you were supposed to be looking at so you switch back to the previous screen, repeating this back and forth like I don’t know how many times wasting hours just trying to figure out what you were thinking about 2 seconds ago.\nAt a bare minimum, I will always have 3 files opened and sometimes more than 8. I get the same comment from all my past and present colleagues when they walk pass my desk.\n“I have no f***ing idea how you even operate with that.”\nCons High learning curve\nI’m pretty sure this is one of the common reasons that bars people from using the tool. Emacs Lisp, while it’s extremely flexible and fast (compiles to byte code), it has a syntax a lot of people are not used to.\nDefault key strokes in Emacs can be awkward at first as well. For example, saving a file is Ctrl-x Ctrl-s. That’s 2 key strokes and seems more effort for a lot of people when you’re used to just doing Ctrl-s or Cmd-s for saving a file.\nIf you’re willing to stick with it, you’ll be amazed how fast it’ll become going through all those weird key stroke combinations thanks to muscle memory, but your productivity will definitely slow down for some amount of time until that memory sticks.\nExtreme customization\nRelated to the key stroke combination above, some crazy people (like me) go extra steps to customize Emacs to fit their needs. This is one of the double edged sword characters of Emacs, because it makes pairing soooooooooo much more painful. You can hardly pair with even a fellow Emacs user, since it will feel like you’ve suddenly entered a different universe.\nBut hey, I don’t work at Pivotal, therefore I don’t pair 100% of the time so it should be fine right?\nDocumentation\nIf it has been around for such a long time, wouldn’t there be plenty of documentations?\nYes, there are tons of them. But also a lot of them are outdated so there could be struggles when you try to do something following the documentation you found online and it completely blows up on your face.\nPackage repositories are also kind of scattered around both up to date and outdated so you might need to connect to all of them in order to get the package you want. Looks like people are finally deciding on a single source of truth these days so hopefully life will be easier when you are just trying to install a plugin to test it out.\nSome distributions like Spacemacs can help by providing a layer of abstraction so you don’t need to handle all the details yourself. It also provides a nice set of defaults, but if you’re the kind of person that wants to know what each of you configurations does… oh well, you have been warned.\nWhy Emacs So, should you switch to Emacs?\nTo be honest, you don’t need to. Like I said earlier, everything is a trade-off. So if you’re the kind of person who don’t care about the tool and want it to just work, then VSCode, Atom or Sublime is a better fit for you.\nIf you’re the kind of person who cares more about performance and don’t mind investing a little time to get that, then I think Emacs is a great editor, even after 40+ years since its creation.\nHow about Vim? Pros and cons wise, Vim is pretty much the same. I was initially a Vim user, but had to switch to Emacs for performance reasons when editing large files x amount of years ago.\nTo provide a little more context before I get backslash from enthusiastic vim users.\nBack at the time when I decided to switch to Emacs, I was doing\nLinting Code completion Auto code format after save on all opened files. Vim wasn’t able to do async operations back then so whenever I opened a giant file, it takes like 5 seconds for my typing to show up on the screen, and I think everyone will agree that 5 seconds is unbearable. I’m complaining with 16ms so you can tell that I was tearing my hair out with that amount of latency. But I didn’t want to disable all those settings so I decided to give Emacs a try since I heard it compiles to byte code and I thought I would be able to keep the best of both worlds.\nBeing lazy with code and have it render fast on the screen.\nAnd as expected, it worked great ever since! Vim and the newer rewrite NeoVim both have async APIs now so you shouldn’t encounter the issue I had anymore.\nIf you’re considering Vim, definitely give it a go. I still uses Vim as my sub editor for quick edits, because to be honest, it actually loads way faster than Emacs but I just don’t have the motivation to maintain 2 configurations.\nThe next cool kid? editor? around the block I’ve been tracking the Xi editor for a while now. The design philosophy is something I like a lot, and it looks like it a Emacs/Vim rebuilt with modern technologies, also learning from past lessons.\nUnfortunately, it is not ready for a day to day work level yet, so if you are interested in a performant text editor, give Emacs a try for now.\nI personally think it’s worth the investment but I would like to know what you think about it too!\n","date":"2019-06-21","href":"/blog/2019-06-21-being-an-emacs-user-in-2019/","id":"21e9199a28fd89efec90fca5d126f162","summary":" Web development technologies, especially front-end related ones are changing rapidly in the past few years.\nOne of the unexpected areas they have entered (personally) are the text editor space. The well known ones these days built from web technologies are Atom and Visual Studio Code.\nI consistently get questions regarding Emacs from people considering switching to it but are not sure what kind of horror stories are awaiting them so hopefully this would shed some light.\n","title":"Being An Emacs User In 2019","type":"blog"},{"content":" https://github.com/sous-chefs/pyenv\nA Chef cookbook to manage pyenv installations.\nTaken over ownership from Shane in 2017 and refactored the cookbook.\nTransferred ownerhsip of the codebase to the sous-chef organization in 2020.\n","date":"2017-01-01","href":"/projects/chef-pyenv/","id":"a61d1bf78baad5be68f2576c8b8c84a7","summary":" https://github.com/sous-chefs/pyenv\nA Chef cookbook to manage pyenv installations.\nTaken over ownership from Shane in 2017 and refactored the cookbook.\nTransferred ownerhsip of the codebase to the sous-chef organization in 2020.\n","title":"Chef pyenv","type":"projects"},{"content":" I’m a technologist based in the Bay Area.\nMajored Political Science and Economics but have felt in love with software since my senior year and have made the jump into this world and never look back ever since.\nI’ve worked from small early stage startups to large IPO companies, both as a senior level IC and engineering leader.\nThis site Is mostly my brain dump on things related to Technology and Software Engineering.\nFormat can in the form of blog, notes. Content will be mostly in tech, operations, management and business.\nContact I do consultancy and technical advisor every once in a while. If you like to get some help, feel free to reach out via hey@dwu.sh.\nSocials GitHub LinkedIn Bluesky Goodreads ","date":"0001-01-01","href":"/about/","id":"e1f88686b8ff232351bfe29b8e212959","summary":" I’m a technologist based in the Bay Area.\nMajored Political Science and Economics but have felt in love with software since my senior year and have made the jump into this world and never look back ever since.\nI’ve worked from small early stage startups to large IPO companies, both as a senior level IC and engineering leader.\nThis site Is mostly my brain dump on things related to Technology and Software Engineering.\n","title":"About","type":"page"}]