<?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: Cameron Desautels</title>
    <description>The latest articles on DEV Community by Cameron Desautels (@camdez).</description>
    <link>https://dev.to/camdez</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%2F140800%2F981ef900-eed2-4d46-964a-5e9281605273.jpeg</url>
      <title>DEV Community: Cameron Desautels</title>
      <link>https://dev.to/camdez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/camdez"/>
    <language>en</language>
    <item>
      <title>Chinese Zodiac Time for Emacs</title>
      <dc:creator>Cameron Desautels</dc:creator>
      <pubDate>Tue, 13 Feb 2024 03:22:33 +0000</pubDate>
      <link>https://dev.to/camdez/chinese-zodiac-time-for-emacs-13mi</link>
      <guid>https://dev.to/camdez/chinese-zodiac-time-for-emacs-13mi</guid>
      <description>&lt;p&gt;In the spirit of Chinese New Year, I hacked up a small extension for Emacs to render the current time of day using emoji and Chinese characters:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ITfQ_x8L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://camdez.com/images/blog/chinese-zodiac-time-for-emacs/demo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ITfQ_x8L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://camdez.com/images/blog/chinese-zodiac-time-for-emacs/demo.jpg" alt="Various screenshots of Emacs showing the time displayed with Chinese characters and emoji." width="800" height="356"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Various configurations for your mode line.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It’s just a silly project that I’ll consider a success if it puts a smile on someone’s face, but it is loosely based on &lt;a href="https://dev.toming-system"&gt;a system used to measure time in the Ming dynasty&lt;/a&gt; which divided the day into 12 equal periods (時&lt;sup id="fnref:1"&gt;1&lt;/sup&gt;), named after &lt;a href="https://en.wikipedia.org/wiki/Earthly_Branches"&gt;the 12 earthly branches&lt;/a&gt; (地支).&lt;/p&gt;

&lt;p&gt;Because the animals of the Chinese zodiac map 1-to-1 with the earthly branches, it is equally possible to indicate the time with the zodiac animals!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HziMBQiO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://camdez.com/images/blog/chinese-zodiac-time-for-emacs/earthly-branches.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HziMBQiO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://camdez.com/images/blog/chinese-zodiac-time-for-emacs/earthly-branches.jpg" alt="Chart of correspondence between the earthly branches, zodiac animals, and times of day from Wikipedia. Apologies on this being in Spanish." width="683" height="1280"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Chart of correspondence between the earthly branches, zodiac animals, and times of day from Wikipedia. Apologies on this being in Spanish.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Given that a modern user probably wants to know which of our &lt;em&gt;24&lt;/em&gt; hours they’re in, rather than which two hour period (時), I decided to differentiate the two halves as either 小 (small) or 大 (large).&lt;/p&gt;

&lt;p&gt;Hence, in the image above showing the time as 「大🐲 四十二分」, the current time is 8:42am, by our modern reckoning (7:42am would be the &lt;em&gt;little&lt;/em&gt; dragon!).&lt;/p&gt;

&lt;p&gt;I won’t go into a ton of detail here because I explain it in some detail on &lt;a href="https://github.com/camdez/cn-zodiac-time.el"&gt;the project’s GitHub page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The most amusing part of the project was, perhaps, deciding exactly which emoji to use! In the end, I implemented two sets of emoji you can choose from:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Set&lt;/th&gt;
&lt;th&gt;Emoji&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;'cute&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;🐭🐮🐯🐰🐲🐍🐴🐏🐵🐔🐶🐷&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;'emoji&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;🐀🐄🐅🐇🐉🐍🐎🐑🐒🐓🐕🐖&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Rather disappointing that we don’t quite have a complete set of animal faces. At least not in Apple’s emoji.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you’re wondering why I chose the COW (🐄) emoji in the second set rather than the OX (🐂), it’s because it looked too similar to the neighboring TIGER (🐅), making it easy to confuse the time.&lt;/p&gt;

&lt;p&gt;If you don’t like my choices, the library also makes it extremely easy to bring your own set of emoji, so you can make your own decisions between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RAT (🐀), MOUSE (🐁), and MOUSE FACE (🐭)&lt;/li&gt;
&lt;li&gt;SHEEP (🐑), GOAT (🐐), and RAM (🐏)&lt;/li&gt;
&lt;li&gt;HORSE (🐎) and HORSE FACE (🐴)&lt;/li&gt;
&lt;li&gt;CHICKEN (🐔) and ROOSTER (🐓)&lt;/li&gt;
&lt;li&gt;Or maybe even pretend FROG (🐸) is a snake face&lt;/li&gt;
&lt;li&gt;Or spice up your horse with UNICORN (🦄)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Clearly the sky’s the limit.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For Chinese learners or traditionalists, it can also display the time with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traditional characters: 「大龍 四十二分」&lt;sup id="fnref:2"&gt;2&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;Simplified characters: 「大龙 四十二分」&lt;/li&gt;
&lt;li&gt;Or earthly branches: 「辰正 四十二分」&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(&lt;em&gt;n.b.&lt;/em&gt; the earthly branches are displayed using the proper, traditional system of 初 and 正 suffixes, not my invented prefixes for animals.)&lt;/p&gt;

&lt;p&gt;It’s a lot of fun telling time with cute animals, and might even help you learn a few things if you’re a beginner in Chinese, so &lt;a href="https://github.com/camdez/cn-zodiac-time.el"&gt;check it out on GitHub!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;龍年快樂！恭喜發財！ 🐉🧧&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Students of the Chinese language may find it interesting to know that these &lt;em&gt;two&lt;/em&gt; hour periods are the reason we call (single) hours &lt;strong&gt;小&lt;/strong&gt; 時 in modern Chinese (I know I did!). ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It’s not 100% clear to me if these characters will render the same regardless of locale, so I apologize if they do not appear as I have described—I’m still trying to get my head around &lt;a href="https://en.wikipedia.org/wiki/CJK_Unified_Ideographs"&gt;CJK unification&lt;/a&gt; in Unicode. ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>emacs</category>
      <category>unicode</category>
    </item>
    <item>
      <title>Java Allergies and Revisiting java.time</title>
      <dc:creator>Cameron Desautels</dc:creator>
      <pubDate>Fri, 09 Feb 2024 18:08:27 +0000</pubDate>
      <link>https://dev.to/camdez/java-allergies-and-revisiting-javatime-1n2e</link>
      <guid>https://dev.to/camdez/java-allergies-and-revisiting-javatime-1n2e</guid>
      <description>&lt;p&gt;&lt;em&gt;Wherein I argue that Clojurians should be a touch more embracing of Java interop and that &lt;code&gt;java.time&lt;/code&gt; is actually good.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;Table of Contents&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Fun Times with &lt;code&gt;java.time&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;But I’m Allergic to Java&lt;/li&gt;
&lt;li&gt;To Library Or Not To Library?&lt;/li&gt;
&lt;li&gt;Postscript&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I enjoyed &lt;a href="https://jmglov.net/blog/2024-02-09-counting-blog-posts.html"&gt;Josh Glover’s post&lt;/a&gt; today in which he described how he queried his &lt;a href="https://github.com/borkdude/quickblog"&gt;quickblog&lt;/a&gt; data with a dash of &lt;a href="https://github.com/babashka/babashka"&gt;Babash…ka&lt;/a&gt; (&lt;em&gt;sorry, couldn’t resist&lt;/em&gt;) to determine the number of posts he made during a certain date range—“in 50 simple steps”.&lt;/p&gt;

&lt;p&gt;I appreciate this narrative, almost &lt;em&gt;lab notebook&lt;/em&gt;, style of writing. It’s helpful to see how others work through problems, what tools they use to explore, and what alternatives they consider. It’s also humanizing, reminding us that elegant works we encounter likely didn’t emerge spontaneously, &lt;a href="https://en.wikipedia.org/wiki/Athena#Birth"&gt;Athena-like&lt;/a&gt;, from the heads of their creators, but took time&lt;sup id="fnref:1"&gt;1&lt;/sup&gt; and, perhaps, toil. &lt;em&gt;Ex nihilo nihil fit&lt;/em&gt;—the mill demands its grist.&lt;/p&gt;

&lt;p&gt;It takes extra work to write as he did, tracking your own twists and turns, so, &lt;em&gt;thank you&lt;/em&gt; to Josh for the post. (He has a good sense of humor and makes cool stuff, so check out &lt;a href="https://jmglov.net/blog/"&gt;his blog&lt;/a&gt;!)&lt;/p&gt;

&lt;p&gt;I enjoyed seeing how simple the &lt;a href="https://github.com/borkdude/quickblog"&gt;quickblog&lt;/a&gt; data model was along the way (universal Clojure plot spoiler: &lt;em&gt;it was maps&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9hGE75C0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://camdez.com/images/blog/java-allergies-and-revisiting-java-time/clj-data-reveal.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9hGE75C0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://camdez.com/images/blog/java-allergies-and-revisiting-java-time/clj-data-reveal.jpg" alt="Scooby Doo Reveal meme of Clojure taking the mask off data to reveal a Clojure map beneath." width="489" height="653"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fun Times with &lt;code&gt;java.time&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;I’d like to borrow a few of Josh’s steps&lt;sup id="fnref:2"&gt;2&lt;/sup&gt; as a jumping off point to address date / time handling in Clojure&lt;sup id="fnref:3"&gt;3&lt;/sup&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Realise that :posts is a map of filename to post, but no matter!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sigh as you come to terms with the fact that you’re going to need to do some date parsing and you never remember how to use java.time and argh!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Smile as you remember about tick, which is a library from our good friends at JUXT that provides a nicer API for this sort of stuff&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ve had several discussions with peers who felt the exact same way about &lt;code&gt;java.time&lt;/code&gt;. Hell, &lt;em&gt;I&lt;/em&gt; felt that way for while.&lt;/p&gt;

&lt;p&gt;But while I certainly agree that the &lt;a href="https://www.juxt.pro"&gt;JUXT folks&lt;/a&gt; are great friends to the community (💙), and that they’ve created something nice with &lt;a href="https://github.com/juxt/tick"&gt;tick&lt;/a&gt;, I’d also argue that &lt;strong&gt;&lt;code&gt;java.time&lt;/code&gt; is pretty good&lt;/strong&gt; , and it deserves another look if you wrote it off early on.&lt;/p&gt;

&lt;p&gt;I can’t vouch for everything in &lt;code&gt;java.time&lt;/code&gt;—I don’t &lt;em&gt;know_everything in &lt;code&gt;java.time&lt;/code&gt;—but it was written (comparatively) recently, after the lessons of &lt;code&gt;java.util.Date&lt;/code&gt; (bad) and&lt;a href="https://www.joda.org/joda-time/"&gt;Joda-Time&lt;/a&gt; (much better) had been absorbed, and _they basically got it right&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I suspect most of us have dealt with a date parsing scenario like Josh encountered and found ourselves thinking: &lt;em&gt;“just turn this damn string into a date—how hard could it be?”&lt;/em&gt; Maybe we even came from a language where a single function could parse &lt;code&gt;"2022-08-26"&lt;/code&gt; and&lt;code&gt;"2022-08-26T10:30"&lt;/code&gt; and &lt;code&gt;"2022-08-26T10:30:00.000-05:00"&lt;/code&gt;, and it all seemed so easy. And now we have this fussy, baroque &lt;code&gt;java.time&lt;/code&gt; thing to contend with.&lt;/p&gt;

&lt;p&gt;But the thing about those easy interfaces? They’re &lt;em&gt;all&lt;/em&gt; bad, broken, or incorrect&lt;sup id="fnref:4"&gt;4&lt;/sup&gt;. And, if you haven’t already, you &lt;em&gt;will&lt;/em&gt; eventually get burned by them.&lt;/p&gt;

&lt;p&gt;It’s actually trivial to demonstrate: what does &lt;code&gt;"2022-08-26"&lt;/code&gt;represent? Is it August 26th, 2022 in your computer’s time zone? In GMT? Is it that date &lt;em&gt;regardless&lt;/em&gt; of your timezone (meaning it’s not a single, unified point in time&lt;sup id="fnref:5"&gt;5&lt;/sup&gt;)? These are all foundational concepts in our world; we need all of these concepts to have programs that do practical things, and since the semantics are not differentiated in the content of the string, they cannot possibly be handled correctly by a single (undifferentiated) parser.&lt;/p&gt;

&lt;p&gt;Human representation of time is &lt;em&gt;inherently&lt;/em&gt; complex (read &lt;a href="https://infiniteundo.com/post/25326999628/falsehoods-programmers-believe-about-time"&gt;Falsehoods programmers believe about time&lt;/a&gt; if you need convincing), so you really only have two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The broken way&lt;/strong&gt; — “Being small and &lt;del&gt;simple&lt;/del&gt; [easy] is more important than being correct.” (perjoratively, “the Unix way”, à la&lt;a href="https://archive.org/details/TheUnixHatersHandbook/page/n21/mode/2up"&gt;The Unix Haters Handbook, pg. xx&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The fussy way&lt;/strong&gt; — “The design must be correct in all observable aspects. Incorrectness is simply not allowed.” (generously, “the Lisp way”, à la &lt;a href="https://dreamsongs.com/RiseOfWorseIsBetter.html"&gt;rpg&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A correct implementation, by necessity, reflects the inherent complexity of the problem domain&lt;sup id="fnref:6"&gt;6&lt;/sup&gt;. And I think &lt;code&gt;java.time&lt;/code&gt;actually does a good job of that. &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html"&gt;The core classes in&lt;code&gt;java.time&lt;/code&gt;&lt;/a&gt; neatly represent the underlying concepts in the domain (&lt;em&gt;and are immutable!&lt;/em&gt;)—it’s just that the domain is big, so there’s a lot for us to get our heads around.&lt;/p&gt;

&lt;p&gt;But once we do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A date, irrespective of time or timezone is just:
&lt;code&gt;(LocalDate/parse "2022-08-26")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If that includes a time, it’s:
&lt;code&gt;(LocalDateTime/parse "2022-08-26T10:30")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;And a single point in time is:
&lt;code&gt;(Instant/parse "2022-08-26T10:30:00.000-05:00")&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There’s really no fluff or inconsistency here—we just need to remember the class names. It wouldn’t be any easier if these were three &lt;em&gt;function&lt;/em&gt; names instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  But I’m Allergic to Java
&lt;/h2&gt;

&lt;p&gt;Many Clojurians seem grumpy about seeing Java &lt;em&gt;stuff&lt;/em&gt; in their Clojure code. I get it. I, too, came from the pure Lisp lands of kebabs and unified case (though preferably not &lt;code&gt;*THE-SHOUTY-KIND*&lt;/code&gt;). And didn’t we do all of this to get away from that Java stuff?&lt;/p&gt;

&lt;p&gt;Calling everything via functions looks nice, and has its benefits for porting (&lt;em&gt;e.g.&lt;/em&gt; CLJS), and, hey, wouldn’t it be &lt;em&gt;dreamy&lt;/em&gt; if one day we had a non-hosted, portable language with a spec and maybe it even bootstrapped itself, and compiled natively and… &lt;em&gt;[trails off]&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But in the meantime…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JVM interop is a freaking &lt;em&gt;superpower&lt;/em&gt;. The presence of “Java stuff” in our language means we get to tap into &lt;em&gt;thousands of person-years&lt;/em&gt; of engineering effort that our small community couldn’t have come up with on its own. &lt;em&gt;It’s not a bug—it’s a feature!&lt;/em&gt; (But really this time.)&lt;/li&gt;
&lt;li&gt;You’ll need to learn &lt;em&gt;some&lt;/em&gt; Java stuff if you want to get good at Clojure. You need to be able to read stacktraces effectively, use records and protocols, and wield core Java libraries.&lt;/li&gt;
&lt;li&gt;We shouldn’t shun &lt;em&gt;interop&lt;/em&gt; in the same way that non-Lispers shouldn’t shun &lt;em&gt;s-expressions&lt;/em&gt;. Think what that bias has cost them. If minor syntax details are your biggest concern, you need to work on harder problems!&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://clojure.org/news/2024/02/08/1-12-alpha6"&gt;Clojure 1.12&lt;/a&gt; is around the corner and you’re going to be able to do this:
&lt;code&gt;(map LocalDate/parse ["2022-08-26" ,,,])&lt;/code&gt;
Instead of this:
&lt;code&gt;(map (fn [v] (LocalDate/parse v)) ["2022-08-26" ,,,])&lt;/code&gt;
Rejoice!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  To Library Or Not To Library?
&lt;/h2&gt;

&lt;p&gt;So we want to filter a sequence of maps based on their &lt;code&gt;:date&lt;/code&gt;values—should we pull in a library? (You know what I’m going to say if you read all of the above, so I won’t belabor it…)&lt;/p&gt;

&lt;p&gt;JUXT actually provides &lt;a href="https://github.com/juxt/tick?tab=readme-ov-file#should-you-use-tick-for-date-time-work"&gt;a nice guide to when you might want to use tick&lt;/a&gt; that makes thoughtful points you should read.&lt;/p&gt;

&lt;p&gt;But for the basic cases, my fellow Clojurians, I really encourage you to just learn &lt;code&gt;java.time&lt;/code&gt;. Because of the inherent complexity of time, it’s basically &lt;em&gt;this set of classes&lt;/em&gt; or &lt;em&gt;that set of functions&lt;/em&gt;—and the former is standard, built-in, battle-tested, and known.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Give it another chance.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It may not look like much, but it’s got it where it counts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Postscript
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bonus tip&lt;/strong&gt; : for super basic cases, you can just use&lt;code&gt;read-instant-date&lt;/code&gt; (which pairs great with &lt;a href="https://engineering.collbox.co/post/clj-inst-reader-literal-shortcuts/"&gt;&lt;code&gt;#inst&lt;/code&gt;’s convenient capabilities&lt;/a&gt;!):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(.before (clojure.instant/read-instant-date "2022-08-26") #inst "2022-09-01")
;; =&amp;gt;
true

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

&lt;/div&gt;



&lt;p&gt;It’s naive, without a proper understanding of timezones and such, but it handles the basics fine.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Thank you for reading, and thanks again to Josh for &lt;a href="https://jmglov.net/blog/2024-02-09-counting-blog-posts.html"&gt;the great post&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Hopefully of the &lt;em&gt;hammock&lt;/em&gt; variety. ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Slightly reformatted because &lt;em&gt;computers&lt;/em&gt;. ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is my sincere hope that the author won’t mind my use of his post as a foundation to discuss this topic with the community; it’s certainly not intended as a critique of his post and / or code. ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Just to be clear (and fair), I’m not including &lt;a href="https://github.com/juxt/tick"&gt;tick&lt;/a&gt; in my “bad” list—it’s actually a thin, sane layer over &lt;code&gt;java.time&lt;/code&gt; (on the JVM). ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you want to have a bad time (ugh, sorry), try explaining to a_user_ that a date basically &lt;em&gt;isn’t a thing&lt;/em&gt; and that their globally-distributed team possibly &lt;em&gt;should&lt;/em&gt; see two different dates on the same invoice depending on their location. ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Pigeonhole_principle"&gt;So many pigeons, so few holes.&lt;/a&gt; ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>clojure</category>
      <category>java</category>
    </item>
    <item>
      <title>Launching Dev Dependencies with tmux</title>
      <dc:creator>Cameron Desautels</dc:creator>
      <pubDate>Sun, 29 Mar 2020 16:35:06 +0000</pubDate>
      <link>https://dev.to/camdez/launching-dev-dependencies-with-tmux-hfg</link>
      <guid>https://dev.to/camdez/launching-dev-dependencies-with-tmux-hfg</guid>
      <description>&lt;p&gt;When working on &lt;a href="https://collbox.co"&gt;CollBox&lt;/a&gt;, we have a handful of external services the app depends on which we need to have running at development time. I used to run these via &lt;a href="https://github.com/ddollar/foreman"&gt;Foreman&lt;/a&gt;, but somewhere along the way my Ruby installation seems to have gotten borked (thanks, &lt;a href="https://www.apple.com/macos/catalina/"&gt;Catalina&lt;/a&gt;?) and since then I've been running the services by hand.  I always work in a &lt;a href="https://github.com/tmux/tmux/wiki"&gt;&lt;code&gt;tmux&lt;/code&gt;&lt;/a&gt; session anyway, so I decided it was time to see what it would look like to launch my window full of dependencies in &lt;code&gt;tmux&lt;/code&gt; from a script.&lt;/p&gt;

&lt;p&gt;As it turns out, &lt;code&gt;tmux&lt;/code&gt; is fantastically scriptable.  If you simply run &lt;code&gt;tmux &amp;lt;command&amp;gt;&lt;/code&gt; from a shell inside of a &lt;code&gt;tmux&lt;/code&gt; session, that command will be run by the encapsulating &lt;code&gt;tmux&lt;/code&gt; instance, and these are the same set of commands that can be bound to your &lt;code&gt;tmux&lt;/code&gt; keyboard shortcuts.  You can also simply send a stream of keystrokes to panes inside of &lt;code&gt;tmux&lt;/code&gt;.  All of this means running my four dependencies in a single window (named "deps") under their own panes is as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="c"&gt;# deps.sh&lt;/span&gt;

tmux new-window &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"deps"&lt;/span&gt;

tmux send-keys &lt;span class="s2"&gt;"redis-server redis.conf"&lt;/span&gt; Enter
tmux split-window
tmux send-keys &lt;span class="s2"&gt;"datomic/bin/transactor transactor.properties"&lt;/span&gt; Enter
tmux split-window
tmux send-keys &lt;span class="s2"&gt;"lein shadow-watch"&lt;/span&gt; Enter
tmux split-window
tmux send-keys &lt;span class="s2"&gt;"npx gulp"&lt;/span&gt; Enter

tmux &lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="nt"&gt;-layout&lt;/span&gt; tiled

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

&lt;/div&gt;



&lt;p&gt;When I'm ready to work on the project I simply run &lt;code&gt;./deps.sh&lt;/code&gt; at my shell and I end up with something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;+---------------------------------+---------------------------------+
| &lt;span class="nv"&gt;$ &lt;/span&gt;redis-server redis.conf       | &lt;span class="nv"&gt;$ &lt;/span&gt;datomic/bin/transactor transa |
| ...                             | ...                             |
|                                 |                                 |
|                                 |                                 |
|                                 |                                 |
|                                 |                                 |
|                                 |                                 |
|---------------------------------+---------------------------------|
| &lt;span class="nv"&gt;$ &lt;/span&gt;lein shadow-watch             | &lt;span class="nv"&gt;$ &lt;/span&gt;npx gulp                      |
| ...                             | ...                             |
|                                 |                                 |
|                                 |                                 |
|                                 |                                 |
|                                 |                                 |
|                                 |                                 |
+---------------------------------+---------------------------------+
| 1:deps&lt;span class="k"&gt;*&lt;/span&gt; | 2:zsh |                                                 |
+-------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;fin.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;A few thoughts on other tools that can be used to address this same problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/ddollar/foreman"&gt;Foreman&lt;/a&gt;: Great project; I've used it happy for years. I love the aggregated, colorized logs, which keep things compact yet comprehensible.  The one downside is that it's not convenient to restart a single service, should you need to.  But my main reason for switching was just to see if I could avoid the additional dependencies to my development stack given that I already use &lt;code&gt;tmux&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tmuxinator/tmuxinator"&gt;tmuxinator&lt;/a&gt;: Looks like a nice project to encapsulate essentially what I did above into a simple data-driven format, but I don't see that the gains are big enough (at least for my simple case) to bother adding the additional dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt;: As much as I like the idea of cleanly locking down development dependencies in the Docker style, in practice I've found it exceptionally costly, both in terms of the performance overhead (I literally had to buy a new laptop at my last job once we switched to Docker), and the increased complexity of accessing application state / debugging.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>productivity</category>
      <category>coding</category>
      <category>todayilearned</category>
    </item>
  </channel>
</rss>
