[{"content":"I come from the Ruby on Rails world and the latest popular tool in that community is Kamal. Kamal is a useful tool to quickly deploy a Rails application to a server and manage other deployed services through what Kamal calls \u0026ldquo;accessories.\u0026rdquo;\nAt my day job, I was tasked with building a small internal tool application using any framework I preferred, followed by deploying it to a suitable environment. I decided to use Tanstack Start and to run it on a plain old VPS. There are probably better hosting solutions, but due to the nature of the application, a VPS was perfectly sufficient. Since that was the case, I decided to go ahead and just use Kamal to manage deployments and make it easy for anyone else working on the application to do deploy as well.\nSo here is a small guide on deploying a Tanstack Start application with Kamal.\nTanstack Start Tanstack Start is a new full-stack javascript framework written by Tanner Linsley. I plan to write a longer overview of it at some point in the near future. It\u0026rsquo;s definitely my top choice among the available React based frameworks on the market right now. As of this writing, Tanstack Start is in Beta status until they finish an underlying tooling migration at which point, they\u0026rsquo;ll release V1.\nKamal Overview The main goal of Kamal is to streamline deployments into a simple, straightforward workflow.\nBuild a Docker image Push the image to a registry SSH into a server and pull down the image Spin up the image on the server Use Kamal-proxy to switch port mapping between old and new images, ensuring \u0026ldquo;0 down time deployments\u0026rdquo; Shutdown the old image once health checks on the new image pass All this can be run really simply on any machine as long as it has SSH access to the server.\nThe Stack Tanstack Start Drizzle ORM SQLite PNPM Tanstack Start Configuration There are 3 small tasks that need to be done in the Tanstack Start application to ensure everything works. First, if you\u0026rsquo;re using Drizzle ORM, create a script in package.json to run migrations:\n${PROJECT_ROOT}/package.json\n{ // ... \u0026#34;scripts\u0026#34;: { // ... \u0026#34;migrate\u0026#34;: \u0026#34;npx drizzle-kit migrate\u0026#34; // ... } // ... } Keep in mind you\u0026rsquo;ll need drizzle-kit as a regular dependency, not a devDependency. This is so we can easily run migrations everytime we deploy. Next, configure Vinxi through Tanstack Start\u0026rsquo;s app.config.js, specifying the node-server preset to ensure optimization for a plain Node runtime rather than a platform like Cloudflare Workers.\n${PROJECT_ROOT}/app.config.js\nexport default defineConfig({ // ... server: { preset: \u0026#39;node-server\u0026#39;, }, }) With that done we can test our build by just running pnpm run build (if you\u0026rsquo;ve followed the setup tutorial from the Tanstack Start documentation otherwise just use whatever build command you have.) By default, the assets are all placed in the .output directory and the main entrypoint to the application is .output/server/index.mjs. The application can be started with node .output/server/index.mjs in order to confirm everything is working as expected.\nNow the final thing we need is a health check endpoint for Kamal Proxy to use in order to confirm the application is running. You can place this file wherever you\u0026rsquo;d prefer as long as it\u0026rsquo;s an APIRoute\u0026ndash; I chose src/routes/api/up.ts. This location is configurable through Kamal\u0026rsquo;s proxy settings. All this endpoint needs to do is return a 200 status code to a GET request. Here\u0026rsquo;s what that looks like:\n${PROJECT_ROOT}/src/routes/api/up.ts\nimport { createAPIFileRoute } from \u0026#34;@tanstack/react-start/api\u0026#34; export const APIRoute = createAPIFileRoute(\u0026#39;/api/up\u0026#39;)({ GET: () =\u0026gt; { return new Response() }, }) Now on to Docker.\nDocker Entrypoint The entrypoint is a simple script that will run migrations and start the application everytime the Docker container is started. Here\u0026rsquo;s what it looks like:\n${PROJECT_ROOT}/docker-entrypoint.sh\n#!/bin/sh npm run db:migrate node .output/server/index.mjs Ensure this script has executable permissions by running chmod +x docker-entrypoint.sh. You can also add additional startup commands here if necessary.\nDocker Image Here are a few notables to include in the Dockerfile:\nnode:20-slim will be the base image Cache dependencies via pnpm so builds are faster A volume is required in order to have persistent data across deployments We need to set the environment variables for the application We need to ensure that any and all migrations for Drizzle ORM and our database are automatically run before the app spins up ${PROJECT_ROOT}/Dockerfile\n# Base image FROM node:20-slim AS base # Install \u0026amp; setup pnpm ENV PNPM_HOME=\u0026#34;/pnpm\u0026#34; ENV PATH=\u0026#34;$PNPM_HOME:$PATH\u0026#34; ENV NODE_ENV=production ENV DB_FILE_NAME=file:\u0026lt;DATABASE_NAME\u0026gt; RUN corepack enable RUN mkdir /app RUN mkdir /app/data \u0026amp;\u0026amp; chmod 777 /app/data VOLUME /app/data COPY . /app WORKDIR /app # Install dependencies with a cache entry FROM base AS prod-deps RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile # Build the application FROM base AS build RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile RUN pnpm run build # Copy deps and build output into main container FROM base COPY --from=prod-deps /app/node_modules /app/node_modules COPY --from=build /app/.output /app/.output # Entrypoint execution permissions RUN chmod +x /app/docker-entrypoint.sh # Expose our port EXPOSE 3000 # Start the server CMD [\u0026#34;/app/docker-entrypoint.sh\u0026#34;] Add a simple .dockerignore to ensure there are no file conflicts/overrides happening and that private files aren\u0026rsquo;t copied into the container.\n${PROJECT_ROOT}/.dockerignore\n# Version control .git .gitignore .github # Node.js node_modules npm-debug.log yarn-debug.log yarn-error.log .pnpm-debug.log # db \u0026lt;DEV_DB\u0026gt; # Build outputs dist .output .nuxt .next .cache # Environment variables .env .env.* !.env.example # OS generated files .DS_Store Thumbs.db # Testing coverage # Logs logs *.log # Temporary files tmp temp Kamal Configuration The required Kamal configuration is relatively minimal since there aren\u0026rsquo;t any accessories and a private network isn\u0026rsquo;t being used. You can see my previous post if you\u0026rsquo;re curious about slightly a more complex configuration. Start things off by running kamal init to create the boilerplate files required by Kamal.\n${PROJECT_ROOT}/config/deploy.yml\n# Name of your application. Used to uniquely configure containers. service: \u0026lt;SERVICE_NAME\u0026gt; # Name of the container image. image: \u0026lt;IMAGE_NAME\u0026gt; # Deploy to these servers. servers: web: - \u0026lt;VPS_IP\u0026gt; proxy: ssl: true host: \u0026lt;DOMAIN\u0026gt; app_port: 3000 # Must match what\u0026#39;s exposed via the Dockerfile healthcheck: path: /api/up # Change this to match your healthcheck endpoint (optional) # Credentials for your image host. registry: password: - KAMAL_REGISTRY_PASSWORD # Configure builder setup. builder: arch: amd64 # Inject ENV variables into containers (secrets come from .kamal/secrets). env: clear: DB_FILE_NAME: file:/app/data/\u0026lt;DATABASE_NAME\u0026gt; secret: - RANDOM_SECRET ssh: config: true # Uses your `~/.ssh/config` file user: \u0026lt;SSH_USER\u0026gt; # The user you use to SSH into your VPS if not `root` Most services rely on additional secrets that need to be set in the environment. Kamal Secrets is the default tool to handle this for Kamal.\nWith all that done you can now deploy your application by running kamal setup. This will SSH into the VPS, install Docker and Kamal Proxy, and begin the process of the first deploy.\nA Gotcha (maybe) - permission denied error Kamal assumes that whatever credentials you use to SSH into the server log you in as the root user. This is very strange, especially considering you can change your user in the Kamal config to tell Kamal to use a different user when connecting. If it\u0026rsquo;s the case that your user is not the root user, you may run into an issue where the Docker daemon cannot be accessed. This will present itself as a permission denied error when trying to access the docker.socket. It completly prevents Kamal from spinning up the container.\nIn order to fix this you\u0026rsquo;ll need sudo privileges and you simply have to add the user to the docker group. This can be done by running the following command on the server:\nsudo usermod -aG docker \u0026lt;SSH_USER\u0026gt; Be aware that adding your user to the docker group effectively grants root-level permissions. Therefore, it\u0026rsquo;s critical to implement robust access controls and security measures to protect your environment.\nOnce completed, re-run kamal setup, on your local machine and the deployment should fire off without a hitch.\nThat\u0026rsquo;s it! Happy coding.\nLinks Kamal Kamal Secrets Tanstack Start Drizzle ORM SQLite PNPM My previous post using a private network with Kamal ","permalink":"https://jd.codes/posts/deploy-tanstack-start-kamal/","summary":"\u003cp\u003eI come from the Ruby on Rails world and the latest popular tool in that community is \u003ca href=\"https://kamal-deploy.org/\"\u003eKamal\u003c/a\u003e. Kamal is a useful tool to quickly deploy a Rails application to a server and manage other deployed services through what Kamal calls \u0026ldquo;accessories.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eAt my day job, I was tasked with building a small internal tool application using any framework I preferred, followed by deploying it to a suitable environment. I decided to use Tanstack Start and to run it on a plain old VPS. There are probably better hosting solutions, but due to the nature of the application, a VPS was perfectly sufficient. Since that was the case, I decided to go ahead and just use Kamal to manage deployments and make it easy for anyone else working on the application to do deploy as well.\u003c/p\u003e","title":"Deploying Tanstack Start w/ Kamal"},{"content":"Edit: In the original version of this post I made a mistake. This post has been corrected. See the details at the below for an explanation of the mistake and the solution.\nMistake Summary \u0026amp; Solution In the original version of this post I had stated that the App servers IP in the Kamal configuration should be set to it\u0026rsquo;s public IP. This is incorrect. With the SSH proxy pointing at the public IP as well, this resulted in a jumphost connection problem, meaning it tried to connect to the public IP through a proxy of the public IP. This obviously didn\u0026rsquo;t work and resulted in inconsistent behavior with Kamal. The solution was to replace the App servers IP address to be the private IP instead. As a result, the only place the public IP of the server is referenced is in the Kamal SSH proxy configuration.\nUpdated Post I recently started a small side project and decided to use Rails 8 and Kamal. I\u0026rsquo;ve jumped on the #nobuild bandwagon (at least for this project) and thought I\u0026rsquo;d share a tip for all you non-dev-ops folks like me. I\u0026rsquo;m very new to the world of dev-ops and don\u0026rsquo;t know or understand much by instinct yet so this may end up being something very obvious for some folks. Hopefully someone in my position finds this useful.\n⚠️ Disclaimer ⚠️: I am not a security expert by any means and I implement this in a pretty naive way so please do your own research before committing to using this approach in a production application with any kind of customer data.\nCloud Resources Like the rest of the Rails community, I went with Hetzner for the time being because it\u0026rsquo;s so cheap and easy to use. I configured 5 total resources so far:\nApp Server DB Server Private Network 2 Firewalls (rules) Private Network \u0026amp; Firewall I set up a private network resource to which I added the App and DB server. This allowed me to ensure that the 2 servers have a private communication channel that is inaccessible from the outside world. I set the IP subnet range to whatever arbitrary values I could easily remember and then allowed Hetzner to auto-assign IPs in that subnet to the servers when they were added to the network. For this example, I\u0026rsquo;ll use 11.0.0.10 for the app server and 11.0.0.11 for the db server.\nNote: The private network IP is different than the public IP of your server.\nNote: Keep in mind these are explicit allow rules which means \u0026ldquo;only X behavior is allowed.\u0026rdquo;\nApp Server Firewall Rules Now that both resources could communicate via the private network, I decided to setup the first firewall to block off unnecessary ports on the App server.\nInbound Rules Allow traffic via TCP on port 443 (HTTPS) Allow traffic via TCP on port 80 (HTTP) Allow traffic from my personal IPs via TCP on port 22 (SSH) The SSH port was configured to only allow a specific set of IPs so only my personal known IPs could SSH into the server. I think setting up a VPN is the most flexible/secure approach but I didn\u0026rsquo;t go that far as this is just a small personal project.\nDB Server Firewall Rules The DB server firewall received a much stricter set of rules.\nInbound Rules Allow traffic from 11.0.0.0/24 subnet via TCP on any port Allow traffic from 11.0.0.0/24 subnet via ICMP any port Allow traffic from 11.0.0.0/24 subnet via UDP any port This setup ensures that any and all external traffic is blocked by the firewall. I can\u0026rsquo;t even SSH into the DB server at the moment. I could lock this down even more by providing the specific subnet IP of the App server instead of using that entire subnet range but I don\u0026rsquo;t think that\u0026rsquo;s necessary.\nNow that we have those (non-comprehensive) basics out of the way we\u0026rsquo;ll talk about Kamal configuration.\nKamal Setup I\u0026rsquo;m positive something isn\u0026rsquo;t entirely set up properly here, but it all seems to work okay for me. You need to make sure that your Rails config/database.yml production configuration looks for the DB_HOST environment variable to set the host for the connection, otherwise copying my configuration directly won\u0026rsquo;t work. I\u0026rsquo;m also using SolidQueue \u0026amp; SolidCache, both of which are just running on my App server.\ndeploy.yml # Used .env file to get spun up quickly. DON\u0026#39;T COMMIT SECRETS \u0026lt;% require \u0026#34;dotenv\u0026#34;; Dotenv.load(\u0026#34;.env\u0026#34;) %\u0026gt; service: my-app image: docker-username/my-app servers: web: - 11.0.0.10 # Use App Server private network IP job: hosts: - 11.0.0.10 # Same as App Server private network IP cmd: bin/jobs proxy: ssl: true host: my-app.com registry: server: registry.hub.docker.com # replace with your registry username: docker-username password: - KAMAL_REGISTRY_PASSWORD env: secret: - RAILS_MASTER_KEY - POSTGRES_PASSWORD clear: DB_HOST: 11.0.0.11 # Private network IP for DB server. This is important! POSTGRES_USER: db-user # replace with real value, rails defaults it to the project name POSTGRES_DB: my_app_production # same as POSTGRES_USER JOB_CONCURRENCY: 3 SOLID_QUEUE_IN_PUMA: true RAILS_MAX_THREADS: 5 aliases: console: app exec --interactive --reuse \u0026#34;bin/rails console\u0026#34; shell: app exec --interactive --reuse \u0026#34;bash\u0026#34; logs: app logs -f dbc: app exec --interactive --reuse \u0026#34;bin/rails dbconsole\u0026#34; volumes: - \u0026#34;my_app_storage:/rails/storage\u0026#34; asset_path: /rails/public/assets builder: arch: amd64 # This is important! See below ssh: proxy: root@1.1.1.1 # Replace with App Server public IP accessories: db: image: postgres:15 host: 11.0.0.11 # Private network IP for DB server. port: \u0026#34;5432:5432\u0026#34; env: clear: DB_HOST: my-app-db POSTGRES_USER: db-user # replace with real value POSTGRES_DB: my_app_production # replace with real value secret: - POSTGRES_PASSWORD directories: - data:/var/lib/postgresql/data Explain The setup is pretty predictable as far as Kamal configurations go as I\u0026rsquo;m not doing anything fancy. The biggest gotcha here is that at no point in the config am I referencing the DB server\u0026rsquo;s public IP address. Lets look at the ssh configuration to see how and why:\nssh: proxy: root@1.1.1.1 # Replace with App Server public IP This tells Kamal to use the App server as an SSH proxy to all the resources, and since our machines have SSH access to the App server already, Kamal can connect to resources on the private network we setup because the App server is a member of that private network. If you\u0026rsquo;re not 100% following, here\u0026rsquo;s a rundown \u0026hellip;\nSince the public IP of the server is what Kamal needs to establish an SSH connection, proxy all SSH traffic through the public IP of App server. All SSH traffic from Kamal happens by Kamal establishing an SSH connection to the App server first then connecting to the App Server (again sort of) via it\u0026rsquo;s internal network IP Since we have access to the internal network through the proxy, we can also access the DB accessory on the internal network as well So Kamal uses SSH through the App server public IP (as an SSH proxy) to manage the all the relevant services on the network The docs about configuring an SSH proxy are here. Unfortunately they aren\u0026rsquo;t entirely clear if you don\u0026rsquo;t already know what things like this command ssh -W %h:%p user@proxy-ip do, which I didn\u0026rsquo;t when I started working on this configuration.\nAdditional Resources This post was geared mostly towards people still learning this stuff and want to use Kamal. Here\u0026rsquo;s some additional resources that helped me out a lot while I was configuring everything:\nKamal Documentation is useful, but it could be improved quite a lot Josef Strzibnys Blog Josef also authored Kamal Handbook - The Missing Manual which was mentioned postively by a lot of folks on various threads I saw about Kamal. I\u0026rsquo;ll likely pick it up myself in my next round of book buys. Sam Johnsons Adding Postgres \u0026amp; Redis to Kamal Video He demonstrates using Kamal v1, it was still really helpful to me to see someone configure everything from scratch. ","permalink":"https://jd.codes/posts/kamal-tip-private-network/","summary":"\u003cp\u003e\u003cstrong\u003e\u003cstrong\u003eEdit\u003c/strong\u003e\u003c/strong\u003e: In the original version of this post I made a mistake. This post has been corrected. See the details at the below for an explanation of the mistake and the solution.\u003c/p\u003e\n\u003cdetails\u003e\n\u003csummary\u003eMistake Summary \u0026amp; Solution\u003c/summary\u003e\n\u003cdiv class=\"details\"\u003e\n\u003cblockquote\u003e\n\u003cp\u003eIn the original version of this post I had stated that the App servers IP in the Kamal configuration should be set to it\u0026rsquo;s public IP. This is incorrect. With the SSH proxy pointing at the public IP as well, this resulted in a jumphost connection problem, meaning it tried to connect to the public IP through a proxy of the public IP. This obviously didn\u0026rsquo;t work and resulted in inconsistent behavior with Kamal. The solution was to replace the App servers IP address to be the private IP instead. As a result, the only place the public IP of the server is referenced is in the Kamal SSH proxy configuration.\u003c/p\u003e","title":"Kamal Tip - Private Network only Database Server"},{"content":"Magit is an innovative package that provides an amazing interface over git. The complexity of its UI is completely hidden away thanks to another package born out of Magit called Transient. Transient is so innovative that it was added to emacs core in 2021. Understanding at least the basics of Transient can provide alot of value in building tools to enhance various workflows.\nFrom the official manual\nTransient is the library used to implement the keyboard-driven “menus” in Magit. It is distributed as a separate package, so that it can be used to implement similar menus in other packages.\nFrom Transient Showcase\nTransient means temporary. Transient gets its name from the temporary keymap and the popup UI for displaying that keymap.\nFoundation A Transient menu is made of up of 3 parts: prefix, suffix and infix.\nPrefix: represents a command to \u0026ldquo;open\u0026rdquo; a transient menu. For example magit-status is a prefix which will initialize and open the magit-status buffer.\nSuffix: represents the \u0026ldquo;output\u0026rdquo; command. This is whats invoked inside of a transient menu to perform some kind of operation. For example in magit calling magit-switch-branch is a suffix which has a (completing-read) in front of it.\nInfix: represent the \u0026ldquo;arguments\u0026rdquo; or the intermediary state of a transient. For example, adding -f, --force-with-lease means you\u0026rsquo;re using an infix for the magit-push suffix.\nThere are 2 additional things to understand about transients:\nSuffixes can call prefixes allowing for \u0026ldquo;nesting\u0026rdquo; of \u0026ldquo;menus.\u0026rdquo; In magit when a commit is at point and you call magit-diff that is a suffix that is a really just a prefix with it\u0026rsquo;s own set of infixes and suffixes. See Example 3 below for a more elaborate example of this. Think of it this way: Prefix -\u0026gt; Suffix -\u0026gt; Prefix -\u0026gt; ... State can be persisted between Suffixes and Prefixes to build very robust UIs that engage in very complex behavior while exposing a simple view to the user. Note: I don\u0026rsquo;t go over state persisting through prefixes in the post. I do plan on doing a follow up for more complex situations as I continue to learn.\nDefine While the actual model is much more complex than I\u0026rsquo;ve lead on and has many more domain concepts to understand than I\u0026rsquo;m going to layout, defining simple transients can enhance your workflow in meaningful ways once you at least understand the basics. This is by no means a comprehensive guide on Transients but merely a (hopefully) educational and useful overview. For an incredible guide, checkout positron-solutions Transient Showcase which is one of the most thorough guides I\u0026rsquo;ve ever seen. If any information I share here is different in Positrons guide, trust Positron.\nNote: Each of the Examples work and can be evaluated inside of Emacs and I encourage you to do so!\n1 Prefix ➡️ 1 Suffix Lets define a simple transient to just output a message.\n(transient-define-prefix my/transient () \u0026#34;My Transient\u0026#34; [\u0026#34;Commands\u0026#34; (\u0026#34;m\u0026#34; \u0026#34;message\u0026#34; my/message-from-transient)]) (defun my/message-from-transient () \u0026#34;Just a quick testing function.\u0026#34; (interactive) (message \u0026#34;Hello Transient!\u0026#34;)) Once evaluated, M-x my/transient can be invoked and a transient opens with one suffix command m which maps to my/message-from-transient and outputs a message to the minibuffer.\nExplain transient-define-prefix is a macro used to define a simple prefix and create everything Transient needs to operate. The body is where we define our Transient keymap, which in this case is called \u0026quot;Commands\u0026quot;. The body can define multiple sets of keymaps and each one should be defined as a vector where the first element is the \u0026ldquo;name\u0026rdquo; or \u0026ldquo;title display\u0026rdquo; of the current set of commands, and the subsequent N number of lists make up the whole map. The lists are in the format of (but not limited to) (KEY DESCRIPTION FUNCTION). The FUNCTION arg must be interactive in order to work.\nThere are a handful of other ways to define the Transient elements, but we\u0026rsquo;ll stick with this simple version. If you\u0026rsquo;re interested in more complex methods refer back to Positrons guide.\nLets expand our example a bit by adding arguments and switches.\n1 Prefix ➕ 2 Infix ➡️ 1 Suffix Here we will add 2 types of arguments: switches and arguments with a readable value.\n(transient-define-prefix my/transient () \u0026#34;My Transient\u0026#34; [\u0026#34;Arguments \u0026amp; Switches\u0026#34; (\u0026#34;-s\u0026#34; \u0026#34;Switch\u0026#34; \u0026#34;--switch\u0026#34;) (\u0026#34;-n\u0026#34; \u0026#34;Name Argument\u0026#34; \u0026#34;--name=\u0026#34;)] [\u0026#34;Commands\u0026#34; (\u0026#34;m\u0026#34; \u0026#34;message\u0026#34; my/message-from-transient)]) (defun my/message-from-transient (\u0026amp;optional args) \u0026#34;Just a quick testing function.\u0026#34; (interactive (list (transient-args transient-current-command))) (if (transient-arg-value \u0026#34;--switch\u0026#34; args) (message (concat \u0026#34;Hello: \u0026#34; (transient-arg-value \u0026#34;--name=\u0026#34; args))))) Now we have a transient that gives us 2 infixes or \u0026ldquo;arguments\u0026rdquo;.\n-s is the keymapped function to toggle the --switch argument. A good example of this is a terminal command like ls -a where -a is a boolean type value that toggles all on for ls. -n is the keymapped function to prompt for a minibuffer input to enter in what\u0026rsquo;s appended to the --name= argument. Once evaluated we can now run the transient with M-x my/transient and then press - followed by s to toggle the --switch switch argument. Pressing - followed by n will engage the --name= argument which will generate a minibuffer prompt to read user input. Once a name is typed in and Enter is pressed the minibuffer prompt will finish and the value entered will be displayed in the Transient menu itself. Pressing m will run the suffix. With --switch toggled on a message should appear in the minibuffer: \u0026ldquo;Hello: \u0026quot; followed by the input to --name=. Performing the flow with --switch toggled off results in nothing being displayed.\nExplain The suffix changes on my/message-from-transient are minimal but very important. We need to make sure that it can interactively take args which are passed in by our Transient when the suffix is executed. This is a list of the values of our infixes from our prefix. We can then use the helper function transient-arg-value which has the following docstring:\nFor a switch return a boolean. For an option return the value as a string, using the empty string for the empty value, or nil if the option does not appear in ARGS.\nSo when we do (if (transient-arg-value \u0026quot;--switch\u0026quot; args) ...) that gets cast into a boolean for us to use. We could pass it directly into something as well without having to cast it ourselves or rely on elisp to do it. It also gives us the value of --name= as a string so we can just pass it into (message). There\u0026rsquo;s some more flexibility with argument passing we\u0026rsquo;ll get into in a further example.\nThe shorthand we\u0026rsquo;re using to define infixes makes it easy to define these two types, a switch and arguments.\n1 Prefix ➕ 2 Infix ➡️ 1 Suffix ➡️ 1 Prefix Lets expand our example by demonstrating the composability of transient menus. We\u0026rsquo;ll perform essentially the same example as before but instead of just triggering a (message ...) function, our suffix will instead point to a prefix, based on the infix arguments.\n(transient-define-prefix my/transient () \u0026#34;My Transient\u0026#34; [\u0026#34;Arguments \u0026amp; Switches\u0026#34; (\u0026#34;-s\u0026#34; \u0026#34;Switch\u0026#34; \u0026#34;--switch\u0026#34;) (\u0026#34;-n\u0026#34; \u0026#34;Name Argument\u0026#34; \u0026#34;--name=\u0026#34;)] [\u0026#34;Commands\u0026#34; (\u0026#34;m\u0026#34; \u0026#34;message\u0026#34; my/message-from-transient) (\u0026#34;c\u0026#34; \u0026#34;go to composed\u0026#34; my/composed-transient)]) (defun my/message-from-transient (\u0026amp;optional args) \u0026#34;Just a quick testing function.\u0026#34; (interactive (list (transient-args transient-current-command))) (if (transient-arg-value \u0026#34;--switch\u0026#34; args) (message (concat \u0026#34;Hello: \u0026#34; (transient-arg-value \u0026#34;--name=\u0026#34; args))))) (transient-define-prefix my/composed-transient () \u0026#34;My Composed Transient\u0026#34; [\u0026#34;Arguments \u0026amp; Switches\u0026#34; (\u0026#34;-l\u0026#34; \u0026#34;Loop\u0026#34; \u0026#34;--loop\u0026#34;)] [\u0026#34;Commands\u0026#34; (\u0026#34;x\u0026#34; \u0026#34;Execute\u0026#34; my/composed-suffix)]) (defun my/composed-suffix (\u0026amp;optional args) (interactive (list (transient-args transient-current-command))) (if (transient-arg-value \u0026#34;--loop\u0026#34; args) (my/transient))) Now we have a transient that provides 2 infixes as before, but now has another suffix that is in fact a prefix, a \u0026ldquo;sub-menu\u0026rdquo;! Then it uses an infix to determine the subsequent action when the suffix is called. If the --loop argument is set to true, we then loop back to our original prefix as this commands suffix.\nExplain Here we simply expand on everything we\u0026rsquo;ve learned up to this point and simply call a prefix as a suffix. This demonstrates the composability of transients in that we created a \u0026ldquo;sub menu\u0026rdquo; for our main transient. The example isn\u0026rsquo;t truly relying on the infixes to determine the second suffix/prefix behavior but that\u0026rsquo;s for a subsequent post. Refer to the resources listed below for more information on that. The concept here is important to grasp as it\u0026rsquo;s the foundation for building complex structured menus with transient.\nReal World The usefulness of creating your own transients goes far beyond just developing packages. At my day job I use a transient menu to run our test suite. While I\u0026rsquo;m not a fan of how our test suite is setup, I wanted to make it as painless to interact with as possible.\nOverview I work on a Ruby on Rails application that utilizes Minitest. In the command line you can normally run the following bin/rails test path/to/test.rb and the suite will run. You can also optionally provide a line number to run a specific test instead of a whole file like bin/rails test path/to/test.rb:50. While there is a litany of ways to improve this experience with tools like FZF, I don\u0026rsquo;t want to break my flow by switching windows.\nUnfortunately,we also use environment variables that dictate additional behavior for our test suite such as providing specific database seeds, or running selenium on a headless browser live so you can debug end to end tests. While there are better ways to manage complex test suites, I\u0026rsquo;ll make do with it and let emacs handle the annoying stuff.\nAt the end of it all, I end up with a test command that looks like: SKIP_SEEDS=true MAGIC_TEST=0 PRECOMPILE_ASSETS=false rails test path/to/test.rb. Typing that sucks, and setting them by default in my shell doesn\u0026rsquo;t do much because they change so often in my normal work. So I wrote a transient menu to make things easy for me.\nCommander.el I named it commander.el even though it\u0026rsquo;s not a package I\u0026rsquo;m providing publicly. It\u0026rsquo;s just for me and I wanted a cool name to keep it separate from my normal configuration files.\n(transient-define-prefix jd/commander () \u0026#34;Transient for running Rails tests in CF2.\u0026#34; [\u0026#34;Testing Arguments\u0026#34; (\u0026#34;s\u0026#34; \u0026#34;Skip Seeds\u0026#34; \u0026#34;SKIP_SEEDS=\u0026#34; :always-read t :allow-empty nil :choices (\u0026#34;true\u0026#34; \u0026#34;false\u0026#34;) :init-value (lambda (obj) (oset obj value \u0026#34;true\u0026#34;))) (\u0026#34;a\u0026#34; \u0026#34;Precompile Assets\u0026#34; \u0026#34;PRECOMPILE_ASSETS=\u0026#34; :always-read t :allow-empty nil :choices (\u0026#34;true\u0026#34; \u0026#34;false\u0026#34;) :init-value (lambda (obj) (oset obj value \u0026#34;false\u0026#34;))) (\u0026#34;c\u0026#34; \u0026#34;Retry Count\u0026#34; \u0026#34;RETRY_COUNT=\u0026#34; :always-read t :allow-empty nil :init-value (lambda (obj) (oset obj value \u0026#34;0\u0026#34;))) (\u0026#34;-m\u0026#34; \u0026#34;Magic Test\u0026#34; \u0026#34;MAGIC_TEST=1\u0026#34;)] [\u0026#34;Testing\u0026#34; (\u0026#34;t\u0026#34; \u0026#34;Run Test\u0026#34; commander--run-current-file) (\u0026#34;p\u0026#34; \u0026#34;Run Test at Point\u0026#34; commander--run-command-at-point) (\u0026#34;f\u0026#34; \u0026#34;Find test and run\u0026#34; commander--find-test-and-run)] [\u0026#34;Commands\u0026#34; (\u0026#34;d\u0026#34; \u0026#34;Make dev-sync\u0026#34; commander--dev-sync) (\u0026#34;r\u0026#34; \u0026#34;Rails\u0026#34; jd/rails-commander)]) ;; ... (defun commander--run-current-file (\u0026amp;optional args) \u0026#34;Suffix for using current buffer-file-name as relevant test file.\u0026#34; (interactive (list (transient-args \u0026#39;jd/commander))) (commander--run-command (concat (mapconcat #\u0026#39;identity args \u0026#34; \u0026#34;) (commander--test-cmd (commander--current-file))))) (defun commander--find-test-and-run (\u0026amp;optional args) \u0026#34;Suffix for using completing-read to locate relevant test file.\u0026#34; (interactive (list (transient-args \u0026#39;jd/commander))) (commander--run-command (concat (mapconcat #\u0026#39;identity args \u0026#34; \u0026#34;) (commander--test-cmd (commander--find-file))))) (defun commander--run-command-at-point (\u0026amp;optional args) \u0026#34;Suffix for using current buffer-file-name and line-at-pos as relevant test.\u0026#34; (interactive (list (transient-args \u0026#39;jd/commander))) (commander--run-command (concat (mapconcat #\u0026#39;identity args \u0026#34; \u0026#34;) (commander--test-cmd (commander--current-file-at-point))))) ;; ... (defun commander--run-command (cmd) \u0026#34;Runs CMD in project root in compilation mode buffer.\u0026#34; (interactive) (when (get-buffer \u0026#34;*commander test*\u0026#34;) (kill-buffer \u0026#34;*commander test*\u0026#34;)) (with-current-buffer (get-buffer-create \u0026#34;*commander test*\u0026#34;) (setq compilation-scroll-output t) (setq default-directory (projectile-project-root)) (compilation-start cmd \u0026#39;minitest-compilation-mode))) I have this bound to \u0026lt;leader\u0026gt; r which for me is SPC r. This allows me to toggle on any environment variables and essentially build the testing command I need. I then use (compilation-start COMMAND) to run my test in a controlled popup buffer so I can easily see the results while I\u0026rsquo;m continuing to code. I\u0026rsquo;ve also set up commander--run-current-file and comander--run-command-at-point. commander--run-current-file will just run the generated command for the file that open in the current buffer. So ...env vars rails test path/to/test.rb, while commander--run-at-point will run the command and include the number line at the current cursor point, so I can just run a single test without any issue.\nThis has sped up my workflow tremendously and made testing way faster for me as I don\u0026rsquo;t have to bother with building a command from scratch, but I can instead just build it with a transient.\nConclusion Hopefully this post has provided some inspiration for you to get into building transient menus. I\u0026rsquo;m still pretty new to elisp and learning about transient.el so there maybe some inaccuracies here and there. I also elected to use the transient-define-prefix macro instead of the more formal methods for creating a transient, but the macro is probably sufficient for most use cases like mine.\nBelow are links to resources that helped to expand my own knowledge and even inspire this post. A big shout out goes to Jonas for creating such an incredible package as well as positron-solutions for such a thorough guides through it all.\nResources Transient API Example by u/Psionikus: Part 1 Transient API Example by u/Psionikus: Part 2 Official Transient Manual Transient Showcase by positron-solutions ","permalink":"https://jd.codes/posts/transient-emacs/","summary":"\u003cp\u003e\u003ca href=\"https://magit.vc/\"\u003eMagit\u003c/a\u003e is an innovative package that provides an amazing interface over git. The complexity of its UI is completely hidden away thanks to another package born out of Magit called \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_mono/transient.html\"\u003eTransient\u003c/a\u003e. Transient is so innovative that it was added to emacs core in 2021. Understanding at least the basics of Transient can provide alot of value in building tools to enhance various workflows.\u003c/p\u003e\n\u003cfigure\u003e\n    \u003cimg loading=\"lazy\" src=\"magit.png\"/\u003e \n\u003c/figure\u003e\n\n\u003cp\u003e\u003ca href=\"https://magit.vc/manual/transient/\"\u003eFrom the official manual\u003c/a\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eTransient is the library used to implement the keyboard-driven “menus” in Magit. It is distributed as a separate package, so that it can be used to implement similar menus in other packages.\u003c/p\u003e","title":"Transient Menus in Emacs pt. 1"},{"content":"I\u0026rsquo;m a big believer in keeping a clean commit history. This practice isn\u0026rsquo;t always necessary depending on the type of work being done, but I frequently reference old commits, so keeping the merge commits out of my history just helps me to get rid of the noise. This means, that I rebase my branches often which can cause an issue when branching off branches, as once a branch is merged into the main branch, you need to catch up your currently working branch some how.\nSo here\u0026rsquo;s the process I follow to make sure that all my branches stay up to date. Lets say I\u0026rsquo;m working on branch-B which is branched off branch-A which itself is branched off main.\nNote: You can see a similar output to this by doing git log --pretty=oneline.\n# branch-B commits b-3 b-2 b-1 a-3 (branch-A) a-2 a-1 # branch-A commits a-3 a-2 a-1 Lets say branch-A gets merged to main via a merge commit. The merge commit squashes a-1,2,3 into a single commit and now main has all the changes on the remote origin. Now we\u0026rsquo;re left with branch-B which looks like:\nb-3 b-2 b-1 a-3 a-2 a-1 The fix is really encapsulated into a single command, but before we do that we have to ensure our local main is up to date so it has those changes.\n$ git checkout main $ git pull Now that the local version of main is up to date we can now rebase branch-B onto main from branch-A. The git command almost reflects that sentence perfectly.\n$ git checkout branch-B $ git rebase --onto main branch-A What happens here is that branch-B upstream changes from branch-A to main but with gits knowledge of what happened to branch-A which in this case was a merge commit. This means, that the merge commit is honored, and only the commits from branch-B proper are re-applied. So after this the history of branch-B looks like:\n# branch-B commits b-3 b-2 b-1 \u0026hellip;while the upstream is now main.\nNote: It\u0026rsquo;s important that you make sure your local main has that merge commit in it\u0026rsquo;s history otherwise you\u0026rsquo;ll end up with weird conflicts.\n","permalink":"https://jd.codes/posts/branches-off-branches/","summary":"\u003cp\u003eI\u0026rsquo;m a big believer in keeping a clean commit history. This practice isn\u0026rsquo;t always necessary depending on the type of work being done, but I frequently reference old commits, so keeping the merge commits out of my history just helps me to get rid of the noise. This means, that I rebase my branches often which can cause an issue when branching off branches, as once a branch is merged into the \u003ccode\u003emain\u003c/code\u003e branch, you need to catch up your currently working branch some how.\u003c/p\u003e","title":"Quick Tip: Git - Rebasing Branches"},{"content":"Prodigy is an incredible tool of convenience for me. I\u0026rsquo;ve been slowly migrating my entire workflow into Emacs and Prodigy has become a staple in my day to day.\nWhat is Prodigy? Manage external services from within Emacs I came up with the idea when I got to work one Monday morning and before I could start working I had to manually start ten or so services. To get rid of this tedious work, I started working on this Emacs plugin, which provides a nice and simple GUI to manage services.\n\u0026ndash; Johan Andersson (author of Prodigy)\nThis has to be probably the most \u0026ldquo;Emacs user\u0026rdquo; solution to a problem I\u0026rsquo;ve ever heard.\nIn short, you can define a list of services in your configuration, and in turn, are given a simple UI to manage those services. This site is currently built with zola and the command to start the server is zola serve. Instead of managing a terminal buffer or worse switching to a terminal app I can define the following in my configuration:\n(prodigy-define-service :name \u0026#34;Personal Blog\u0026#34; :command \u0026#34;zola\u0026#34; :args \u0026#39;(\u0026#34;serve\u0026#34;) :cwd \u0026#34;~/code/my-blog-v2\u0026#34; :tags \u0026#39;(personal)) Now when I run M-x prodigy a buffer comes up showing me the service I\u0026rsquo;ve defined. (It\u0026rsquo;s running as I\u0026rsquo;m writing this and taking screenshots).\nYou can also very easily open a buffer with the log output for inspecting/debugging:\nThis interface takes a lot of inspiration from dired in that services can be marked and then acted upon in some way so you can start or stop multiple services at one time. In the UI, you can filter services by tags or name, which allows you to build groups of services really easily that pertain to a particular project. After filtering your defined services, you can then select all of them with prodigy-mark-all and then prodigy-start to kick them all off.\nHere\u0026rsquo;s a list of all the default keybindings in the `prodigy-mode` buffer:\nkey function `n` prodigy-next `p` prodigy-prev `M-\u0026lt;` prodigy-first `M-\u0026gt;` prodigy-last `m` prodigy-mark `t` prodigy-mark-tag `M` prodigy-mark-all `u` prodigy-unmark `T` prodigy-unmark-tag `U` prodigy-unmark-all `s` prodigy-start `S` prodigy-stop `r` prodigy-restart `$` prodigy-display-process `o` prodigy-browse `f t` prodigy-add-tag-filter `f n` prodigy-add-name-filter `F ` prodigy-clear-filters `j m` prodigy-jump-magit `j d` prodigy-jump-file-manager `M-n` prodigy-next-with-status `M-p` prodigy-prev-with-status `C-w` prodigy-copy-cmd Tags Here\u0026rsquo;s a more intense use case. The product I work on at my day job has about 26 services accross a couple different applications, databases, cache systems, asset compilers/transpilers, kafka consumers, and background job servers.\n;; In eshell ~ λ (length (prodigy-services-tagged-with \u0026#39;work)) 26 The default on my team is to use 3 different Procfiles in 2 different repositories to spin everything up. That\u0026rsquo;s a pain honestly, especially when you have to inspect logs that are intermingled with half a dozen other service logs. Overmind has been suggested and has some support in my engineering org, but being pushed into using tmux is more annoying than anything to me.\nTags are very useful for me as not only can I quickly select a subset of services, but I can also add some shared configuration among similar services. Here\u0026rsquo;s the tag I use for all the Kafka consumers:\n(prodigy-define-tag :name \u0026#39;cf-consumer :ready-message \u0026#34;=\u0026gt; Ctrl-C to shutdown consumer\u0026#34;) You can see here that it indicates a `ready-message`. This tag attribute will utilize Prodigy\u0026rsquo;s log \u0026ldquo;identifying\u0026rdquo; regex in order to tell Prodigy that a service is status \u0026ldquo;ready\u0026rdquo;. This regex is matched against all log output until it\u0026rsquo;s matched, at which point Prodigy will identify the service status as \u0026ldquo;ready\u0026rdquo;. This makes it easy to manually tell Prodigy exactly when a service is done spinning up. Here\u0026rsquo;s another tag:\n(prodigy-define-tag :name \u0026#39;rails :on-output (lambda (\u0026amp;rest args) (let ((output (plist-get args :output)) (service (plist-get args :service))) (when (or (s-matches? \u0026#34;Listening on 0\\.0\\.0\\.0:[0-9]+, CTRL\\\\+C to stop\u0026#34; output) (s-matches? \u0026#34;Use Ctrl-C to stop\u0026#34; output)) (prodigy-set-status service \u0026#39;ready))))) This is basically ripped straight from Prodigy\u0026rsquo;s README but it works like a charm for me. Every output log line will run this callback and is useful for triggering custom side effects or, as I\u0026rsquo;m doing here, telling prodigy the service is ready. I run 3 Rails apps so being able to just tag them all with `\u0026lsquo;rails` makes it easy to add the configuration everywhere without rewriting it everytime and tells me what behavior the Prodigy services is relying on at a glance in the prodigy buffer. You don\u0026rsquo;t have to do it this way, I just found it useful to experiment with as I was configuring things, so I left it.\nService Definitions Prodigy is such a simple package and it\u0026rsquo;s configuration api is also very simple, but for completeness sake here I\u0026rsquo;ll explain a bit more about configuring services.\n(prodigy-define-service :name \u0026#34;esbuild-app\u0026#34; :cwd \u0026#34;~/code/admin\u0026#34; :command \u0026#34;yarn\u0026#34; :args \u0026#39;(\u0026#34;build\u0026#34; \u0026#34;--watch\u0026#34;) :ready-message \u0026#34;successfully rebuilt - now reloading\u0026#34; :tags \u0026#39;(work cf-frontend)) (prodigy-define-service :name \u0026#34;cf-chat-frontend\u0026#34; :command \u0026#34;webpack-dev-server\u0026#34; :args \u0026#39;(\u0026#34;s\u0026#34; \u0026#34;-p\u0026#34; \u0026#34;5002\u0026#34;) :cwd \u0026#34;~/code/cfchat\u0026#34; :path \u0026#39;(\u0026#34;~/code/cfchat/bin\u0026#34;) :ready-message \u0026#34;Built at:\u0026#34; :tags \u0026#39;(work)) The configuration is fairly straight forward. The name, command, and args are all defined as you\u0026rsquo;d expect. Then cwd will be the path to the directory where the command should be executed. In some cases, the binary for the command you need to run isn\u0026rsquo;t in $PATH so you can optionally provide path which will tell Prodigy the path of the binary to run. Both of these services define their own ready-message since they\u0026rsquo;re unique compared to the rest of the services. Then finally we just add the list of tags.\nA few additional options not in my examples are:\n:env to add environment variables as needed to the command. ex. :env '((\u0026quot;ENV_VARIABLE\u0026quot; \u0026quot;value\u0026quot;)) :stop-signal the type \u0026ldquo;kill signal\u0026rdquo; to send the process to stop it. I haven\u0026rsquo;t needed to do this myself, so I\u0026rsquo;m not 100% sure how it works. :kill-process-buffer-on-stop which will kill the log output buffers completely when the service is stopped. By default, they persist for an entire emacs session unless killed manually. Check out the projects README for more in depth options than what\u0026rsquo;s provided here.\nHere\u0026rsquo;s an exact play-by-play of all the commands I use and how I do this everytime I want to spin things up at work. \u0026lt;details\u0026gt; \u0026lt;summary\u0026gt;Play-by-play\u0026lt;/summary\u0026gt;\nSince I use doom-emacs as my base distribution, YMMV on some of the keybindings here but:\nSPC r s - runs (prodigy) which opens buffer i t - runs (prodigy-add-tag-filter) Type wo - fills in completing read for \u0026ldquo;work\u0026rdquo; tag. RET - applies the filter M - runs (prodigy-mark-all) s - runs (prodigy-start) Wait for a bit for all them to spin up Begin work\u0026hellip; \u0026lt;/details\u0026gt;\n\u0026lt;br /\u0026gt; That\u0026rsquo;s the intro to Prodigy and managing local services with it. If you\u0026rsquo;re interested in a few things on my todo-list to implement for myself for your own inspiration read on\u0026hellip;\nFuture Customization Modeline integration Place the number of running services for a project or with a specific tag output in the modeline. I\u0026rsquo;d also like to map this to projectile-project-root and a tag so as I\u0026rsquo;m switching projects or repositories, I can keep a birds eye view of the services running at a glance in the modeline. Utilize prodigy-output-filters to either alert me or dump a message in the modeline so I can easily be notified of exceptions being raised in the log output of a particular buffer. Additional macro-esque keybindings Whenever I switch branches, I\u0026rsquo;d like to run one keybinding to kill all services running, run a sync command for the project, and then re-start all the services for a project with some message output or a compilation-mode style \u0026ldquo;logging.\u0026rdquo; Dynamically create Prodigy services from Procfile entries and/or conventional rails, yarn, or npm commands based on the project. ","permalink":"https://jd.codes/posts/emacs-prodigy/","summary":"\u003cp\u003e\u003ca href=\"https://github.com/rejeep/prodigy.el\"\u003eProdigy\u003c/a\u003e is an incredible tool of convenience for me. I\u0026rsquo;ve been slowly migrating my entire workflow into Emacs and Prodigy has become a staple in my day to day.\u003c/p\u003e\n\u003ch2 id=\"what-is-prodigy\"\u003eWhat is Prodigy?\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003eManage external services from within Emacs\nI came up with the idea when I got to work one Monday morning and before I could start working I had to manually start ten or so services.\nTo get rid of this tedious work, I started working on this Emacs plugin, which provides a nice and simple GUI to manage services.\u003c/p\u003e","title":"Managing Local Services in Emacs with Prodigy"},{"content":"I was recently working on a porcelain for local database management in Emacs, tablemacs (name tbd). The general idea here is to give a magit style interface for interacting with a local database. This mode is built off SQLi (sql-interactive-mode) and uses a hidden comint buffer to execute commands. Everything was working great till I encountered a really weird issue. Let me preface everything with, I\u0026rsquo;m still very new to elisp and am still very much a beginner. Not only is it a radically different language than what I\u0026rsquo;m used to, the paradigms are also just very unique to emacs. If some of the code here looks wrong, it\u0026rsquo;s a mistake in translation as some of it was modified for ease of understanding.\nThe process \u0026amp; the Issue Right now tablemacs creates a hidden comint buffer with sql-interactive-mode engaged. I then use comint-redirect-send-command-to-process which redirects the output of a comint command to an aribtrary buffer, which is my tablemacs-status buffer.\n(comint-redirect-send-command-to-process COMMAND OUTPUT-BUFFER PROCESS ECHO \u0026amp;optional NO-DISPLAY)\nDocumentation\nSend COMMAND to PROCESS, with output to OUTPUT-BUFFER. With prefix arg, echo output in process buffer. If NO-DISPLAY is non-nil, do not show the output buffer.\nThis works as you\u0026rsquo;d expect however, there\u0026rsquo;s some artifacts in the output. Here\u0026rsquo;s what I get for my show-tables command which just runs show tables;:\nshow tables;^ M +--------------------------+^ M | Tables_in_tablemacs_test | +--------------------------+^ M | test_table |^ M +--------------------------+^ M All those =^M=s means it\u0026rsquo;s displaying the carriage returns in the redirected buffer. Obviously, I wanted to remove those.\nI searched around for something that could help and I had already known about comint filters. These allow you to run filter functions on the strings as they or after they\u0026rsquo;ve interacted with the comint buffer. Here\u0026rsquo;s a non-comprehensive list of a few of the available \u0026ldquo;filters\u0026rdquo; list variables you can add filter functions too:\ncomint-input-filter-functions comint-output-filter-functions comint-preoutput-filter-functions comint-redirect-filter-functions comint-redirect-original-filter-function There\u0026rsquo;s a few more but those are the ones that were interesting to me in this situation. Looking at the documentation, comint-redirect-filter-functions seemed perfect.\nList of functions to call before inserting redirected process output. Each function gets one argument, a string containing the text received from the subprocess. It should return the string to insert, perhaps the same string that was received, or perhaps a modified or transformed string.\nThe functions on the list are called sequentially, and each one is given the string returned by the previous one. The string returned by the last function is the text that is actually inserted in the redirection buffer.\nYou can use `add-hook\u0026rsquo; to add functions to this list either globally or locally.\nSeems ok so far! So I plugged it in with:\n(add-hook \u0026#39;tablemacs-minor-mode-hook (lambda () (push \u0026#39;comint-strip-ctrl-m comint-redirect-filter-functions) )) It did not work.\nInvestigation I then moved to setting the comint-redirect-filter-functions globally and still it did not work. I thought surely I was doing something wrong, but when I used describe-variable on comint-redirect-filter-functions it appeared to have comint-strip-ctrl-m as it should. I\u0026rsquo;m still a beginner when it comes to elisp so I thought I was doing something wrong. So I wrote my own filter just to see:\n(defun tablemacs--comint-strip-ctrl-m-test (str) \u0026#34;test filter\u0026#34; (message \u0026#34;ran filter!\u0026#34;) str) Low and behold I got the message in my minibuffer. So what gives?\nWell the next thing to do was to look at describe-function for comint-strip-ctrl-m which is as follows:\n(defun comint-strip-ctrl-m (\u0026amp;optional _string interactive) \u0026#34;Strip trailing `^M\u0026#39; characters from the current output group. This function could be on `comint-output-filter-functions\u0026#39; or bound to a key.\u0026#34; (interactive (list nil t)) (let ((process (get-buffer-process (current-buffer)))) (if (not process) ;; This function may be used in ;; `comint-output-filter-functions\u0026#39;, and in that case, if ;; there\u0026#39;s no process, then we should do nothing. If ;; interactive, report an error. (when interactive (error \u0026#34;No process in the current buffer\u0026#34;)) (let ((pmark (process-mark process))) (save-excursion (condition-case nil (goto-char (if interactive comint-last-input-end comint-last-output-start)) (error nil)) (while (re-search-forward \u0026#34;\\r+$\u0026#34; pmark t) (replace-match \u0026#34;\u0026#34; t t))))))) Herein lies the culprit. This filter takes in an \u0026amp;optional _string and usually, variables prefixed with _ means they aren\u0026rsquo;t used. So if it\u0026rsquo;s not using the passed in string, what\u0026rsquo;s it doing? Well it\u0026rsquo;s using (get-buffer-process (current-buffer)) and then marking where the process command output starts and then searching through with (research-forward \u0026quot;\\r+$\u0026quot; pmark t) which is what actually replaces the carriage returns. The big red flag here is that it\u0026rsquo;s using the (current-buffer) which, in my use case, isn\u0026rsquo;t the buffer that the process is running in, instead its my porcelein buffer.\nSo the issue turned out to be the implementation of comint-strip-ctrl-m and not the way I was using it.\nWhat to do next? It\u0026rsquo;s pretty clear to me that the function of `comint-strip-ctrl-m` doesn\u0026rsquo;t match the documentation. Emacs documentation is exceptional compared to anything else I\u0026rsquo;ve used, I mean it\u0026rsquo;s known as the \u0026ldquo;self documenting text editor\u0026rdquo; for a reason. However, this is a very specific case where the documentation, or expected implicit behavior derrived from the documentation, doesn\u0026rsquo;t line up with reality. So what should I do?\nMy fix In my code, I just wrote my own filter to do exactly comint-strip-ctrl-m should do. It looks like this:\n(defun tablemacs--comint-strip-ctrl-m (str) \u0026#34;Filter function to remove carriage returns from comint output This is needed because one provided by comint rely\u0026#39;s on `current-buffer` to get the process and it\u0026#39;s always going to be wrong.\u0026#34; (replace-regexp-in-string \u0026#34;\\r\u0026#34; \u0026#34;\u0026#34; str)) So this now works with comint-redirect-filter-functions as expected.\nshow tables; +--------------------------+ | Tables_in_tablemacs_test | +--------------------------+ | test_table | +--------------------------+ Emacs bug report? At this point I\u0026rsquo;m considering filing a report, or at least a request to update the documentation for this rather specific small bug. It\u0026rsquo;s not like this is a huge breaking bug for most users, and it\u0026rsquo;s a pretty specific use case. But this might open up a potential contribution opporunity or at least a way to get involved with the emacs maintainer community at least a little bit. Possible fixes could consist of one of the following:\nUpdating the documentation for comint-strip-ctrl-m to explictely state it uses current-buffer instead of just the passed in string. Updating comint-strip-ctrl-m to actually use the string it\u0026rsquo;s passed and perform the same string editing functions. Creating a new comint-strip-ctrl-m-filter (name TBD?) which takes in a string, modifies it and returns a modified string. I don\u0026rsquo;t know. Maybe someone will let me know if this is in fact an issue or if I\u0026rsquo;m just missing something else important.\nHappy Hacking.\n","permalink":"https://jd.codes/posts/emacs-comint-filter-bug/","summary":"\u003cp\u003eI was recently working on a porcelain for local database management in Emacs, \u003ccode\u003etablemacs\u003c/code\u003e (name tbd). The general idea here is to give a magit style interface for interacting with a local database. This mode is built off \u003ccode\u003eSQLi\u003c/code\u003e (sql-interactive-mode) and uses a hidden \u003ccode\u003ecomint\u003c/code\u003e buffer to execute commands. Everything was working great till I encountered a really weird issue. Let me preface everything with, I\u0026rsquo;m still \u003cstrong\u003every\u003c/strong\u003e new to elisp and am still very much a beginner. Not only is it a radically different language than what I\u0026rsquo;m used to, the paradigms are also just very unique to emacs. If some of the code here looks wrong, it\u0026rsquo;s a mistake in translation as some of it was modified for ease of understanding.\u003c/p\u003e","title":"Finding an Emacs Bug"},{"content":"Manging the state of objects and state specific behavior is always an interesting problem to deal with. The Rails community has done a great job of developing libraries to help manage this. Most of these libraries come in the form of State Machines. These typically have the pattern of defining states, events to change states, and constraints by which those states can or cannot change. Usually, this code is maintained in your model, and in some cases states can have their very own model and DB table and keep an audit history of some kind.\nThe Problem A lot of state machines require code to be placed directly in the model and have mechanisms by which side effects can be called. With a complex state machine, or a state machine that evolves over time, this can create a lot of odd behavior and weird dependencies on side effects at each transition. This quickly becomes hard to troubleshoot and hard to test and (even worse) can also result in transition events that only fire in order to fire their side effects or \u0026ldquo;reset\u0026rdquo; the state because of an error that occurred down stream. For a simple state management use case that has a consistent set of linear flows and minimal side effects, a state machine would probably be a good fit. However, when things grow beyond that, or when mulitple objects are having to interact as a result of the state transitions we need to look for something more robust, easily extensible, and that follows good object oriented design principals: The State Design Pattern.\nSide Note I highly recommend picking up a copy of Design Patterns: Elements of Resuable Object Oriented Software as these patterns are rather timeless and the material is easily referenceable.\nState Design Pattern Overview The State Design pattern that at it\u0026rsquo;s core allows you to manage your objects state specific behavior in a state object concrete class. This concrete class inherits from an abstract super class that defines the public interface, which acts as your contract to the outside world. In Rails, all of this can be confined into a concern to share this behavior with other objects if necessary. For now though, lets look at at a simple example implementation with just plain old Ruby.\nHere we have a Post object. It has an id and content and when the object is initialized it\u0026rsquo;s always initialized by being in a draft state.\nclass Post attr_accessor :id, :content def initialize(id, content) @id = id @content = content end def post_to_socials puts \u0026#34;Posted to social accounts!\u0026#34; end end We have not defined any state behavior yet, just building the foundation for the example so the rest is easy to follow.\nThe state design pattern typically starts off with an abstract class that defines the proper interface that every subclass, concrete state object, has to implement.\nclass State attr_reader :context def initialize(context) @context = context end def unpublish raise NotImplementedError end def current_state raise NotImplementedError end def publish raise NotImplementedError end def archive raise NotImplementedError end def log_state(state) puts \u0026#34;Transitioning from: #{context.state.current_state} to: #{state}\u0026#34; end end The @context variable is set to the current object implementing this state, so in this case a `Post`. It allows us to make object specific method calls as we need and update the object attributes as transitions happen. This is also were any global behavior that happens among ALL states can be placed. It\u0026rsquo;s important to note, that if you do want to implement some kind of global validation or side effect (like logging), that every single child class implements that behavior. It would be unwise to use conditionals to determine whether or not to call a side effect or validation in the super class, even if 5 out of 6 of your child classes need it. Prefer duplication over the wrong abstrction ;).\nUp next we have the concrete state classes. These can be anything but they should inherit from the abstract State class.\nclass DraftState \u0026lt; State def current_state \u0026#34;draft\u0026#34; end def unpublish raise StandardError \u0026#34;Cannot unpublish post in draft state.\u0026#34; end def publish post_to_socials log_state(\u0026#34;published\u0026#34;) context.state = PublishedState.new(context) end def archive log_state(\u0026#34;archived\u0026#34;) context.state = ArchivedState.new(context) end private def post_to_socials context.post_to_socials end end class PublishedState \u0026lt; State def current_state \u0026#39;published\u0026#39; end def unpublish log_state(\u0026#34;unpublished\u0026#34;) context.state = DraftState.new(context) end def publish raise StandardError \u0026#34;Cannot publish already published post!\u0026#34; end def archive log_state(\u0026#34;archived\u0026#34;) context.state = ArchivedState.new(context) end end class ArchivedState \u0026lt; State def current_state \u0026#39;archived\u0026#39; end def unpublish log_state(\u0026#34;unpublished\u0026#34;) context.state = DraftState.new(context) end def publish log_state(\u0026#34;published\u0026#34;) context.state = PublishedState.new(context) end def archive raise StandardError \u0026#34;Cannot archive already archived post!\u0026#34; end end Now we can see the full power of this state design pattern. Every state is it\u0026rsquo;s own object implementing every method from it\u0026rsquo;s super class. Each one controls it\u0026rsquo;s transition to the next state and calls any and all side effects necesssary to the transtiion of each state.\nIn DraftState#publish we fire off the post_to_socials side effect. Lets say this method fails, and our domain requires this to succeed before publishing. Well here we can implement that fairly easily.\ndef publish # draftState.rb post_to_socials log_state(\u0026#34;published\u0026#34;) context.state = PublishedState.new(context) rescue SocialPoster::Error # completely arbitrary error class log_state(\u0026#34;unpublished\u0026#34;) end end This will prevent a state update from happening when the necessary behavior has not taken place.\nOk now lets actually make this behavior accessible to the Post object. This will use delegation in order to preserve an easy predictable API for changing states.\nclass Post attr_accessor :id, :content, :state def initialize(id, content) @id = id @content = content @state = DraftState.new(self) # Initial state end # Delegated def current_state @state.current_state end # Delegated def publish @state.publish end # Delegated def archive @state.archive end def post_to_socials puts \u0026#34;Posted to social accounts!\u0026#34; end end As you can see, this is simply delegating any and all state calls to the relevant state object.\nImportance of this pattern This implementation is very Open/Closed meaning, it\u0026rsquo;s open for extenstion and closed to modification. This is the O in SOLID. This allows us to extend it\u0026rsquo;s behavior without modifying existing behavior which is a powerful tool in software development and a core principal of OOP. At any point, adding a new state is just adding a couple methods and creating the state object you\u0026rsquo;d wish to implement and that\u0026rsquo;s it. This is personally why I prefer to use this type of pattern over a state machine.\nState machines, if not planned and maintained well easily get out of hand. They tend to have to handle a multitude of things that can make coupling code too easy. Typically they can handle before \u0026amp; after transition side effects, guards to prevent state transition happening, etc. This can introduce some confusion into your code as corners are inevitably cut due to business needs. This also means that testing each transtion requires the instantiation of the object implementing and following it through each individual transition. Testing with the state design pattern instead gives a great entrypoint to just testing the individual objects, allowing you to have confidence your state machine is working just as you intended. This is also good for complex state machines, where you have dependencies on the state of other objects, or you need mulitple objects to implement this same exact state machine. This can be easily abstracted and states can be predetermiend by a value and a method to set itself.\nAll in all my focus on writing good OOP code has revealed a lot of interesting things I take for granted in the Ruby community. State machines were definitely something I never realized could be simplified into smaller objects like this and now that I have, I can\u0026rsquo;t think of a scenario where I would use a state machine unless the state transitions were finite, well defined, and dependencies were kept to a minimum, even so I might elect for this pattern by virtue of it\u0026rsquo;s testability alone.\n","permalink":"https://jd.codes/posts/state-design-pattern/","summary":"\u003cp\u003eManging the state of objects and state specific behavior is always an interesting problem to deal with. The Rails community has done a great job of developing libraries to help manage this. Most of these libraries come in the form of State Machines. These typically have the pattern of defining states, events to change states, and constraints by which those states can or cannot change. Usually, this code is maintained in your model, and in some cases states can have their very own model and DB table and keep an audit history of some kind.\u003c/p\u003e","title":"State Design Pattern"},{"content":"Polymorphic associations is a common theme among many applications. Things can get complicated, especially as far as naming is concerned, when you consider having a double polymorphic association. Rails provides all the necessary mechanisms by which to manage this in a way that makes sense for most business needs as well as leaving it readable for future programmers that come by in the future.\nIn programming languages and type theory, polymorphism is the provision of a single interface to entities of different types or the use of a single symbol to represent multiple different types.\nThe example we\u0026rsquo;ll work with today is one taken from some work I recently did helping to implement a Favorites feature. The requirements for this were:\nA User can have many favorites, which can be a Report or a Team A Team can have many favorites, which can be a Report This is what I mean by a double polymorphic relationship. One side, favoritor, can be one of a User or Team while the other side, the favouritee, can be of the type Team or Report. The requirements lended itself to building a Favoritings table and using that as our base. This would have a favoritor and favoritee polymorphic columns, which with Rails and ActiveRecord automatically include the id and type of each of those. This is what the migration looked like:\nclass CreateFavoritings \u0026lt; ActiveRecord::Migration[6.1] def change create_table(:favoritings) do |t| t.references(:favoritee, polymorphic: true, index: true) t.references(:favoritor, polymorphic: true, index: true) t.timestamps end end end So now comes time to develop the actual relationships to the other models. This is complicated to a degree but you have to consider how your domain is laid out in order to define these relationships as they\u0026rsquo;re needed. For one a Team can have many favourites and a User can have many favourites. Lets solve that first.\n# app/models/user.rb class User \u0026lt; ApplicationRecord has_many :favorites, class_name: \u0026#39;Favoriting\u0026#39;, foreign_key: :favoritor_id, as: :favoritor end While the name of the relationship isn\u0026rsquo;t exact to the model, the domain name of favorites makes total sense. A User has many favorites. We then go onto define what the class name is since we\u0026rsquo;re not explicitely using the Favoritings class name. Then we have to tell it the key this relationship uses on that model, as well as the type. A User has many favorites of class Favoritings based on the foreign key favoritor_id as the type of favoritor. This makes a well understood API for querying later: User.find(1).favourites will yield all the favourites. You could also get more specific with:\nhas_many :favorite_teams, class_name: \u0026#39;Favoriting\u0026#39;, foreign_key: :favoritor_id, as: :favoritor, source_type: \u0026#39;Team\u0026#39; This not only defines the relationship more explicitely to the individual type but also builds the query via a join instead of having to call another query to scope it down after the fact. One of the many optimizations ActiveRecord can supply us.\nNow lets implement the other side: Teams as a favoriting.\n# app/models/team.rb class Team \u0026lt; ApplicationRecord has_many :favoritings, as: :favoritee has_many :user_favoritors, through: :favoritings, source: :favoritor, source_type: \u0026#39;User\u0026#39; end The first relationship says a Team has many favouritings as the favouritee. So this model can be \u0026ldquo;favorited.\u0026rdquo; Next we have a Team has many user_favoritors through Favoritings model which are of the type Users and the key/type is favoritor. This will pull all the users that have favorited this team. Just like earlier this allows ActiveRecord to optimize queries for these early on instead of running mulitple or having to manage scopes. This also provides a very readable API for developers down the road.\nThis is half the aforementioned implementation but it describes the principal enough. Rails and ApplicationRecord provides a great and flexible interface for explicitely defining these types of complex relationships that all flow through the same model.\n","permalink":"https://jd.codes/posts/double-polymorphic-associations/","summary":"\u003cp\u003ePolymorphic associations is a common theme among many applications. Things can get complicated, especially as far as naming is concerned, when you consider having a double polymorphic association. Rails provides all the necessary mechanisms by which to manage this in a way that makes sense for most business needs as well as leaving it readable for future programmers that come by in the future.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eIn programming languages and type theory, polymorphism is the provision of a single interface to entities of different types or the use of a single symbol to represent multiple different types.\u003c/p\u003e","title":"Double Polymorphic Associations in Rails"},{"content":"Recently, I needed to figure out how to route some internet traffic through another computer to access a private network. Dynamic port forwarding with SSH seemed to be the best solution for this type of thing. I don\u0026rsquo;t know enough about SSH so this was a good place to dig in a little deeper and learn a few things. Once the tunnel was setup I decided to utilize Firefox\u0026rsquo;s profiles feature in order to setup a SOCKS Proxy and ensure that only the web traffic I wanted was routed through the SSH tunnel.\nSetup I setup this tunnel in a rather simple way. Here\u0026rsquo;s the man page entries for the relevant flags I used, -D, -n, and -f.\n-D [bind_address:]port Specifies a local \u0026ldquo;dynamic\u0026rdquo; application-level port forwarding. This works by allocating a socket to listen to port on the local side, optionally bound to the specified bind_address. Whenever a connection is made to this port, the connection is forwarded over the secure channel, and the application protocol is then used to determine where to connect to from the remote machine. Currently the SOCKS4 and SOCKS5 protocols are supported, and ssh will act as a SOCKS server. Only root can forward privileged ports. Dynamic port forwardings can also be specified in the configuration file.\n-f Requests ssh to go to background just before command execution. This is useful if ssh is going to ask for passwords or passphrases, but the user wants it in the background. This implies -n. The recommended way to start X11 programs at a remote site is with something like ssh -f host xterm. If the ExitOnForwardFailure configuration option is set to “yes”, then a client started with -f will wait for all remote port forwards to be successfully established before placing itself in the background.\n-n Redirects stdin from /dev/null (actually, prevents reading from stdin). This must be used when ssh is run in the background. A common trick is to use this to run X11 programs on a remote machine. For example, ssh -n shadows.cs.hut.fi emacs \u0026amp; will start an emacs on shadows.cs.hut.fi, and the X11 connection will be automatically forwarded over an encrypted channel. The ssh program will be put in the background. (This does not work if ssh needs to ask for a password or passphrase; see also the -f option.)\nConfiguration ssh [USER]@[IP_ADDR] -D [PORT] -N -f # Useful alias alias my_ssh_tunnel=\u0026#34;ssh [USER]@[IP_ADDR] -D [PORT] -N -f\u0026#34; As explained above in the documentation, the -f flag is the nifty one as that makes the connection and runs it in the background, but leaves open responses to ensure you can type in an ssh password if you need to. This is better than using the [COMMAND] \u0026amp; shortcut.\nWith that complete you can now navigate to `about:profiles` in Firefox and create a new one, launch it, and configure your network settings in it to use:\nManual Proxy Configuration Input 127.0.0.1 and the specified [PORT] from the command Select SOCKS v5 Enable Proxy DNS using SOCKS v5 and disable use DNS over HTTPs (if configured) Now, only that profile will have it\u0026rsquo;s web traffic routed through the SSH tunnel. Your regular profile will be directly connected. That\u0026rsquo;s it!\nLaunching Firefox You can now launch Firefox pretty easily by using firefox -P [PROFILE] \u0026amp;. Make sure you configure your default profile as you want to ensure you don\u0026rsquo;t send unnecessary traffic through the proxy.\n","permalink":"https://jd.codes/posts/ssh-tunneling/","summary":"\u003cp\u003eRecently, I needed to figure out how to route \u003cem\u003esome\u003c/em\u003e internet traffic through another computer to access a private network. Dynamic port forwarding with SSH seemed to be the best solution for this type of thing. I don\u0026rsquo;t know enough about SSH so this was a good place to dig in a little deeper and learn a few things. Once the tunnel was setup I decided to utilize Firefox\u0026rsquo;s profiles feature in order to setup a SOCKS Proxy and ensure that only the web traffic I wanted was routed through the SSH tunnel.\u003c/p\u003e","title":"Using SSH Tunneling"},{"content":"I love Emacs. I\u0026rsquo;ve been using it since late 2017 and have had an on and off again relationship with it. It\u0026rsquo;s a great tool for anyone who likes to tinker around with software. Like any relationship, there are some pain points I have that consistently want to push me away from Emacs, one of which is performance.\nI\u0026rsquo;ve used Doom Emacs for a really long time and hlissner has done an incredible job of building a fantastic configuration setup, and compared to other configuration frameworks I\u0026rsquo;ve used, Doom is the most performant and most versatile. That being said, no matter how much optimization is done on the configuration side, Emacs can still be extremely slow, especially compared to it\u0026rsquo;s Vim counterpart.\nCue GCC Emacs GCC Emacs is a branch of the main Emacs repository that uses libgccjit, a pseudo-JIT compiler which compiles elisp to native code. You can see all updates from the author here and try to understand exactly what\u0026rsquo;s happening. This provides an exceptionally large performance boost in everything Emacs does from startup time to normal day-to-day work. It also appears to help manage the amount of C code that needs to be written in the underlying Emacs engines. See the Emacs Wiki for more info on how it works and more detailed instructions than what I\u0026rsquo;m about to give.\nGet up and running I\u0026rsquo;ve run this on Arch linux only so far so here are the steps I followed in order to get it running. Here\u0026rsquo;s the build documentation for more information on the flags used to configure and compile. Some used here can be omitted if you don\u0026rsquo;t want them.\nNote: I highly advise against using the AUR package for GCC Emacs and instead just bulid it yourself\n# Install libgccjit: https://aur.archlinux.org/packages/libgccjit/ $ yay -S libgccjit # Install CMake (required for VTerm. Ignore if you want) $ sudo pacman -S cmake # Clone Emacs repo and checkout `feature/native-comp` $ git clone git://git.savannah.gnu.org/emacs.git -b feature/native-comp $ cd emacs # Build $ ./autogen.sh $ ./configure --with-nativecomp --with-dbus --with-gif --with-png --with-jpeg --with-libsystemd --with-rsvg --with-modules $ make -j$(nproc) At this point you can run ./src/emacs in the emacs directory and viola. It should start up pretty fast. At first I renamed my .emacs.d folder just so I could load up vanilla Emacs and test things out. If you want to use Doom like I am and/or use GCC Emacs fulltime, keep reading.\nAt this point I recommend you uninstall the normal Emacs version if you have it installed and then you can install this package proper.\n# Remove Emacs (optional) $ sudo pacman -R emacs # In Emacs directory $ make install The emacs binary you reference should work just as intended. Now for Doom things are quite simple. If you changed the .emacs.d directory go ahead and change it back. You\u0026rsquo;ll then want to run ./emacs.d/bin/doom upgrade which will ensure you have the latest pinned commits of packages for increased chances of stability and build the packages as required.\nWarning: This can take quite a while.\nIt\u0026rsquo;s fast It\u0026rsquo;s been exceptionally fast for me. I also am using VTerm when I need to do anything in the terminal while working on something and it\u0026rsquo;s a lot faster than in the standard release as well.\nCheers.\n","permalink":"https://jd.codes/posts/trying-gcc-emacs/","summary":"\u003cp\u003eI love Emacs. I\u0026rsquo;ve been using it since late 2017 and have had an on and off again relationship with it. It\u0026rsquo;s a great tool for anyone who likes to tinker around with software. Like any relationship, there are some pain points I have that consistently want to push me away from Emacs, one of which is performance.\u003c/p\u003e\n\u003cp\u003eI\u0026rsquo;ve used \u003ca href=\"https://github.com/hlissner/doom-emacs\"\u003eDoom Emacs\u003c/a\u003e for a really long time and hlissner has done an incredible job of building a fantastic configuration setup, and compared to other configuration frameworks I\u0026rsquo;ve used, Doom is the most performant and most versatile. That being said, no matter how much optimization is done on the configuration side, Emacs can still be extremely slow, especially compared to it\u0026rsquo;s Vim counterpart.\u003c/p\u003e","title":"Trying out GCC Emacs"},{"content":"I recently had to build an interesting model that stored values for a JWT in order to implement an allow list style revocation strategy. After some feedback from another developer it became clear the interface for that model needed to be optimized. Here\u0026rsquo;s a quick description of the \u0026ldquo;behavior\u0026rdquo; of that model:\nAll of the columns are read only after creation It\u0026rsquo;s dependent on a User record assocation - thus requires a validation It has an expiration time that is also stored, but set to a pre-determined amount of time It\u0026rsquo;s jti column value is generated by the model itself since it is a \u0026ldquo;propietary\u0026rdquo; action per record Given this set of behavior we can infer that since the expires_at column and jti are both self generated in the model code, the only attribute required for creation is the associated User record.\nThis made the code for the model drastically simpler and also gave me constraints to artificially impose on the model itself, preventing updates and making attributes read only.\nRails provides a nifty way of doing these things but this principal can be used with any language/framework.\n# Model Class Example class AllowListedToken \u0026lt; ApplicationRecord # ... attr_readonly :jti, :user_id, :expires_at # prevents update calls on these columns EXPIRATION_TIME = 1.day.from_now belongs_to :user ## after_initialize is called when the object is created but before the `INSERT` is called ## allowing for object transformations to take place before the record persists. after_initialize :set_generated_values # ... private def set_generated_values self.jti = JtiGenerator.new.jti self.expires_at = EXPIRATION_TIME end end # Usage user = User.find(id) AllowListedToken.create!(user: user) The moral of the story is to take time to consider how your model should behave and what limitations or defaults you can implement to ensure that the constraints you need to fulfill are fulfilled. This helps ensure the maintainability and simplicity of the model and helps to align the expectated behavior and usage.\n","permalink":"https://jd.codes/posts/thoughts-on-interfaces/","summary":"\u003cp\u003eI recently had to build an interesting model that stored values for a JWT in order to implement an allow list style revocation strategy. After some feedback from another developer it became clear the interface for that model needed to be optimized. Here\u0026rsquo;s a quick description of the \u0026ldquo;behavior\u0026rdquo; of that model:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAll of the columns are read only after creation\u003c/li\u003e\n\u003cli\u003eIt\u0026rsquo;s dependent on a \u003ccode\u003eUser\u003c/code\u003e record assocation - thus requires a validation\u003c/li\u003e\n\u003cli\u003eIt has an expiration time that is also stored, but set to a pre-determined amount of time\u003c/li\u003e\n\u003cli\u003eIt\u0026rsquo;s \u003ccode\u003ejti\u003c/code\u003e column value is generated by the model itself since it is a \u0026ldquo;propietary\u0026rdquo; action per record\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eGiven this set of behavior we can infer that \u003cstrong\u003esince the \u003ccode\u003eexpires_at\u003c/code\u003e column and \u003ccode\u003ejti\u003c/code\u003e are both self generated in the model code, the only attribute required for creation is the associated \u003ccode\u003eUser\u003c/code\u003e record.\u003c/strong\u003e\u003c/p\u003e","title":"Thoughts on Interfaces for Models"},{"content":"Run Command is a really nifty Emacs package that abstracts away running arbitrary shell commands into a nice ivy or helm (or other completion frameworks) frontend. I saw a few of the examples and immediately got an idea for using it to build an RSpec watch mode. It\u0026rsquo;s a tiny optimization to my work flow as re-running the test command is just a few keystrokes in of itself, but getting automated feedback means I get to focus on other things while writing tests.\nThe Config The config is rather simple and only requires a couple of things to be setup. The biggest dependency is on an external tool called `entr` which watches for file changes and will re-run a command if it detects a change.\nRequirements Emacs run-command installed projectile installed System entr installed Recipes Run Command is built on top of custom recipes you create in your config. These recipes define a list of similar functionality and each recipe is added to the recipe list run-command-recipes. Here is my recipe for RSpec:\n(defun jd/shell-command-maybe (exe \u0026amp;optional paramstr) \u0026#34;run executable EXE with PARAMSTR, or warn if EXE\u0026#39;s not available; eg. (jd/shell-command-maybe \\\u0026#34;ls\\\u0026#34; \\\u0026#34;-l -a\\\u0026#34;)\u0026#34; (if (executable-find exe) t nil)) (defun jd/get-current-line-number () \u0026#34;Gets current line number based on `(what-line)` output. I\u0026#39;m sure there\u0026#39;s a better way to do this but it\u0026#39;s what I got.\u0026#34; (car (last (split-string (what-line))))) (defun run-command-recipe-rspec () (list (list :command-name \u0026#34;RSpec Run File\u0026#34; :command-line (format \u0026#34;bundle exec rspec %s\u0026#34; (buffer-file-name)) :working-dir (projectile-project-root) :display \u0026#34;Run RSpec on file\u0026#34;) (list :command-name \u0026#34;Rspec Run Single\u0026#34; :command-line (format \u0026#34;bundle exec rspec %s:%s\u0026#34; (buffer-file-name) (jd/get-current-line-number)) :working-dir (projectile-project-root) :display \u0026#34;Run RSpec on single block\u0026#34;) (when (jd/shell-command-maybe \u0026#34;entr\u0026#34;) (list :command-name \u0026#34;RSpec File Watch Mode\u0026#34; :command-line (format \u0026#34;find %s | entr -c bundle exec rspec %s\u0026#34; (buffer-file-name) (buffer-file-name)) :working-dir (projectile-project-root) :display \u0026#34;Rerun rspec on file on save\u0026#34;)) (when (jd/shell-command-maybe \u0026#34;entr\u0026#34;) (list :command-name \u0026#34;Rspec Block Watch Mode\u0026#34; :command-line (format \u0026#34;find %s | entr -c bundle exec rspec %s:%s\u0026#34; (buffer-file-name) (buffer-file-name) (jd/get-current-line-number)) :working-dir (projectile-project-root) :display \u0026#34;Rerun rspec on block on save\u0026#34;)))) The run command-recipe- name for the function is just a convention. That part of the name gets removed when run command lists your recipes. There\u0026rsquo;s a couple of utility functions in there, namely jd/shell-command-maybe that is important. The implementation of the watch mode for RSpec requires that entr be installed on the system. I also thought it would be useful at some point in the future so I went ahead and abstracted it into my own namespaced function. If entr is not present on your machine the watch mode recipes will not be in the lists provided by run command during use. jd/get-current-line-number is also just a wrapper around what-line parsing. I\u0026rsquo;m sure there\u0026rsquo;s a dedicated function to just get the number but I couldn\u0026rsquo;t find it fast enough.\nThis works pretty well and does what it\u0026rsquo;s intended. It allows me to run a file or block in \u0026ldquo;watch mode\u0026rdquo; while I\u0026rsquo;m developing or just run the spec with a few simple commands. Running M-x run-command will kick start your completion framework (which is auto detected) with a list of all your recipes. I\u0026rsquo;ve bound it to SPC r c. SPC r has become my default keymap as it\u0026rsquo;s not used by anything from what I can tell.\nRun Command Configuration According to the Run Commmand documentation it\u0026rsquo;s recommended to use M-x customize command in order to add recipes to the list however, Doom Emacs does not support the custom interface, so I opted in to just set it manually:\n(setq run-command-recipes \u0026#39;(run-command-recipe-rspec)) Ways to Improve There are a few things I can do to improve this configuration and make it work more broadly and more like jest works for javascript. Using projectile-rails to find the matching spec file would be a good way to use it to. So if I\u0026rsquo;m editing app/models/user.rb I could make RSpec run a specific spec in \u0026ldquo;watch\u0026rdquo; mode to make TDD a little quicker. If I do that I\u0026rsquo;ll update this post with the relevant code to do so.\nConclusion I don\u0026rsquo;t know A LOT of elisp but after troubleshooting and fumbling around, figuring it out was pretty fun. It\u0026rsquo;s also yields a high reward as I get to use what I develop every day.\n","permalink":"https://jd.codes/posts/run-command/","summary":"\u003cp\u003e\u003ca href=\"https://github.com/bard/emacs-run-command\"\u003eRun Command\u003c/a\u003e is a really nifty Emacs package that abstracts away running arbitrary shell commands into a nice ivy or helm (or other completion frameworks) frontend. I saw a few of the examples and immediately got an idea for using it to build an RSpec watch mode. It\u0026rsquo;s a tiny optimization to my work flow as re-running the test command is just a few keystrokes in of itself, but getting automated feedback means I get to focus on other things while writing tests.\u003c/p\u003e","title":"Using Run Command in Emacs for RSpec Watch Mode"},{"content":"There\u0026rsquo;s a quick and easy way to satisfy client side routing in a Rails application. Rails will automatically try to resolve it\u0026rsquo;s routing on the server side and throw an immediate 404 if no valid pages exist. Since my main application at work is a React SPA I needed a way to resolve routes to the client and not let them get caught by the server and throw a 404. The (/*path) method route \u0026lsquo;helper\u0026rsquo; allows through any route so it can then be handled elsewhere.\nget \u0026#39;/app(/*path)\u0026#39;, to: \u0026#39;my_app#index\u0026#39; So anytime you visit say /app/123 the /app route will correctly be resolved to the MyAppController#index method and any other parameters will be left for you to parse and decide what to do with on the client side.\nYou can optionally add constraints to ensure that the default Rails behavior kicks in if the route is in fact invalid.\nget \u0026#39;/app(/*path)\u0026#39;, to: \u0026#39;my_app#index\u0026#39;, constraints: {path: /(profile|home)\\/.*/} This makes /app/home and /app/profile completely valid, and passes Rails routing checks, but anything else like /app/message would be invalid to Rails and thus trigger the Rails server side 404 error.\nUsing constraints is great if you have very simple routing, that doesn\u0026rsquo;t use any dynamic arguments, like an ID but that\u0026rsquo;s a very tight use case. Normally I\u0026rsquo;d recommend against this because you\u0026rsquo;ll have to maintain your routes in 2 places, routes.rb and your client code. It\u0026rsquo;s very easy to handle 404 errors with something like `react-router` so that would probably be more preferable long term.\n","permalink":"https://jd.codes/posts/client-routes-rails/","summary":"\u003cp\u003eThere\u0026rsquo;s a quick and easy way to satisfy client side routing in a Rails application. Rails will automatically try to resolve it\u0026rsquo;s routing on the server side and throw an immediate 404 if no valid pages exist. Since my main application at work is a React SPA I needed a way to resolve routes to the client and not let them get caught by the server and throw a 404. The \u003ccode\u003e(/*path)\u003c/code\u003e method route \u0026lsquo;helper\u0026rsquo; allows through any route so it can then be handled elsewhere.\u003c/p\u003e","title":"Resolving client side routes in Rails"},{"content":"I\u0026rsquo;ve used Docker quite a bit but I haven\u0026rsquo;t really dived into configuring my own dockerized app. I recently needed to build a quick proof of concept with a React app and needed to share it easily without worrying too much about build dependencies or anything of the sort. So here\u0026rsquo;s a quick guide on dockerizing an app created with create-react-app.\nThe guide I\u0026rsquo;ll assume you already have a CRA app created. If you\u0026rsquo;ve never used create-react-app, I recommend checking out the docs here. This tutorial will work from the top down and both the Dockerfile and docker-compose.yml files will be at the end in full.\nCreate a Dockerfile at the root of your application. First we need to figure out what base image we\u0026rsquo;re going to use. I\u0026rsquo;m biased towards the Alpine based ones cause those are lite and quick to spin up. So we\u0026rsquo;ll use node:current-alpine3.10. This tells Docker to pull the current alpine 3.10 image from Dockerhub.\nFROM node:current-alpine3.10 Next we\u0026rsquo;ll need to set the working directory, where the app will be \u0026ldquo;put\u0026rdquo;, dependencies will be installed in, and our run command to run.\nWORKDIR /app We\u0026rsquo;ll setup the PATH to ensure that the `node_module` binaries are accessible globally.\nENV PATH /app/node_modules/.bin:$PATH Next is probably the part that confused me the most when working with Docker. We have to copy over critical files to ensure that the container knows where to get our dependencies and how to build them all. This step needs to be done explicitely and not make use of a volume due to the fact that it\u0026rsquo;ll overwrite dependencies if you\u0026rsquo;re not careful.\nCOPY package.json ./ COPY yarn.lock ./ This ensure that just the dependency and depenency lock file are both available to the container. We could just copy over the node_modules folder from our local machine into the container, but it\u0026rsquo;s likely that something will break cause sometimes certain modules are built differently for different targets.\nNext we\u0026rsquo;ll tell the container to install the dependencies.\nRUN yarn install Finally we\u0026rsquo;ll tell the container to execute our build/run command. This command is important cuase it represents the \u0026ldquo;main\u0026rdquo; process for our image which is why this is CMD instead of RUN.\nCMD [\u0026#34;yarn\u0026#34;, \u0026#34;start\u0026#34;] Before we move on we\u0026rsquo;ll need to go ahead and setup the docker-compose.yml and .dockerignore files to ensure everything runs as inteneded. The convience of docker-compose is that you don\u0026rsquo;t have to pass 100 args to the Docker CLI.\nLets setup the .dockerignore first.\nnode_modules build .dockerignore Dockerfile This ensures that Docker doesn\u0026rsquo;t use the node_modules or build directory in the volume we create in the docker-compose.yml. Not ignoring the node_modules directory will result in our previously installed dependencies being overwritten by what\u0026rsquo;s on our local machine. So lets make sure the container uses the dependencies it has.\nOk now for the last bit, the docker-compose file. Here we declare a version, the service/container_name and then pass the actual configuration. We need to tell docker to use the current directory as it\u0026rsquo;s main \u0026ldquo;context\u0026rdquo; and subsequently use the Dockerfile in that directory.\nversion: \u0026#39;3.3\u0026#39; services: wc-concept: container_name: wc-auth-concept build: context: . dockerfile: Dockerfile Now we have to define Volumes. Volumes can be used for persistant reference between Docker container builds. Since each container is meant to be spun up and destroyed with no lingering side effects, volumes represent a way to tell Docker about persistant information. This can be a database file or in our case, the code. This tells docker to reference the code in . which is our local project directory as the code in /app which is the directory of the application code in the container. We also add a node_modules volume to ensure we don\u0026rsquo;t have to constantly download them whenever the container spins up.\nversion: \u0026#39;3.3\u0026#39; services: wc-concept: container_name: wc-auth-concept build: context: . dockerfile: Dockerfile volumes: - \u0026#39;.:/app\u0026#39; - \u0026#39;/app/node_modules\u0026#39; ports: - 3001:3000 environment: - CHOKIDAR_USEPOLLING=true There\u0026rsquo;s 2 more things in the above example. First we define the port to expose out of the container and forward it to a port on our local machine. My project runs on 3000 by default, which is what Docker knows about. We\u0026rsquo;ll expose port 3000 from the container and forward it to port 3001 on our local machine. The format is local_port:container_port. Finally we tell Docker to poll the volumes for changes so we can take advantage of webpack-dev-server or hot reloading.\nNow you can just run docker-compose up, with the optional -d flag which is \u0026ldquo;detached\u0026rdquo; mode and it will run in the background instead of outputting to the terminal, and visit localhost:3001.\nHere\u0026rsquo;s all the code for all 3 files in one place for reference.\nDockerfile\nFROM node:current-alpine3.10 WORKDIR /app ENV PATH /app/node_modules/.bin:$PATH COPY package.json ./ COPY yarn.lock ./ RUN yarn install CMD [\u0026#34;yarn\u0026#34;, \u0026#34;start\u0026#34;] .dockerignore\nnode_modules build .dockerignore Dockerfile docker-compose.yml\nversion: \u0026#39;3.3\u0026#39; services: wc-concept: container_name: wc-auth-concept build: context: . dockerfile: Dockerfile volumes: - \u0026#39;.:/app\u0026#39; - \u0026#39;/app/node_modules\u0026#39; ports: - 3001:3000 environment: - CHOKIDAR_USEPOLLING=true This worked just fine for my purposes. I\u0026rsquo;m sure there\u0026rsquo;s more to be done to make this Docker configuration way more robust. Enjoy.\n","permalink":"https://jd.codes/posts/dockerizing-react/","summary":"\u003cp\u003eI\u0026rsquo;ve used Docker quite a bit but I haven\u0026rsquo;t really dived into configuring my own dockerized app. I recently needed to build a quick proof of concept with a React app and needed to share it easily without worrying too much about build dependencies or anything of the sort. So here\u0026rsquo;s a quick guide on dockerizing an app created with create-react-app.\u003c/p\u003e\n\u003ch2 id=\"the-guide\"\u003eThe guide\u003c/h2\u003e\n\u003cp\u003eI\u0026rsquo;ll assume you already have a CRA app created. If you\u0026rsquo;ve never used create-react-app, I recommend checking out the docs \u003ca href=\"https://reactjs.org/docs/create-a-new-react-app.html\"\u003ehere\u003c/a\u003e. This tutorial will work from the top down and both the \u003ccode\u003eDockerfile\u003c/code\u003e and \u003ccode\u003edocker-compose.yml\u003c/code\u003e files will be at the end in full.\u003c/p\u003e","title":"Dockerize Create React App"},{"content":"As an engineering team grows it becomes imparitive that the leadership among that team grows to scale as well. We all know that organizing work on a product is difficult, but the organization of the engineering team specifically plays the most significant role in the overall developer experience. My personal experience up till this point has been to work mostly on projects or features either by myself or with a single other more senior developer. Over the last quarter I was given the temporary title of technical lead on a project with 4 other developers, which presented an extremely difficult learning opportunity for me.\nMy time as a developer has been marked by taking on research or projects on my own. I spent a good three months managing a set of contractors and then embarked on mostly solo projects. Organizing work for fully integrated team waa something completely foreign to me. This write up simply serves as a way to help solidfy some of what I learned and hopefully help other people in similar situations.\nTheorizing Architecture is a Skill The project I undertook this quarter was not a large full stack architectural effort, instead, it focused mainly on the frontend (React) of our application. We try to be very intentional about how we build components and UI elements to ensure that what needs to be reusable, can be, and that larger page or template type components recieve a quality composition focused structure for easy maintenance. This meant that embarking on a greenfield feature, required some forethought on how the different component API\u0026rsquo;s would work together and how we would handle the required data to accomplish the overall goal of what we wanted to build.\nHerein lies the challenge: coming up with an architectural plan and executing it over the course of weeks.\nIn the past, my tendency was to always do \u0026ldquo;proof-of-concepts\u0026rdquo; that would more often than not, just turn into the code that would actually be used. I never really had to decide on something prior to writing anything and just hoped that it would work. Fairly early on in the project, I had the \u0026ldquo;birds eye view\u0026rdquo; of how this whole feature could work. I took my \u0026ldquo;birds eye view\u0026rdquo; solution and organized the work as such. Our sprints, stages of completion, and deadlines were all built around my rough solution and tickets were broken down and written to accomodate small units of that very idea.\nThis resulted in a large amount of insecurity in how I was leading the team. Why? I didn\u0026rsquo;t really focus on building a complete, very thorough plan, I just maintained my own rough idea. Four developers working through a plan really puts to the test the quality of the plan and ultimately the experience those developers have while executing it. When areas came up that I had inevitably overlooked, we had to make pivots, or have short pairing sessions to help determine the most optimal solution to whatever it was. Pivots to some degree are inevitable in building software, however, these seemed very avoidable as if one or two more hours of thinking would have surfaced these gaps at the beginning.\nThis, at least in part, is what I think helps to define a good senior developer, who not only advocates for quality practices, but also for a good experience for all the developers working around them. Their ability to come up with a detailed plan, minimizing the risk of pivots during a project, and having a framework for dealing with those situations will ensure that the developers working along side them have the best experience possible. Great experiences like this, free up developers to come up with more innovative solutions or to collaborate more on an idea to make things better for the long term.\nMy biggest take away from this was to spend more time planning out how something was to be built do my best proving out examples of the more complex bits and pieces of the code to help deter unknowns.\nDefine Success \u0026amp; Failure Early I think there comes a point in a lot of software companies where data becomes a huge contributor to the products over all direction. Once a business establishes itself it begins the process of making everything better and understanding it\u0026rsquo;s users is finer detail. This very quickly builds the case for proper and established baselines as features are developed. The project we worked on was not large, but it had strong potential to either damage our user conversion/retention rates or improve them. We failed to really understand this potential early on, and failed to understand what \u0026ldquo;failing\u0026rdquo;, or \u0026ldquo;success\u0026rdquo; for that matter, means. This wasn\u0026rsquo;t any one persons fault, it was just a gap the entire team contributed to.\nIt wasn\u0026rsquo;t till about a month into the project that we began discussing a roll out plan. This lead to discussions of the \u0026ldquo;risks\u0026rdquo; involved in changing such a critical piece of our user experience. It was then that we began to dig into the data to try to understand that risk as much as possible. Getting to this point was a good thing and meant that the team was growing more mature, however, this realization came very late. It resulted in a fairly large pivot and a lot of time spent researching how to circumvent certain hurtles in the process.\nUnderstanding risks, impacts, and how things will be measured early ensures that development goes smoothly and the smallest units of work shippable can be completed quickly, in a quick agile-esque cycle. This also helps to guide the later stages of a project and gives you a steady framework for adjusting to pivots that arise during the development of a feature.\n","permalink":"https://jd.codes/posts/organizing-work/","summary":"\u003cp\u003eAs an engineering team grows it becomes imparitive that the leadership among that team grows to scale as well. We all know that organizing work on a product is difficult, but the organization of the engineering team specifically plays the most significant role in the overall developer experience. My personal experience up till this point has been to work mostly on projects or features either by myself or with a single other more senior developer. Over the last quarter I was given the temporary title of technical lead on a project with 4 other developers, which presented an extremely difficult learning opportunity for me.\u003c/p\u003e","title":"Organizing Work is Hard"},{"content":" This is a repost of my original 2017 blog post. It maybe a little outdated.\nI recently got my first developer job as a Quality Assurance Engineer at a company called Modern Message and I want to share a few tips on things I did to help me eventually land this job.\nI\u0026rsquo;m a student at Bloc which is a remote, self-paced developer bootcamp. I managed to pick their longest track called the Software Engineering Track.\nIt\u0026rsquo;s a Numbers Game When I was searching for a job, I assumed 5% of my applications would result in a job. That\u0026rsquo;s a conservative number I think, I don\u0026rsquo;t even remember where I got that from, but it gave me a goal. So let\u0026rsquo;s assume, that stat is correct.\nIf 5% of your applications result in a job, lets say 20% actually call you after applying. This is great news. That\u0026rsquo;s 20 out of 100 applications. That\u0026rsquo;s 20 opportunities. If your working hard, just 1 of those opportunities is enough.\nWhile I\u0026rsquo;m sure that the actual stats are much different based on a very large number of factors, that stat still is some number though, which means each application you send out, gets you one step closer to the employer that\u0026rsquo;ll make you an offer. Keep this at the forfront of your mind, cause finding your first gig can be real up hill struggle. Just remember, each place you apply, increases your chances of getting an offer. It may seem basic, but it kept me going after sending out my 120th application.\nThe Industry There\u0026rsquo;s a few things that I felt like companies were really looking for when it came to finding candidates to work for them:\nIndustry Fit Culture Fit Technical Fit Industry Fit A business wants to know you\u0026rsquo;re passionate about what you\u0026rsquo;re doing. That you\u0026rsquo;re keeping up with issues/news about the software industry. There\u0026rsquo;s plenty of places to get this info like HackerNews or Reddit. You can easily see trends and see the focus of people in the industry to gauge better what you should be learning about and what you can talk about in interviews.\nES6 was a new thing when I was hunting, so being able to at least discuss it, even at just a high level, benefitted me in a couple interviews.\nCulture Fit This is huge. Most software companies understand that programming isn\u0026rsquo;t a science where you hold all the knowledge in your heard about everything. Very few fields are that way. What\u0026rsquo;s important is that you show that you\u0026rsquo;re always willing to learn and accept feedback. This is especially true for junior level developers. Showing that you take initiative to grow in your field, and you can take criticism well will help take you a long way with potential employers.\nTechnical Fit This is the most obvious, but should definitely still be stated. Learn to code. You don\u0026rsquo;t have to know everything, but understand the fundamentals really well. If you\u0026rsquo;re studying Ruby like I did, make it a point to study up on topics like OOP, inheritence, and even going deep-ish on a framework. All these things will just make you a better programmer, but they\u0026rsquo;ll also give you things to speak to in interviews.\nIt\u0026rsquo;s important that you just build things also. This gives you practice in integrating technologies, thinking about planning, architecture and system design. Just build something from scratch. If you\u0026rsquo;re not sure what to build, build a clone of a popular website. I think building a Pinterest clone was the first project I ever did. This will also give you stories to talk about in interviews.\nGetting Started I started my job search about a month into Bloc. I didn\u0026rsquo;t know much and had only built very small applications by following tutorials and stuff, but my mentor encouraged me to just start applying. I initiated my first iteration of a blog, got my LinkedIn all nice and up to date and started the long process.\nThe easiest thing to do when starting is to just sit down and clean up your LinkedIn.\nI made sure everything was up to date. I made sure my skills reflected what I was studying (Rails, Javascript, Ruby, SQLite etc\u0026hellip;). I updated my profile picture to something that I looked relatively professional in but not \u0026ldquo;suit and tie\u0026rdquo; professional.\u0026quot; Mostly just basic stuff.\nI then focused a lot of time and effort on my resume. I had it reviewed by peers, mentors, and anyone I spoke to that had seen it basically. I used Creddle for my first iteration before moving to something custom. Here\u0026rsquo;s a few things to make sure of:\nOnly ONE page for my resume. I made sure I explained actual accomplishments under my previous employment descriptions. I put my skill list at the very top. (A lot of recruiters for companies aren\u0026rsquo;t that technical, so they are using template matching. I made sure the first thing htey saw on my resume were the words that would match the template they got from the engineering department). I put references on there as well as links to my Github and website. I listed \u0026ldquo;potential weak points\u0026rdquo; at the bottom of the resume, decreasing the chances it would get focused on. A resume MUST be clear and concise, only focusing on whats important, not useless details about the Chess Club you were in in highschool.\nThis is the big point.\nNetwork Network, Network, Network. I can\u0026rsquo;t say it enough. I\u0026rsquo;m not the most out going person in the world, I can even be socially awkward in odd situations. But I had to really work at that. Mostly by just practicing what I would say, or listing out the questions I would ask before the interaction. A whole blog could be devoted to this I think.\nGo to Meet Ups\nAt Meet Ups you can engage with people you already have a common interest in, making initiating conversation a tad bit easier. I recommend coming up with 3-4 questions you\u0026rsquo;ll ask upon meeting people, like:\nWhere do you work? How long have you been programming with x technology? How\u0026rsquo;d you learn? What challenges are you encountering at work? I did this to almost every person I met at Meet Ups.\nCoffee\nI asked about 8 developers for coffee in my job search. Through that I was able to get to know them, pick their brains and learn. Another engineer, Haseeb Qureshi has a great blog on this whole topic, especially networking. If you\u0026rsquo;re still reading this and not his blog (which is totally the wrong move by the way) here\u0026rsquo;s what I did.\nI went to a Meet Up and asked one of the obvious experienced engineers out for coffee. He was very kind and obliged. I paid, and got to sit down with him for almost 2 hours just picking his brain. At the end I asked, \u0026ldquo;I\u0026rsquo;m really trying to get a job as a developer using x technology, mostly right now I\u0026rsquo;m just trying to get to know people and learn from them. Do you have someone else you can reccommend I talk to?\u0026rdquo;\nI\u0026rsquo;ve heard of these leading to job offers and such, but I ended up just meeting 8 good solid, very nice engineers. It turns out engineers are just people who like to talk about what they do, like most people do. This not only brought a level of comfort meeting new people, but also helped me to learn about the industry in my area.\nPractice There\u0026rsquo;s a couple of things to practice when looking for developer job.\nWhiteboarding Answering Questions Whiteboarding This is some what of a controversial subject. It\u0026rsquo;s good to go into it with the mentaility of solving problems instead of actually coding. I did several whiteboarding interviews that involved dealing with collisions in hashes, implementing a method on a string like .reverse, and taking an algorithm and making it faster. All these are skills that can be practiced easily, but there\u0026rsquo;s a method which will give you great results.\nFind the problem CodeWars Cracking the Coding Interview Exercism.io Speak out loud as you try to solve the problem. Ask yourself questions about the data. ALWAYS. Ask yourself about output. Explain your thought process and theory before writing one line of code. Code and explain the solution Using these steps will give you good practice for what whiteboarding is like. Most of the hiring managers I\u0026rsquo;ve spoken too, don\u0026rsquo;t emphasize the right answer as much as being able to solve the problem and communicate the idea behind the solution.\nAnswering Questions It\u0026rsquo;s definitely in your best interest to practice answering questions about your coding skills. One of the questions I frequently rehearsed was \u0026ldquo;what\u0026rsquo;s a big challenge that you\u0026rsquo;ve experienced and how did you tackle that?\u0026rdquo; I came up with both a \u0026ldquo;soft-skills\u0026rdquo; answer and a \u0026ldquo;technical-skills\u0026rdquo; answer to that question. I rehearsed the answer over and over so I didn\u0026rsquo;t have to think about it much. I made it clear and concise, with enough detail to make sense, but not enough that I bored the interviewer to death. I\u0026rsquo;m sure a Google search can turn up hundreds of answers for questions that\u0026rsquo;ll be asked in an interview. Google it and come up with your answers before hand.\nCue the Offer I was hell bent on meeting every Ruby engineer in the DFW area. I would frequently skip the local \u0026ldquo;hacknights\u0026rdquo; as I was intimidated by potentially letting a senior engineer peak at my super lame code. Thankfully, one night when I was supposed to stay home, I randomly decided to go to the hacknight. I went and met the CTO of the company I\u0026rsquo;d later get an offer from.\nI think just personality wise we got a long really well and hit it off. I\u0026rsquo;m sure that building this level of rapport was a BIG part of how I landed the job. After talking about random things like (Minecraft), I asked his (and the other devs there that would later become collegues) advice on finding a Jr Developer rails job in Dallas. This lead to a great conversation about the open positions at Modern Message and I got an offer 2 1/2 weeks later.\nI ultimately think that it was because I \u0026ldquo;practicing\u0026rdquo; building rapport with those other engineers that I was able to build rapport with Daniel and the other developers which ended up increasing my chances of getting the job.\nIt\u0026rsquo;s a Grind It\u0026rsquo;s definitely a grind. My thoughts go back to my days of playing World of Warcraft\u0026hellip; Anyway. I have a pending post I\u0026rsquo;m working on about my actual job search and how I organized it using a Trello board. This post is already too long.\nGood luck on your job search and remember, network.\n","permalink":"https://jd.codes/posts/breaking-into-tech/","summary":"\u003cblockquote\u003e\n\u003cp\u003eThis is a repost of my original 2017 blog post. It maybe a little outdated.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eI recently got my first developer job as a Quality Assurance Engineer at a company called \u003ca href=\"http://modernmsg.com\"\u003eModern Message\u003c/a\u003e and I want to share a few tips on things I did to help me eventually land this job.\u003c/p\u003e\n\u003cp\u003eI\u0026rsquo;m a student at \u003ca href=\"http://bloc.io\"\u003eBloc\u003c/a\u003e which is a remote, self-paced developer bootcamp. I managed to pick their longest track called the Software Engineering Track.\u003c/p\u003e","title":"Tips for Breaking into the Tech Industry"}]