<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mark Hesketh</title>
    <description>The latest articles on DEV Community by Mark Hesketh (@markhesketh).</description>
    <link>https://dev.to/markhesketh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F288966%2F86d26a8c-fbab-490e-b61d-714fbfb4823b.jpeg</url>
      <title>DEV Community: Mark Hesketh</title>
      <link>https://dev.to/markhesketh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/markhesketh"/>
    <language>en</language>
    <item>
      <title>Introducing: Write Good, an Obsidian plugin</title>
      <dc:creator>Mark Hesketh</dc:creator>
      <pubDate>Mon, 10 Mar 2025 09:40:00 +0000</pubDate>
      <link>https://dev.to/markhesketh/introducing-write-good-an-obsidian-plugin-30l3</link>
      <guid>https://dev.to/markhesketh/introducing-write-good-an-obsidian-plugin-30l3</guid>
      <description>&lt;p&gt;Last week, I built '&lt;a href="https://github.com/markahesketh/write-good-obsidian/" rel="noopener noreferrer"&gt;Write Good&lt;/a&gt;', an Obsidian plugin to help improve writing style, built on top of a package of the same name, &lt;a href="https://github.com/btford/write-good" rel="noopener noreferrer"&gt;Write Good by Brian Ford&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This week, it got approved by the Obsidian team and is now &lt;a href="https://obsidian.md/plugins?search=write%20good" rel="noopener noreferrer"&gt;listed as a community plugin&lt;/a&gt;. You can also install it from within Obsidian itself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqlsxtdcznc7f3mgsdp1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqlsxtdcznc7f3mgsdp1.png" alt="Write Good Installer from the Obsidian plugin directory" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It highlights issues and suggests improvements as you type, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Passive voice&lt;/li&gt;
&lt;li&gt;Complex phrases&lt;/li&gt;
&lt;li&gt;weasel' words&lt;/li&gt;
&lt;li&gt;etc &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I built it for myself as while a VS Code extension already exists, I use Obsidian for my note-taking and wanted to port these features across.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F486pyze7rtzmmobehmgh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F486pyze7rtzmmobehmgh.gif" alt="Write Good Obsidian plugin in action" width="516" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From a technical standpoint, I built it using TypeScript while leaning heavily on GitHub Copilot's new agent mode to figure out the gritty details of piecing together an Obsidian plugin.&lt;/p&gt;

&lt;p&gt;You can install it today by searching for 'Write Good' within Obsidian's community plugins or via &lt;a href="https://obsidian.md/plugins?id=write-good" rel="noopener noreferrer"&gt;Obsidian's plugin website&lt;/a&gt;. Its also &lt;a href="https://github.com/markahesketh/write-good-obsidian/" rel="noopener noreferrer"&gt;open source&lt;/a&gt;, of course.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/markahesketh/write-good-obsidian/" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://obsidian.md/plugins?search=write%20good" rel="noopener noreferrer"&gt;Plugin on the Obsidian plugin directory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/btford/write-good" rel="noopener noreferrer"&gt;Write Good by Brian Ford&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>writing</category>
      <category>showdev</category>
      <category>opensource</category>
      <category>obsidian</category>
    </item>
    <item>
      <title>Git tips and tricks I use every day</title>
      <dc:creator>Mark Hesketh</dc:creator>
      <pubDate>Sun, 09 Mar 2025 12:09:00 +0000</pubDate>
      <link>https://dev.to/markhesketh/git-tips-and-tricks-i-use-every-day-ibc</link>
      <guid>https://dev.to/markhesketh/git-tips-and-tricks-i-use-every-day-ibc</guid>
      <description>&lt;p&gt;I am by no means an expert, but I've been using Git for years at this point. Over that time I've picked up some tips, tricks and habits I use daily that I think could help you too.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Switching back to the previous branch
&lt;/h2&gt;

&lt;p&gt;I swap between main/master, my feature branch and back to main/master constantly. Rather than typing out the name of branch you want to switch to, Git provides a nice alias to switch back to your previous branch:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This might look familiar as it mirrors &lt;code&gt;cd -&lt;/code&gt; which navigates to your previous directory in the terminal in the same way.&lt;/p&gt;

&lt;p&gt;I use this all the time to ping pong between main/master and whatever feature branch I'm working on. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git branch
* main

$ git checkout -b feature-branch
Switched to branch 'feature-branch'

$ git switch -
Switched to branch 'main'

$ git switch -
Switched to branch 'feature-branch'

$ git switch -
Switched to branch 'main'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Pushing to a remote branch of the same name
&lt;/h2&gt;

&lt;p&gt;When working on a feature branch you'll often need to push your changes to a new remote branch before creating a PR. Typically, the remote branch has the same name as your local.&lt;/p&gt;

&lt;p&gt;Its tedious having to copy/paste (or god forbid type out) your branch name. What if there was a better way?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git push origin HEAD

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

&lt;/div&gt;



&lt;p&gt;It pushes and creates a branch on the remote using the same name as your local branch. It doesn't matter how long or tedious your branch name is. Using the &lt;code&gt;HEAD&lt;/code&gt; alias will pick it up from your local branch, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git checkout -b feature-branch
Switched to a new branch 'feature-branch'

$ git push origin HEAD
...
To github.com:company-name/project-name.git
 * [new branch]      HEAD -&amp;gt; feature-branch

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

&lt;/div&gt;



&lt;p&gt;I find this useful as at work we have conventions for branch names. They're often long and include ticket numbers, for example &lt;code&gt;feature/123456/great-new-feature-that-will-triple-revenue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By using &lt;code&gt;HEAD&lt;/code&gt; I never have to care about the branch name. It works every time. In fact, I use an alias of &lt;code&gt;git poh&lt;/code&gt; on all my feature branches when pushing.&lt;/p&gt;

&lt;p&gt;Speaking of aliases...&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Git aliases
&lt;/h2&gt;

&lt;p&gt;Git allows you to specify aliases to effectively create your own Git commands.&lt;/p&gt;

&lt;p&gt;You probably have some shell aliases set up already, you might even have some aliases specific to Git. I prefer to use git aliases rather than shell aliases as they're scoped to Git and feel like real Git commands.&lt;/p&gt;

&lt;p&gt;To create one open up &lt;code&gt;~/.gitconfig&lt;/code&gt; and add your commands under the &lt;code&gt;[alias]&lt;/code&gt; section like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
[alias]
    deploy = push production master
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a new command &lt;code&gt;git deploy&lt;/code&gt; which is as if you wrote &lt;code&gt;git push production master&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I have a bunch of these and I've &lt;a href="https://gist.github.com/markahesketh/f340af3f8dd87ec12c460e3f2c050ca4" rel="noopener noreferrer"&gt;published my .gitconfig to as a gist&lt;/a&gt; if you're looking for some inspiration. Some of my favourites are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Cleans your working copy, resetting everything to the previous commit creating a blank slate. Stolen from Jeffrey Way 
nah = "!f() { git clean -d -f; git reset --hard; }; f"

# git status, but shorter
st = status -s

# Removes the last commit, but keeps the changes so you can make any changes or deletions
undo = reset HEAD~1 --mixed

# Unstages any changes
unstage = restore --staged

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Open the current project in GitHub
&lt;/h2&gt;

&lt;p&gt;A couple of shell aliases (not git aliases) I like are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ghu&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These open up the current directory's project in GitHub in the browser.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gh&lt;/code&gt; opens the &lt;em&gt;origin&lt;/em&gt; remote and &lt;code&gt;ghu&lt;/code&gt; opens the &lt;em&gt;upstream&lt;/em&gt; remote, depending on whether I'm working on a fork or not.&lt;/p&gt;

&lt;p&gt;I find these useful when I'm working on a project and want to take a look at the GitHub issues or PRs.&lt;/p&gt;

&lt;p&gt;If you'd like to use them too, open up your shell's config or alias file (&lt;code&gt;~/.zshrc&lt;/code&gt;/&lt;code&gt;~/.bashrc/etc)&lt;/code&gt; and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
function gh() {
    local repo_url=`git remote get-url origin | sed -e 's/git@//' -e 's/.git//' -e 's/:/\//'`
    open "https://$repo_url"
}

function ghu() {
    local repo_url=`git remote get-url upstream | sed -e 's/git@//' -e 's/.git//' -e 's/:/\//'`
    open "https://$repo_url"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>git</category>
      <category>productivity</category>
      <category>github</category>
      <category>programming</category>
    </item>
    <item>
      <title>Introducing: rustywind-ruby</title>
      <dc:creator>Mark Hesketh</dc:creator>
      <pubDate>Mon, 03 Feb 2025 23:02:00 +0000</pubDate>
      <link>https://dev.to/markhesketh/introducing-rustywind-ruby-5d0h</link>
      <guid>https://dev.to/markhesketh/introducing-rustywind-ruby-5d0h</guid>
      <description>&lt;p&gt;I'm thrilled to share my first published Ruby gem: &lt;a href="https://rubygems.org/gems/rustywind-ruby" rel="noopener noreferrer"&gt;rustywind-ruby&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Its a wrapper for &lt;a href="https://github.com/avencera/rustywind" rel="noopener noreferrer"&gt;RustyWind&lt;/a&gt;, a rust-based CLI utility for sorting Tailwind CSS classes. This makes it easier to use in Ruby and Rails #nobuild projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;I've been using Tailwind CSS for a while and RustyWind keeps my utility classes predictable.&lt;/p&gt;

&lt;p&gt;Unfortunately, RustyWind is not available through RubyGems or bundler. Tailwind CSS itself recommends Prettier, an npm package, to sort CSS classes. Since I've been embracing importmaps and #nobuild recently this was a problem.&lt;/p&gt;

&lt;p&gt;As RustyWind is a small standalone binary, I used the &lt;code&gt;bin/setup&lt;/code&gt; script to import it. This worked, but it didn't feel great having a dependency outside of my Gemfile.&lt;/p&gt;

&lt;p&gt;I decided to follow the lead of the &lt;a href="https://github.com/flavorjones/tailwindcss-ruby" rel="noopener noreferrer"&gt;tailwind-ruby&lt;/a&gt; project, building a small wrapper around the RustyWind binaries. This allows bundler and your Gemfile to manage it like any other dependency.&lt;/p&gt;

&lt;p&gt;It was also the perfect scope for my first gem.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use it
&lt;/h2&gt;

&lt;p&gt;via bundler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle add rustywind-ruby
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or without:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem install rustywind-ruby
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use RustyWind via &lt;code&gt;bundler exec&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle exec rustywind
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Personally, I run RustyWind as part of a &lt;code&gt;bin/check&lt;/code&gt; script alongside other actions such as tests, linters, and audits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future plans
&lt;/h2&gt;

&lt;p&gt;A future update will be to have GitHub Actions sync with the RustyWind upstream repo to keep versions up to date automatically.&lt;/p&gt;

&lt;p&gt;For now though, it works as expected.&lt;/p&gt;

&lt;p&gt;If it doesn't for you, let me know in the &lt;a href="https://github.com/markahesketh/rustywind-ruby/issues" rel="noopener noreferrer"&gt;GitHub Issues&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>tailwindcss</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Switching between multiple PHP versions on macOS</title>
      <dc:creator>Mark Hesketh</dc:creator>
      <pubDate>Mon, 10 Feb 2020 16:04:21 +0000</pubDate>
      <link>https://dev.to/markhesketh/switching-between-multiple-php-versions-on-macos-566g</link>
      <guid>https://dev.to/markhesketh/switching-between-multiple-php-versions-on-macos-566g</guid>
      <description>&lt;p&gt;I often need to switch between multiple PHP versions on my macOS environment when working on legacy projects.&lt;/p&gt;

&lt;p&gt;As usual, I had forgot how to do this, so I’ve decided to publish the steps for my own and other’s reference.&lt;/p&gt;

&lt;p&gt;The instructions below are for use with macOS 10.15 Catalina, and allow installation of PHP 5.6, 7.0, 7.1, 7.2, 7.3 &amp;amp; 7.4.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs311wuqsojeely8cvccy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs311wuqsojeely8cvccy.jpg" width="800" height="370"&gt;&lt;/a&gt;Using multiple versions of PHP on macOS via homebrew&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Prerequisites
&lt;/h2&gt;

&lt;p&gt;You’ll need both Xcode Command Line Tools and &lt;a href="https://brew.sh" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt; installed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.1 Install XCode Command Line Tools&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xcode-select --install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1.2 Install Homebrew&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://brew.sh" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt; is a package manager for macOS. It is similar to &lt;code&gt;apt&lt;/code&gt; on Ubuntu.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

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

&lt;/div&gt;



&lt;p&gt;Check that brew has been installed correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ brew --version
Homebrew 2.2.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also run &lt;code&gt;brew doctor&lt;/code&gt; to check everything is good to go.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Install Multiple Versions of PHP
&lt;/h2&gt;

&lt;p&gt;As of writing, &lt;strong&gt;only PHP 7.2, 7.3 and 7.4 are actively maintained&lt;/strong&gt; and officially supported by Homebrew.&lt;/p&gt;

&lt;p&gt;To &lt;strong&gt;install PHP 5.6, 7.0 &amp;amp; 7.1&lt;/strong&gt; we’ll need to ‘tap’ an additional repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew tap exolnet/homebrew-deprecated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can install all the available PHP versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install php@5.6
brew install php@7.0
brew install php@7.1
brew install php@7.2
brew install php@7.3
brew install php@7.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may take a little time to install. Go make yourself a brew!&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Switching between PHP versions
&lt;/h2&gt;

&lt;p&gt;Once installed, you can switch between PHP versions by ‘linking’ and ‘unlinking’ in brew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Switch from 7.4 to 5.6
brew unlink php@7.4
brew link php@5.6 --force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvn6z63fd60s6k8bkz2dn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvn6z63fd60s6k8bkz2dn.jpg" width="800" height="632"&gt;&lt;/a&gt;Switching from PHP 7.4 to 5.6&lt;/p&gt;

&lt;p&gt;You can combine &lt;code&gt;brew unlink&lt;/code&gt; and &lt;code&gt;brew link&lt;/code&gt; to swap between any installed version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Source Alternatives
&lt;/h2&gt;

&lt;p&gt;There are a few open source projects that aim to automate this for you, if you prefer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://phpbrew.github.io/phpbrew/" rel="noopener noreferrer"&gt;phpbrew/phpbrew&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/philcook/brew-php-switcher" rel="noopener noreferrer"&gt;philcook/brew-php-switcher&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.markhesketh.com/switching-multiple-php-versions-on-macos/" rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>todayilearned</category>
      <category>tutorial</category>
      <category>macos</category>
    </item>
    <item>
      <title>Embrace Bin Scripts</title>
      <dc:creator>Mark Hesketh</dc:creator>
      <pubDate>Tue, 04 Feb 2020 12:42:09 +0000</pubDate>
      <link>https://dev.to/markhesketh/embrace-bin-scripts-2j3f</link>
      <guid>https://dev.to/markhesketh/embrace-bin-scripts-2j3f</guid>
      <description>&lt;p&gt;I recently watched Matt Stauffer’s talk “&lt;a href="https://www.youtube.com/watch?v=enTb2E4vEos" rel="noopener noreferrer"&gt;Patterns That Pay Off&lt;/a&gt;” from Laracon 2018. It’s packed with great advice that I’ve been bringing into my own projects.&lt;/p&gt;

&lt;p&gt;One piece of advice I’d like to highlight is the use of project-based bin scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Whats the problem?
&lt;/h2&gt;

&lt;p&gt;Have you ever had a project that hasn’t seen active development in years but now needs a small update.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Where do I get Bower from these days?”&lt;/li&gt;
&lt;li&gt;“What is a PEAR package?”&lt;/li&gt;
&lt;li&gt;“How do I deploy to Rackspace?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That quick CSS fix has become a much bigger headache.&lt;/p&gt;

&lt;p&gt;Or, a typical PHP Laravel project a local setup might involve these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Switch to PHP 7.4&lt;/li&gt;
&lt;li&gt;Install PHP dependencies via Composer&lt;/li&gt;
&lt;li&gt;Switch to Node v12.7&lt;/li&gt;
&lt;li&gt;Install frontend dependencies via NPM&lt;/li&gt;
&lt;li&gt;Start local PHP web server&lt;/li&gt;
&lt;li&gt;Start webpack build system&lt;/li&gt;
&lt;li&gt;Start a MySQL service&lt;/li&gt;
&lt;li&gt;Copy &lt;code&gt;.env&lt;/code&gt; variables&lt;/li&gt;
&lt;li&gt;Run database migrations and seeders&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thats a lot of steps to remember or fit into your readme, and thats assuming the developer reads the readme at all!&lt;/p&gt;

&lt;h2&gt;
  
  
  Whats the solution?
&lt;/h2&gt;

&lt;p&gt;What if &lt;em&gt;all&lt;/em&gt; your projects had these steps encapsulated in a single &lt;code&gt;bin/install.sh&lt;/code&gt; script.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglnht4f40hvimyb9bci8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglnht4f40hvimyb9bci8.png" width="800" height="378"&gt;&lt;/a&gt;Running the install script on a new project&lt;/p&gt;

&lt;p&gt;This script could perform the installation steps and check for project requirements. It could also handle the nuances between macOS, Linux or Windows dev environments.&lt;/p&gt;

&lt;p&gt;It doesn’t matter if you are working on a PHP, Node or static web app – you &lt;code&gt;cd&lt;/code&gt; into the project and run &lt;code&gt;./bin/install.sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once you’re ready to commit, run &lt;code&gt;./bin/precommit.sh&lt;/code&gt; to run your tests, static analysis, and formatting.&lt;/p&gt;

&lt;p&gt;Finally, run &lt;code&gt;./bin/deploy.sh&lt;/code&gt; to build production assets, update release notes and deploy. How you deploy that particular project doesn’t matter. Docker? Digital Ocean? Heroku? Who cares!&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the alternatives? Docker? Composer?
&lt;/h2&gt;

&lt;p&gt;You might be thinking &lt;em&gt;“this is the sort of thing Docker and CI solves!”&lt;/em&gt; or &lt;em&gt;“can I not just use composer/npm scripts?”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Docker can standardise your build steps – but not every project needs Docker. I have several projects where Docker would be overkill. For example, sites built using static site generators.&lt;/p&gt;

&lt;p&gt;A Docker-based app can still make use of bin scripts. If only to wrap &lt;code&gt;docker-compose up&lt;/code&gt; in the familiar &lt;code&gt;bin/run.sh&lt;/code&gt; script.&lt;/p&gt;

&lt;p&gt;Similarly, a PHP project may not even use Composer – such as a typical WordPress website.&lt;/p&gt;

&lt;p&gt;By embracing bin scripts, it doesn’t matter what an individual project’s tech stack is. The interface to install, run and deploy is the same across all your projects.&lt;/p&gt;

&lt;p&gt;Most importantly, shell scripts will run out of the box on macOS, Linux and Windows in almost all cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me the code!
&lt;/h2&gt;

&lt;p&gt;I have a &lt;code&gt;bin&lt;/code&gt; directory in my project root which contains my bin scripts. It looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tree bin
bin
├── install
├── run
└── precommit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each script is self-contained and includes everything it needs to run. Because of this, they’ll can work in many years from the first &lt;code&gt;git clone&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, one of my PHP Laravel apps has the following &lt;code&gt;bin/install.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env bash

# bin/install
# Install the application

command_exists() {
    command -v "$@" &amp;gt; /dev/null 2&amp;gt;&amp;amp;1
}

if ! command_exists fnm; then
    echo "fnm is not installed"
    echo "Visit https://github.com/Schniz/fnm to install"
    exit
fi

if ! command_exists composer; then
    echo "fnm is not installed"
    echo "Visit https://getcomposer.org/download/ to install"
    exit
fi

if ! command_exists yarn; then
    echo "fnm is not installed"
    echo "Visit https://yarnpkg.com/lang/en/docs/install/ to install"
    exit
fi

echo "Removing existing ./node_modules folder"
rm -rf ./node_modules
echo "Removing existing ./vendor folder"
rm -rf ./vendor

fnm use
composer install
yarn install

cp .env.example .env
php artisan key:generate
php artisan migrate:fresh --seed

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;bin/run.sh&lt;/code&gt; script as as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env bash

# bin/run
# Run the local development environment

if [["$OSTYPE" == "linux"*]]; then
    sudo service mysql start
fi

php -S 0.0.0.0:8000 -t public/ &amp;amp; yarn run watch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and finally, this is the &lt;code&gt;bin/precommit.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env bash

# bin/precommit
# Tasks to run pre-comment

php ./vendor/bin/phpunit

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

&lt;/div&gt;



&lt;p&gt;The scripts do not need overcomplicating, and can simply be a list of commands. The &lt;code&gt;bin/precommit.sh&lt;/code&gt; script only runs my test suite and nothing more.&lt;/p&gt;

&lt;p&gt;Crucially, it holds up across all my projects spanning years the tech stacks of their time.&lt;/p&gt;

&lt;p&gt;Laravel? WordPress? Static? No problem.&lt;/p&gt;

&lt;p&gt;Nice!&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating your own
&lt;/h2&gt;

&lt;p&gt;I can offer some final words of encouragement, if you’re interested in creating your own.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start small&lt;/strong&gt;. Don’t worry about adding support for Windows environments if you only ever use macOS. Add as you need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not everything needs scripting&lt;/strong&gt;. A printed message to direct the user could be enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep it simple&lt;/strong&gt;. There’s a temptation to create abstractions from your scripts. Resist adding complexity, duplication is not always a bad thing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create aliases.&lt;/strong&gt; &lt;a href="https://github.com/markahesketh/dotfiles/blob/master/home/.aliases" rel="noopener noreferrer"&gt;I’m a big fan of aliases&lt;/a&gt; and saving a keystroke. Once you’ve settled on your script names, you can alias them for even more convenience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.markhesketh.com/bin-scripts/" rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>bash</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>2020: Plans &amp; Goals</title>
      <dc:creator>Mark Hesketh</dc:creator>
      <pubDate>Mon, 06 Jan 2020 19:48:44 +0000</pubDate>
      <link>https://dev.to/markhesketh/2020-plans-goals-1jkh</link>
      <guid>https://dev.to/markhesketh/2020-plans-goals-1jkh</guid>
      <description>&lt;p&gt;Last week I &lt;a href="https://www.markhesketh.com/2019-year-in-review/" rel="noopener noreferrer"&gt;wrote a retrospective on how I felt 2019 went&lt;/a&gt;. Today, the Christmas tree came down, the country went back at work and I’m looking ahead to my plans for 2020.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing
&lt;/h2&gt;

&lt;p&gt;One of my main takeaways from 2019 was that I simply didn’t write enough even though &lt;a href="https://www.markhesketh.com/writing-about-thinking-about-writing/" rel="noopener noreferrer"&gt;I’d planned to&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Over the past 5 years I’ve got into an infinite loop with my blog, which goes something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decide I want to start blogging again&lt;/li&gt;
&lt;li&gt;Make a Trello board&lt;/li&gt;
&lt;li&gt;Scribble down some topic ideas&lt;/li&gt;
&lt;li&gt;Redesign and redeploy blog onto a new platform, infrastructure etc&lt;/li&gt;
&lt;li&gt;Become dissatisfied before writing a single post and move onto something else&lt;/li&gt;
&lt;li&gt;Repeat 18 months later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m taking a pragmatic approach and sticking with WordPress, the theme, the hosting – the lot, and writing some bloody posts.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The plan: Write more, build more, share more. 2017 gonna be a good 'un&lt;/p&gt;

&lt;p&gt;— Mark Hesketh (@markahesketh) &lt;a href="https://twitter.com/markahesketh/status/815888846223278080?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;January 2, 2017&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ve got some big projects planned for 2020, and I want to share everything I learn, both here and on &lt;a href="https://twitter.com/markahesketh" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;. I may also cross-post to communities such as &lt;a href="https://dev.to"&gt;dev.to&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to keep up with my writing on Modern PHP, Laravel, Testing, Developer soft-skills and how I use it all to build web apps in 2020 then &lt;a href="https://www.markhesketh.com/feed/" rel="noopener noreferrer"&gt;subscribe to the RSS feed&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Projects
&lt;/h2&gt;

&lt;p&gt;As mentioned, I’ve got a few personal projects lined up for this year, alongside my day job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Laravel E-commerce Applications
&lt;/h3&gt;

&lt;p&gt;I’ve embarked on an overly ambitious journey to build a couple of e-commerce applications.&lt;/p&gt;

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

&lt;p&gt;Rather than picking up an off-the-shelf e-commerce platform, I’ll be building them from scratch using Laravel. This has drawn some chuckles and skepticism from some of my colleagues, but I am undeterred! I have quite a few reasons for this which I’ll attempt to justify in a series of posts.&lt;/p&gt;

&lt;p&gt;The e-commerce stores are for my girlfriend’s business, selling hand-made jewellery.&lt;/p&gt;

&lt;p&gt;I built the original store in 2011 using PrestaShop, a PHP-based e-commerce platform, followed by a 2015 redesign. Now its time for refresh and at least one additional store, armed with everything we’ve learnt since.&lt;/p&gt;

&lt;p&gt;This is a nights and weekends project, and for now is built for purpose to minimise the scope – but there’s definitely potential to extract some open-source packages along the way. As mentioned, I will also write about its progress, decisions made and lessons learnt.&lt;/p&gt;

&lt;h3&gt;
  
  
  Proudly Powered
&lt;/h3&gt;

&lt;p&gt;I registered &lt;a href="https://www.proudlypowered.com" rel="noopener noreferrer"&gt;proudlypowered.com&lt;/a&gt; in 2012 while freelancing and primarily building on WordPress.&lt;/p&gt;

&lt;p&gt;The name is a reference to &lt;em&gt;“Proudly powered by WordPress”&lt;/em&gt; seen in the footers of WordPress-based websites, and I’ve always liked it. However, I moved away from WordPress soon after registering the domain and never did much with it.&lt;/p&gt;

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

&lt;p&gt;I’m not planning a return to WordPress professionally but I am actively using it for this website. In doing so, I expect to open-source any custom themes, plugins and tools that I build under the Proudly Powered name.&lt;/p&gt;

&lt;p&gt;In addition to my own work, it may also recommend plugins, themes and techniques by other developers that are of high quality should be highlighted.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Are there any recommended WordPress resources that aren't thinly veiled affiliate link aggregators?&lt;/p&gt;

&lt;p&gt;— Mark Hesketh (@markahesketh) &lt;a href="https://twitter.com/markahesketh/status/1208718000540540929?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;December 22, 2019&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
May be harsh, but my initial search was fruitless.



&lt;p&gt;It could be a single page website, it may be more. I haven’t decided. Regardless, I’d like it to be a legitimate reference for developers who take pride in their work, have an eye for quality and choose to build on WordPress.&lt;/p&gt;

&lt;h2&gt;
  
  
  Guitar
&lt;/h2&gt;

&lt;p&gt;I’d like to adopt more hobbies outside of programming and computers, revisiting some of the things I enjoyed before getting deep into web development.&lt;/p&gt;

&lt;p&gt;I played guitar through my teens, barely above beginner level, but I really enjoyed playing along to bands in my bedroom. Much to my brother’s discomfort.&lt;/p&gt;

&lt;p&gt;Before Christmas I dusted off my Epiphone Les Paul that I bought in 2004 with money saved working in a local pub kitchen, and set myself a challenge to learn a full album.&lt;/p&gt;

&lt;p&gt;Not a single song, riff or solo, as I’m prone to do – but the full album.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpgs2q1xeqocrobku0qxm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpgs2q1xeqocrobku0qxm.jpg" alt="The Killers : Hot Fuss album cover" width="350" height="350"&gt;&lt;/a&gt;“Coming out of my cage and I’ve been doing just fine”&lt;/p&gt;

&lt;p&gt;The album I’ve picked is Killers – Hot Fuss, for a few reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I like every song on the album&lt;/li&gt;
&lt;li&gt;It seems achievable at my skill level, with a few tricky ones thrown in to make it a challenge&lt;/li&gt;
&lt;li&gt;It gives me an excuse to learn &lt;a href="https://www.youtube.com/watch?v=gGdGFtwCNBE" rel="noopener noreferrer"&gt;the anthem of my generation&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  And the rest
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Complete ‘Dry January’. Christmas was heavily indulged&lt;/li&gt;
&lt;li&gt;Make 2020 the year we buy our first home&lt;/li&gt;
&lt;li&gt;Attend at least one PHP / Laravel conference or local meetup&lt;/li&gt;
&lt;li&gt;Record a screencast&lt;/li&gt;
&lt;li&gt;Watch Burnley FC maintain their Premier League status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s to a great 2020!&lt;/p&gt;

</description>
      <category>notes</category>
    </item>
    <item>
      <title>Your README Is Important</title>
      <dc:creator>Mark Hesketh</dc:creator>
      <pubDate>Wed, 20 Sep 2017 20:57:08 +0000</pubDate>
      <link>https://dev.to/markhesketh/your-readme-is-important-oc</link>
      <guid>https://dev.to/markhesketh/your-readme-is-important-oc</guid>
      <description>&lt;p&gt;Good documentation is very important and expected of open-source projects.&lt;/p&gt;

&lt;p&gt;We should hold our private projects to the same standard. The &lt;code&gt;README&lt;/code&gt; is not a &lt;code&gt;@todo&lt;/code&gt;. It should be available and up to date, even if only for our own benefit.&lt;/p&gt;

&lt;h2&gt;
  
  
  But why?
&lt;/h2&gt;

&lt;p&gt;It might sound like a waste of time to document something you’ve made for yourself but you’d be mistaken.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The faintest ink is more powerful than the strongest memory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ve lost count of the number of times I’ve picked up an old client’s project and been thankful I’d included a &lt;code&gt;README.md&lt;/code&gt;. I’d taken the 5 minutes to document the setup steps, and can now onboard myself even several years later. Instead of trying to remember my workflow of years gone by, the instructions are right there.&lt;/p&gt;

&lt;p&gt;What seems obvious now, may not be later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practice makes perfect
&lt;/h3&gt;

&lt;p&gt;Writing concise documentation is a worthwhile skill and you should practice whenever possible. Using the documentation on your personal projects is the perfect opportunity.&lt;/p&gt;

&lt;p&gt;This practice will benefit you and others when documenting public or team projects.&lt;/p&gt;

&lt;p&gt;Good documentation can be the difference between a project succeeding or not. Personally, I’ll skip any project that does not have clear and concise documentation.&lt;/p&gt;

&lt;p&gt;Hone your documentation skills and give personal projects their best chance to succeed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to start?
&lt;/h2&gt;

&lt;p&gt;Dig into your projects folder, find a project that is missing a &lt;code&gt;README.md&lt;/code&gt; and get to work. Your future-self will thank you.&lt;/p&gt;

&lt;p&gt;For tips on writing your README, refer to Eric Barnes’ great article on &lt;a href="https://m.dotdev.co/how-to-write-a-readme-that-rocks-bc29f279611a"&gt;how to write a README that rocks&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>notes</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
