<?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: Chris Watson</title>
    <description>The latest articles on DEV Community by Chris Watson (@watzon).</description>
    <link>https://dev.to/watzon</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%2F169960%2F46a60390-8019-4033-90f2-c4e50fb5a90c.jpg</url>
      <title>DEV Community: Chris Watson</title>
      <link>https://dev.to/watzon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/watzon"/>
    <language>en</language>
    <item>
      <title>25 Web Design Trends to Watch in 2025</title>
      <dc:creator>Chris Watson</dc:creator>
      <pubDate>Tue, 15 Apr 2025 19:46:36 +0000</pubDate>
      <link>https://dev.to/watzon/25-web-design-trends-to-watch-in-2025-e83</link>
      <guid>https://dev.to/watzon/25-web-design-trends-to-watch-in-2025-e83</guid>
      <description>&lt;p&gt;Every year, I like to take stock of where web design is headed—and 2025 is shaping up to be one of the boldest years yet. This roundup covers &lt;strong&gt;25 of the biggest web design trends&lt;/strong&gt; I'm seeing across the internet right now. Whether you're a fellow dev, a designer, or a founder figuring out what the hell to do with your homepage, this should help spark some ideas.&lt;/p&gt;

&lt;p&gt;This originally appeared on &lt;a href="https://spectrumitconsulting.com/blog/25-for-25-top-web-design-trends-2025" rel="noopener noreferrer"&gt;Spectrum IT Consulting&lt;/a&gt;, where I share more resources and insights for growing businesses through thoughtful design and tech.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Interactive and Immersive Experiences
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Micro Animations
&lt;/h3&gt;

&lt;p&gt;Tiny details with big impact. Micro animations help guide users, reinforce actions, and give interfaces that extra bit of polish. Think hover effects, button ripples, loading indicators—they're subtle, but powerful.&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%2Fe8djosm0ydk4104bno2q.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%2Fe8djosm0ydk4104bno2q.png" alt="Peter Nottage's website showcases a ton of beautiful micro animations." width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Cursor Animation
&lt;/h3&gt;

&lt;p&gt;Custom cursors are in. Designers are using them as brand elements—everything from sparkly trails to responsive morphing shapes. It’s weirdly delightful.&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%2F5bna5lpt3jme4l59yo3n.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%2F5bna5lpt3jme4l59yo3n.png" alt="The Observatory has a fantastic example of cursor animations" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Scroll-Triggered Animations
&lt;/h3&gt;

&lt;p&gt;Forget static content. Scroll-triggered animations add drama and structure to the experience—elements zoom, slide, or fade in as you scroll. It's like turning a page in a story.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Experimental Navigation
&lt;/h3&gt;

&lt;p&gt;Hamburgers and dropdowns? Snooze. 2025 is full of weird nav: radial menus, scrolling-as-navigation, and even gesture-based navigation on some sites. It’s not for every project, but damn does it stand out.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Non-Traditional Scrolling
&lt;/h3&gt;

&lt;p&gt;Sideways, diagonal, sticky-scroll, or scroll-jacking in a good way—creativity is bleeding into scroll mechanics, making them part of the storytelling experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎨 Visual Design Elements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6. Futuristic, Sci-Fi Gaming UI Aesthetics
&lt;/h3&gt;

&lt;p&gt;Interfaces inspired by games and sci-fi films are on the rise—think neon glows, HUD-style overlays, and glitchy transitions.&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%2F56luvmfgroiylxz8aldf.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%2F56luvmfgroiylxz8aldf.png" alt="Zero Gravity's website features an interesting futuristic and game like interface" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Brutalist Design
&lt;/h3&gt;

&lt;p&gt;Unapologetically harsh layouts, massive fonts, and clashing elements. Brutalism is still kicking, especially in indie and portfolio sites. Bonus points if you blend it with modern techniques like I did on my own site.&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%2Fa6m4kqiazy4p77sqo7kj.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%2Fa6m4kqiazy4p77sqo7kj.png" alt="Spectrum IT Consulting features a neo-brutalist design, which combines elements of brutalism with other modern techiques" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Organic Matter
&lt;/h3&gt;

&lt;p&gt;Designs with earthy textures, wavy lines, and organic flow are balancing out the cold, minimal vibes of the past few years.&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%2F04931whei9w4vl9t4473.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%2F04931whei9w4vl9t4473.png" alt="EveeRoseCo's website is full of earthy tones and flowing natural elements" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  9. UFOs (Unexpected Floating Objects)
&lt;/h3&gt;

&lt;p&gt;Floating shapes, drifting blobs, and gravity-defying elements that dance on the screen. They break the grid in fun ways and keep things playful.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Full-Screen Headers
&lt;/h3&gt;

&lt;p&gt;The “above the fold” area is now “above everything.” Full-screen headers are visually intense and set the tone right away.&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%2F0w6xk50j25t33cazovwj.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%2F0w6xk50j25t33cazovwj.png" alt="Nomadic Tribe's site features a beatiful full screen video hero" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  11. 3D Websites
&lt;/h3&gt;

&lt;p&gt;WebGL and friends are being used for more than just cool portfolios—product showcases, interactive charts, and landing pages are all getting the 3D treatment.&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%2F6oi3gso4ski9qd0mkefo.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%2F6oi3gso4ski9qd0mkefo.png" alt="Bruno Simon's portfolio features a really cool 3d design with game like navigation" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🧱 Layout and Structure
&lt;/h2&gt;

&lt;h3&gt;
  
  
  12. Bento Grid / Bento UI
&lt;/h3&gt;

&lt;p&gt;Inspired by Japanese bento boxes, this layout style uses modular blocks to organize content. Great for portfolios and dashboards.&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%2F9fgpvmxi97yz0nejaco8.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%2F9fgpvmxi97yz0nejaco8.png" alt="Handkit features lovely bento elements" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  13. Grid Design (With a Twist)
&lt;/h3&gt;

&lt;p&gt;Asymmetric grids are hot. Breaking the perfect grid rules adds personality while keeping layouts structured.&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%2Fzlitc0qryxogx9y1akad.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%2Fzlitc0qryxogx9y1akad.png" alt="ETQ uses asymetric grid elements throughout their site" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  14. Negative Space / White Space
&lt;/h3&gt;

&lt;p&gt;Whitespace isn't just trendy—it’s foundational. It makes everything breathe and helps direct attention to the stuff that matters.&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%2Fn4ixahclkpysp57ioju9.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%2Fn4ixahclkpysp57ioju9.png" alt="Apple's website is full of negative space" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🔠 Typography and Color
&lt;/h2&gt;

&lt;h3&gt;
  
  
  15. Expressive Typography
&lt;/h3&gt;

&lt;p&gt;Type is no longer just functional. It's huge, it's moving, it's animated. Designers are using expressive fonts as centerpieces instead of just accents.&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%2Fdypwcqo0b8kn3if8chr4.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%2Fdypwcqo0b8kn3if8chr4.png" alt="Expressive typography website" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  16. Color Trends
&lt;/h3&gt;

&lt;p&gt;We’re seeing bold contrasts, saturated gradients, transparent overlays, and interactive themes that respond to user preferences. It's like a paint party for the web.&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%2Fpcmum8dj8yr6xtmzrdgl.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%2Fpcmum8dj8yr6xtmzrdgl.png" alt="Thirsty Dumpling features a striking blue and yellow color palette" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  17. Dark Mode and Light Mode
&lt;/h3&gt;

&lt;p&gt;It’s not just about flipping between black and white anymore. Great dark mode means rethinking design balance, color theory, and accessibility from the ground up.&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%2Fhgwp2db8y01xai7yqtx6.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%2Fhgwp2db8y01xai7yqtx6.png" alt="Play features a very dark color scheme" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🧾 Content Presentation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  18. Text-Only Websites
&lt;/h3&gt;

&lt;p&gt;Text-only layouts are coming back—especially for writers, devs, and minimalist blogs. Super fast, super readable, super raw.&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%2Fmefxzuo1ogw8ned5ufx6.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%2Fmefxzuo1ogw8ned5ufx6.png" alt="People and Blogs features a very clean and minimal text only design" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  19. Custom Illustrations
&lt;/h3&gt;

&lt;p&gt;Illustrations give a site instant personality. Bonus points if they're animated or interactive.&lt;/p&gt;

&lt;h3&gt;
  
  
  20. Blending Images and Graphics
&lt;/h3&gt;

&lt;p&gt;Mixing photography with graphical overlays—like doodles, arrows, and collage elements—is a killer way to add context and creativity.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Technical Enhancements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  21. Chatbot Design
&lt;/h3&gt;

&lt;p&gt;Bots have grown up. They’re now brand reps with personality, custom UIs, and seamless interactions. Think less "tech support" and more "concierge."&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%2Fefezgnvqb5przigrcbk3.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%2Fefezgnvqb5przigrcbk3.png" alt="Domino's Dom is a chatbot that can help you order pizza" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  22. Smart Videos
&lt;/h3&gt;

&lt;p&gt;Silent by default, looped seamlessly, and designed for performance—videos are now ambient design elements instead of content hogs.&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%2Fj2chbdfgq7i971yfbsvm.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%2Fj2chbdfgq7i971yfbsvm.png" alt="The Cartier Agency site demonstrates smart video usage" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  23. Anti-Design
&lt;/h3&gt;

&lt;p&gt;This is the punk rock of web design—clashing colors, chaotic layouts, ugly fonts, and attitude. It shouldn’t work, but sometimes it &lt;em&gt;really&lt;/em&gt; does.&lt;/p&gt;

&lt;h3&gt;
  
  
  24. Increased Focus on UX/UI
&lt;/h3&gt;

&lt;p&gt;The best UI is the one you don’t notice. Expect even more obsession with micro-interactions, user flow, and intuitive design.&lt;/p&gt;

&lt;h3&gt;
  
  
  25. Responsive Web Design
&lt;/h3&gt;

&lt;p&gt;This isn’t a trend—it’s a necessity. But the approach is getting smarter. Think foldables, ultrawides, and screen ratios that weren’t even on our radar 5 years ago.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;2025 web design is all about &lt;strong&gt;personality&lt;/strong&gt;, &lt;strong&gt;playfulness&lt;/strong&gt;, and &lt;strong&gt;performance&lt;/strong&gt;. Trends are moving fast, and if you're not keeping up—you’re falling behind.&lt;/p&gt;

&lt;p&gt;If you’re working on a redesign or planning something new, feel free to reach out. I help businesses build modern, performant websites that are anything but boring. You can check out more of my work and get in touch at &lt;a href="https://spectrumitconsulting.com" rel="noopener noreferrer"&gt;Spectrum IT Consulting&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>design</category>
      <category>webdev</category>
      <category>ui</category>
      <category>ux</category>
    </item>
    <item>
      <title>Meet PostPilot</title>
      <dc:creator>Chris Watson</dc:creator>
      <pubDate>Mon, 11 Nov 2024 23:14:32 +0000</pubDate>
      <link>https://dev.to/watzon/meet-postpilot-ep4</link>
      <guid>https://dev.to/watzon/meet-postpilot-ep4</guid>
      <description>&lt;p&gt;Anyone that's been in web development long enough is familiar with the struggles of testing email, since so many applications require the ability to send emails for one reason or another. Whether it be for authentication, notifications, or just about anything else, email is a crucial part of of the web as it has been for the past few decades.&lt;/p&gt;

&lt;p&gt;The problem is that testing email sending is a pain, and for most developers it means setting up SendGrid, Mailgun, or enabling SMTP on their personal email account. Moreover, once you start actually sending emails you have to deal with them clogging up your inbox while you're testing.&lt;/p&gt;

&lt;p&gt;Granted there are a ton of ways around this. Just to name a few:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use your personal email account (Gmail, Fastmail, ProtonMail, etc.) and enable SMTP&lt;/li&gt;
&lt;li&gt;Have a local mail server be part of your development environment, along with a frontend like &lt;a href="https://squirrelmail.org/" rel="noopener noreferrer"&gt;SquirrelMail&lt;/a&gt; or &lt;a href="https://rainloop.net/" rel="noopener noreferrer"&gt;RainLoop&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Go the tried and true route of setting up an email service like SendGrid, Mailgun, or Postmark&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While these are all valid solutions which I've tried (other than setting up a local mail server), they all have their own drawbacks.&lt;/p&gt;

&lt;p&gt;For example, using your personal email account is great for a quick and dirty solution, but it doesn't scale well when you're testing a large number of emails. Setting up a local mail server is a bit more involved, and while it does scale it adds another layer of complexity to your development environment. Using an email service is a good middle ground, but it adds another dependency to your project and can incur additional costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter PostPilot
&lt;/h2&gt;

&lt;p&gt;For these reasons and more, I've been working on &lt;a href="https://postpilot.watzon.tech" rel="noopener noreferrer"&gt;PostPilot&lt;/a&gt;, a free and open source email testing tool inspired by &lt;a href="https://github.com/axllent/mailpit" rel="noopener noreferrer"&gt;Mailpit&lt;/a&gt; and Laravel Herd.&lt;/p&gt;

&lt;p&gt;For those that aren't aware, the Herd developers &lt;a href="https://herd.laravel.com/docs/1/herd-pro/mail" rel="noopener noreferrer"&gt;solved this issue&lt;/a&gt; as a part of the Laravel stack a while ago by creating a nice GUI that lists sent emails and allows you to view and interact with them. It's a beautiful solution and makes the $100 for a Herd Pro license almost worth it (the other parts of Herd take it from an almost to a definite yes). Unfortunately, it's not free, not open source, only available on macOS and Windows, and is mostly useful for the Laravel ecosystem.&lt;/p&gt;

&lt;p&gt;Like Mailpit, PostPilot is written in Go and comes complete with a beatiful UI, notifications, and the ability to interact with incoming emails. Unlike Mailpit, PostPilot is a GUI application rather than a headless server with a web interface. I won't say either is better or worse, but they do cater to a different audience as far as preferences go.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;PostPilot is in very active development and is very much still in the early stages. I just released version 0.1.2 which is the first actual release, and I have managed so far to get a build process in place for Linux and Windows. As of right now, the recommended way to run PostPilot on macOS would be to build it from source. Once I get to the point where I can afford an Apple developer account and a Windows signing certificate, I'll start working on installers for both platforms.&lt;/p&gt;

&lt;p&gt;The next things I'll be working on are better documentation for the development process, and then I'll be attempting to get some of the more popular features from Mailpit working, like SpamAssassin integration and the ability to filter emails based on certain criteria.&lt;/p&gt;

&lt;p&gt;If you're interested in following along or contributing, you can find the project on &lt;a href="https://github.com/watzon/postpilot" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, and if you want to help me with the ability to get Windows and macOS builds out you can always support me on &lt;a href="https://patreon.com/watzon" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;, &lt;a href="https://github.com/sponsors/watzon" rel="noopener noreferrer"&gt;Github Sponsors&lt;/a&gt;, or &lt;a href="https://ko-fi.com/watzon" rel="noopener noreferrer"&gt;Ko-Fi&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>tooling</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Rediscovering PHP: A Modern Alternative to JavaScript Fatigue</title>
      <dc:creator>Chris Watson</dc:creator>
      <pubDate>Thu, 17 Oct 2024 19:28:59 +0000</pubDate>
      <link>https://dev.to/watzon/rediscovering-php-a-modern-alternative-to-javascript-fatigue-453e</link>
      <guid>https://dev.to/watzon/rediscovering-php-a-modern-alternative-to-javascript-fatigue-453e</guid>
      <description>&lt;p&gt;For many developers, PHP conjures memories of tangled codebases, inconsistent syntax, and a language that seemed stuck in the past. If you've spent the last decade distancing yourself from PHP, you're not alone. But as the JavaScript ecosystem becomes increasingly complex, it's worth reconsidering PHP as a viable and even superior alternative for certain projects. This post aims to shed light on how PHP has evolved and why it might just be the refreshing change you're looking for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The JavaScript Landscape: A Double-Edged Sword
&lt;/h2&gt;

&lt;p&gt;JavaScript has undeniably revolutionized web development, enabling rich, interactive experiences on the client side. However, the ecosystem has become a labyrinth of frameworks, libraries, and build tools. The constant churn—new frameworks supplanting old ones, frequent breaking changes, and an overwhelming number of choices—can lead to what's often termed "JavaScript fatigue".&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Pain Points:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Overwhelming Choices&lt;/strong&gt;: React, Angular, Vue, Svelte—the list goes on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex Tooling&lt;/strong&gt;: Webpack, Babel, ESLint, and a myriad of plugins.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rapid Obsolescence&lt;/strong&gt;: Libraries and frameworks can become outdated quickly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistent Practices&lt;/strong&gt;: Diverse paradigms and styles leading to fragmented codebases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fqllcqjppld9vifrcj1iu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fqllcqjppld9vifrcj1iu.png" alt="Image description" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PHP's Renaissance: Not the Language You Remember
&lt;/h2&gt;

&lt;p&gt;Contrary to its reputation from a decade ago, PHP has undergone significant transformations. Modern PHP is a robust, performant, and developer-friendly language that addresses many of the issues that led developers to abandon it in the first place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Improvements in PHP:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modern Syntax and Features&lt;/strong&gt;: Introduction of type declarations, anonymous classes, arrow functions, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Enhancements&lt;/strong&gt;: PHP 7 and 8 have brought massive speed improvements and reduced memory usage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Error Handling&lt;/strong&gt;: Engine exceptions and clearer error messages make debugging easier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strong Community and Ecosystem&lt;/strong&gt;: Frameworks like Laravel and Symfony embrace modern development practices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fwkumzkdqi05yv8q8byq5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fwkumzkdqi05yv8q8byq5.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Breaking Down PHP's Evolution
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Type Safety and Modern Language Features&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Then (2010):
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Weak typing led to unexpected behaviors.&lt;/li&gt;
&lt;li&gt;Lack of modern programming constructs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Now:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scalar Type Declarations&lt;/strong&gt;: Enforce types for function parameters and return values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Union and Intersection Types&lt;/strong&gt;: Allow variables to hold multiple types.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nullable Types&lt;/strong&gt;: Explicitly define if a variable can be &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arrow Functions&lt;/strong&gt;: Concise one-line anonymous functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Reduced runtime errors and more predictable code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fhfz2oqb3tpjjiam4yotn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fhfz2oqb3tpjjiam4yotn.png" alt="Image description" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Performance That Rivals Competitors&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Then (2010):
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Considered slow and resource-intensive.&lt;/li&gt;
&lt;li&gt;Not suitable for performance-critical applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Now:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PHP 7 and 8&lt;/strong&gt;: Up to 3x performance improvements over PHP 5.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Just-In-Time Compilation&lt;/strong&gt;: Introduced in PHP 8.0 for even faster execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OPcache Extension&lt;/strong&gt;: Built-in caching mechanism for bytecode.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Faster response times and the ability to handle more traffic with fewer resources.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Frplbae9f6y06n09ei325.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Frplbae9f6y06n09ei325.png" alt="Image description" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Asynchronous Programming and Real-Time Applications&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Then (2010):
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Limited to synchronous execution.&lt;/li&gt;
&lt;li&gt;Not suitable for real-time applications like chat or gaming servers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Now:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Async Libraries&lt;/strong&gt;: Tools like ReactPHP and Amp bring asynchronous programming to PHP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebSockets Support&lt;/strong&gt;: Enable real-time, bidirectional communication.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Build scalable real-time applications without switching languages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fmb01bf35p9f08eac5k14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fmb01bf35p9f08eac5k14.png" alt="Image description" width="800" height="547"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Robust Frameworks and Tooling&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Then (2010):
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Few frameworks, often with inconsistent practices.&lt;/li&gt;
&lt;li&gt;Lacked modern development tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Now:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frameworks&lt;/strong&gt;: Laravel, Symfony, and Slim provide solid foundations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composer&lt;/strong&gt;: Dependency management akin to npm, streamlining package installation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing Tools&lt;/strong&gt;: PHPUnit, Pest, and Mockery for comprehensive testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static Analysis&lt;/strong&gt;: Tools like PHPStan and Psalm improve code quality.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Accelerated development with reliable, well-maintained tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F2s16i469buivic5kh53a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F2s16i469buivic5kh53a.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Improved Syntax and Developer Experience&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Then (2010):
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Verbose and sometimes inconsistent syntax.&lt;/li&gt;
&lt;li&gt;Lacked features to write clean, maintainable code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Now:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cleaner Syntax&lt;/strong&gt;: Features like the null coalescing operator (&lt;code&gt;??&lt;/code&gt;), spaceship operator (&lt;code&gt;&amp;lt;=&amp;gt;&lt;/code&gt;), and match expressions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attributes and Enums&lt;/strong&gt;: Introduced in PHP 8 for better code organization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Error Handling&lt;/strong&gt;: Using &lt;code&gt;try-catch&lt;/code&gt; blocks with multiple exceptions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Write cleaner, more maintainable code that is easier to read and debug.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fie8xshox6pyu59k1pko4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fie8xshox6pyu59k1pko4.png" alt="Image description" width="800" height="794"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PHP vs. JavaScript: Where PHP Shines
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Simplicity Over Complexity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;PHP offers a more straightforward approach to web development. With a single, cohesive language for both front-end (with templating engines) and back-end, the cognitive load is reduced.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Building a simple CRUD application can be faster and less complex in PHP using frameworks like Laravel, compared to setting up a full JavaScript stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Stability and Backward Compatibility&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;PHP maintains a focus on backward compatibility and gradual deprecation, minimizing the impact on existing codebases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contrast:&lt;/strong&gt; JavaScript frameworks often introduce breaking changes that require significant refactoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Mature Ecosystem for Web Development&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;PHP was built for the web. It excels in serving dynamic web pages and has a mature ecosystem for tasks like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Content Management Systems&lt;/strong&gt;: WordPress, Drupal, and Joomla.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E-commerce Platforms&lt;/strong&gt;: Magento, PrestaShop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Development&lt;/strong&gt;: Quick and efficient RESTful APIs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2F1w0vvv2ofijn2khbzoe8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F1w0vvv2ofijn2khbzoe8.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Use Cases Where Modern PHP Excels
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Command-Line Applications and Automation&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Symfony Console&lt;/strong&gt;: Build powerful CLI tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation Scripts&lt;/strong&gt;: Manage tasks like deployments and database migrations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Static Site Generation&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;: Sculpin and Jigsaw allow you to generate static sites with PHP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benefits&lt;/strong&gt;: Utilize PHP's templating engines for static content.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Microservices and APIs&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight Frameworks&lt;/strong&gt;: Slim and Lumen for microservices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Efficient handling of API requests with low overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Real-Time Applications&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WebSockets&lt;/strong&gt;: Implement real-time features like chats and notifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async PHP&lt;/strong&gt;: Handle concurrent connections efficiently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2F7u4dau15goybje95whd7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F7u4dau15goybje95whd7.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Embracing PHP in a Modern Workflow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Composer: PHP's Package Manager&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Management&lt;/strong&gt;: Easily include and manage libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Packagist Repository&lt;/strong&gt;: Access to thousands of packages.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Frameworks That Leverage Modern PHP&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Laravel&lt;/strong&gt;: Offers elegance and simplicity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Symfony&lt;/strong&gt;: A robust enterprise-level framework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Platform&lt;/strong&gt;: Build APIs effortlessly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Interoperability and Integration&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docker Support&lt;/strong&gt;: Containerize PHP applications for consistency across environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous Integration&lt;/strong&gt;: Integrate with tools like Jenkins, Travis CI, and GitHub Actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Overcoming the Stigma: Why You Should Give PHP Another Chance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Misconceptions Persist&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Many criticisms of PHP are based on outdated information or experiences from older versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Community and Support&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A vibrant community contributes to an ever-improving ecosystem, providing tutorials, packages, and support.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Job Opportunities&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;PHP remains widely used in the industry, with many companies seeking developers proficient in modern PHP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Focunx39ih7sb1z9q1jqa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Focunx39ih7sb1z9q1jqa.png" alt="Image description" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with Modern PHP
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Update Your Knowledge&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: Visit the official PHP docs to learn about new features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tutorials&lt;/strong&gt;: Platforms like Laracasts offer in-depth lessons.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Experiment with Frameworks&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Laravel New&lt;/strong&gt;: Create a new Laravel project and explore its features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Symfony Demo&lt;/strong&gt;: Test out Symfony's capabilities with their demo application.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Join the Community&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Conferences&lt;/strong&gt;: Attend PHP conferences and meetups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forums and Groups&lt;/strong&gt;: Engage with others on platforms like Reddit's r/PHP or PHP UG groups.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fdb8z4dys5lmcez6mun92.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fdb8z4dys5lmcez6mun92.png" alt="Image description" width="768" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: A Fresh Start with PHP
&lt;/h2&gt;

&lt;p&gt;If you've been disheartened by the complexities of the current JavaScript ecosystem, it's time to take a fresh look at PHP. The language has matured significantly, shedding its old baggage and adopting modern programming paradigms. With improved performance, a wealth of new features, and a focus on developer experience, PHP offers a stable and efficient alternative for web development and beyond.&lt;/p&gt;

&lt;p&gt;So, dust off your old perceptions, and give PHP another chance. You might be pleasantly surprised by what you find.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fc6ex0bm7cifjqqmknqcm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fc6ex0bm7cifjqqmknqcm.png" alt="Image description" width="800" height="547"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Thank you for reading! If you have experiences with modern PHP or thoughts on the current state of JavaScript, feel free to share in the comments below.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Cursor has a problem, and it's not just the price</title>
      <dc:creator>Chris Watson</dc:creator>
      <pubDate>Wed, 16 Oct 2024 16:49:55 +0000</pubDate>
      <link>https://dev.to/watzon/cursor-has-a-problem-and-its-not-just-the-price-4cpl</link>
      <guid>https://dev.to/watzon/cursor-has-a-problem-and-its-not-just-the-price-4cpl</guid>
      <description>&lt;p&gt;Cursor is a controversial AI code editor forked from VS Code and backed by Y Combinator. The controversies range from the $20-a-month price tag for a limited number of queries, to the closed-source nature of the editor, which was forked from an open-source project, and, of course, to the broader controversy around AI itself. However, this post isn't about any of that.&lt;/p&gt;

&lt;p&gt;Surprisingly, one issue I haven't seen discussed much is how Cursor seems to treat Linux as a second-class citizen. To understand what I mean by that, it's important to understand the AppImage format. So let's dive into that for a moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AppImage
&lt;/h2&gt;

&lt;p&gt;In simple terms, AppImages are a "build once, run anywhere" package format for Linux. They bundle all the necessary files, including shared libraries, into a virtual filesystem and add a runtime layer that makes launching your app straightforward. If this sounds similar to Flatpak and Snap, that's because it is. The key difference is that you don't need to install anything to run an AppImage—everything is self-contained.&lt;/p&gt;

&lt;p&gt;AppImages, however, come with their own set of issues. One major drawback is that they can't be easily installed like applications from your distribution's package manager. While you can download and run them without much hassle, they lack desktop integration unless you put in extra effort. Tools like &lt;a href="https://appimage.github.io/AppImagePool/" rel="noopener noreferrer"&gt;AppImagePool&lt;/a&gt; and &lt;a href="https://github.com/mijorus/gearlever" rel="noopener noreferrer"&gt;Gear Lever&lt;/a&gt; help alleviate this, but at that point, you might as well use Flatpak or Snap to benefit from their built-in sandboxing capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cursor on Linux
&lt;/h2&gt;

&lt;p&gt;When you download Cursor for Linux, you get an AppImage. If you're using a distribution like Arch, this isn't as much of an issue because the AUR provides a way for users to make the installation process easier (though it's not perfect, as we'll discuss). For the majority of other distributions, however, you're stuck dealing with the AppImage format and its limitations. Now we can finally get to the part that's been the biggest pain for me.&lt;/p&gt;

&lt;p&gt;Coming from VS Code, I had certain expectations when using Cursor. Call it a first-world problem, but I want to be able to launch the editor from the command line, just like you can with VS Code's shell command. You can get part of the way there by renaming &lt;code&gt;cursor.AppImage&lt;/code&gt; to &lt;code&gt;cursor&lt;/code&gt; and adding it to your PATH, but this approach is flawed. The biggest issue—at least from my perspective—is that it takes over the terminal, making the window/tab unusable while Cursor is open. It also means you have to keep the terminal open.&lt;/p&gt;

&lt;p&gt;To address this, you can run the process in the background using &lt;code&gt;cursor . &amp;amp;&lt;/code&gt;, but this still results in occasional logs appearing in your terminal. To suppress these, you can pipe the output to &lt;code&gt;/dev/null&lt;/code&gt; by running &lt;code&gt;cursor &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&lt;/code&gt;. While this mostly resolves the problem, it's not a very convenient command to run every time you open Cursor.&lt;/p&gt;

&lt;p&gt;Ultimately, installing Cursor on Linux is cumbersome, and using it remains a hassle compared to alternatives like VS Code or Zed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;One potential solution is to add a &lt;code&gt;cursor&lt;/code&gt; function to your shell profile to handle launching Cursor. This is the workaround I've been using, but it's still far from ideal. Not only do I have to write the script myself, but I also need to set it up on every system where I want to use Cursor. Moreover, I still have to deal with manually installing the AppImage, and updating it requires re-downloading from the Cursor website.&lt;/p&gt;

&lt;p&gt;So I did what I do best—I wrote some code. Specifically, I created a few bash scripts and made them available for anyone to use. You can find the project at &lt;a href="https://github.com/watzon/cursor-linux-installer" rel="noopener noreferrer"&gt;github.com/watzon/cursor-linux-installer&lt;/a&gt;, and it can be installed with a single CURL command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -fsSL https://raw.githubusercontent.com/watzon/cursor-linux-installer/main/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since all of the code is public, I encourage you to audit it before running it, and please let me know if you encounter any issues. I'm fully aware that this is a solution looking for a problem, but it has been a personal annoyance for me, and until the Cursor team decides to create distro-specific installers or a Flatpak version, this is the method I'll continue using.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>vscode</category>
      <category>programming</category>
      <category>devops</category>
    </item>
    <item>
      <title>Safari-like archive handling in Linux</title>
      <dc:creator>Chris Watson</dc:creator>
      <pubDate>Sun, 19 Sep 2021 01:12:05 +0000</pubDate>
      <link>https://dev.to/watzon/safari-like-archive-handling-in-linux-34eg</link>
      <guid>https://dev.to/watzon/safari-like-archive-handling-in-linux-34eg</guid>
      <description>&lt;p&gt;Just wanted to share this, because I spent all morning figuring it out for myself. As someone that's used macOS a lot recently one of the features I really appreciate is Safari's ability to automatically extract archives when you open them. Granted that's about the only feature I appreciate about Safari, but I'll give credit where credit is due.&lt;/p&gt;

&lt;p&gt;Having recently reinstalled Arch on my home workstation this is one the the features that I've really missed, so this morning I decided to add the feature myself.&lt;/p&gt;

&lt;p&gt;Starting off I knew I'd most likely need to write a script and somehow associate the mime-types of the various archives I want to open with that script. Keep in mind that these instructions are known to work on GNOME and require the zsh shell. Different types of archives also require different programs to open them.&lt;/p&gt;

&lt;p&gt;Here are the 2 files you're going to need. I'll explain them a bit further down.&lt;/p&gt;

&lt;p&gt;First is &lt;code&gt;extract.zsh&lt;/code&gt; (place this in &lt;code&gt;~/.local/bin&lt;/code&gt;):&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And then the desktop file (place this in &lt;code&gt;~/.local/share/applications&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;Honestly it's super simple, and makes use of &lt;a href="https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/extract" rel="noopener noreferrer"&gt;some existing code&lt;/a&gt; from Oh-My-ZSH. &lt;code&gt;extract.zsh&lt;/code&gt; checks the extension of the file you're trying to extract and matches it with the correct program for opening that file. This script was meant to be used as a zsh plugin, but I repurposed it. In doing so I needed to change the output directory (initially files were being extracted to my user's home directory) and make it automatically overwrite existing directories since we wanted this process to be automatic.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;.desktop&lt;/code&gt; file allows the script to be registered as the default program for a given mime-type. All you have to do is open one archive with a given extension using the &lt;code&gt;extract&lt;/code&gt; menu option and that's it, extract is now the default program for opening those archives.&lt;/p&gt;

&lt;p&gt;Now for the little bit of setup:&lt;/p&gt;

&lt;p&gt;Any archive formats you want to have automatically extract need to be opened with extract so that the default for that archive type can be changed. To do this (on GNOME) right click an archive, select "Open With Other Application", click "Find New Applications" at the bottom of the dialog, and then find &lt;code&gt;extract&lt;/code&gt; in the list. If you don't see it you may need to log out and then log back in again.&lt;/p&gt;

&lt;p&gt;That's really it. Now download an archive and try opening it directly from the downloads menu in your browser. The archive should be extracted and then the directory automatically opened.&lt;/p&gt;

</description>
      <category>systems</category>
      <category>linux</category>
    </item>
    <item>
      <title>Debugging Zig with VS Code</title>
      <dc:creator>Chris Watson</dc:creator>
      <pubDate>Tue, 07 Jul 2020 22:07:03 +0000</pubDate>
      <link>https://dev.to/watzon/debugging-zig-with-vs-code-44ca</link>
      <guid>https://dev.to/watzon/debugging-zig-with-vs-code-44ca</guid>
      <description>&lt;p&gt;I've seen questions regarding this both on Reddit and in the Zig Discord, so I wanted to take a minute to share to all those Ziggites (Ziggies? Ziggos? Zigstronauts?) out there how to easily debug their Zig programs using VS Code and GDB.&lt;/p&gt;

&lt;p&gt;First, of course, you will need both VS Code and GDB installed. If you don't... well get them. I'll wait.&lt;/p&gt;

&lt;p&gt;Now, with VS Code opened, press Ctrl + p (Cmd + p for those Mac people), paste &lt;code&gt;ext install webfreak.debug&lt;/code&gt; into the command input box, and hit enter. This will install the wonderfully built Native Debug extension for VS Code which supports GDB &lt;em&gt;and&lt;/em&gt; LLDB. In this walkthrough I'll be giving GDB instructions, but you should be able to make it work with LLDB with very few changes.&lt;/p&gt;

&lt;p&gt;Now we need to make a build file. Since Zig is compiled, your program obviously needs to be built before it can be run. Press Ctrl + Shift + p and search for "Tasks: Configure Default Build Task", select it, and follow the prompts until you have a &lt;code&gt;tasks.json&lt;/code&gt; file created. You will want to create a "build" task which basically runs &lt;code&gt;zig build&lt;/code&gt; with whatever arguments you need. As a point of reference, mine looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tasks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shell"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"zig build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"problemMatcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"isDefault"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;all it does is run &lt;code&gt;zig build&lt;/code&gt; in the current working directory. My &lt;code&gt;build.zig&lt;/code&gt; file does the rest.&lt;/p&gt;

&lt;p&gt;Next you will need a &lt;code&gt;launch.json&lt;/code&gt;. This can be created by once again pressing Ctrl + Shift + p and searching for "Debug: Open launch.json". When prompted, choose the "C++ (GDB/LLDB)" option. This will generate a &lt;code&gt;launch.json&lt;/code&gt; file for you, which will be responsible for telling VS Code how to launch and attach the debugger, in our case GDB.&lt;/p&gt;

&lt;p&gt;You'll need to change the &lt;code&gt;program&lt;/code&gt; option to the location where your built program will be output, in my case it's "./zig-cache/bin/build", but this will vary.&lt;/p&gt;

&lt;p&gt;You'll also need to add &lt;code&gt;preLaunchTask&lt;/code&gt; as an option, and set its value to the name of your build command. In the above example the task name is "build". Your final &lt;code&gt;launch.json&lt;/code&gt; should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"configurations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(gdb) Launch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cppdbg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"launch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./zig-cache/bin/build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"stopAtEntry"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"cwd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${workspaceFolder}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"externalConsole"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"MIMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gdb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"preLaunchTask"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"setupCommands"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Enable pretty-printing for gdb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-enable-pretty-printing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"ignoreFailures"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's really it. Try it out by setting some breakpoints in your code, heading over to the debug tab in the activity bar, and pressing play.&lt;/p&gt;

&lt;p&gt;Hope this helped!&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>gdb</category>
      <category>zig</category>
      <category>lldb</category>
    </item>
    <item>
      <title>Browsing The Web With Crystal</title>
      <dc:creator>Chris Watson</dc:creator>
      <pubDate>Mon, 12 Aug 2019 06:39:33 +0000</pubDate>
      <link>https://dev.to/watzon/browsing-the-web-with-crystal-3mf2</link>
      <guid>https://dev.to/watzon/browsing-the-web-with-crystal-3mf2</guid>
      <description>&lt;p&gt;If you've been in the web development industry for any decent amount of time it's likely you've heard mention of tools like Selenium, WebDriver, and Puppeteer. These are mainly touted as "testing automation frameworks" because they enable developers to automate the testing of web apps by saying "go here", "click this", "take a screenshot and compare it against a previous screenshot and make sure nothing's changed". These tools are also helpful with web scraping, as they allow you to see web pages exactly as the browser sees them. This means JavaScript rendered content is scrapable!&lt;/p&gt;

&lt;p&gt;To date Selenium is probably the most popular of these tools. It's used everywhere, from testing environments and CI's to web scrapers and pentesting tools. It is extremely powerful, but has one major drawback. Java.&lt;/p&gt;

&lt;p&gt;Anyone who's used written or used a Java application knows that it has one major drawback. Memory usage. Java applications are heavy, which limits their usefulness on systems with less resources and containerized applications. This doesn't stop people from trying, but why use extra resources if you don't have to?&lt;/p&gt;

&lt;p&gt;So, with speed and memory efficiency in mind, I set about recently to devise my own solution for the Crystal ecosystem; a solution I decided to call Marionette after the Firefox Marionette protocol.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring Marionette
&lt;/h2&gt;

&lt;p&gt;Of course before wrapping any kind of API you have to do some research. Unfortunately, Marionette is not super well documented. Marionette and WebDriver share a lot in terms of methods and functionality, with Marionette building on top of the functionality that the WebDriver protocol provides.&lt;/p&gt;

&lt;p&gt;Naturally my first Google search was for "firefox marionette protocol", which led me to &lt;a href="https://firefox-source-docs.mozilla.org/testing/marionette/marionette/Protocol.html" rel="noopener noreferrer"&gt;this page&lt;/a&gt; which describes the protocol, but not in near as much detail as I'd hope. That being said, it does at least describe the format that a message must take when being sent to Firefox. Unfortunately after browsing the whole Marionette section of that site I didn't find any information on what commands the Marionette protocol accepted. So I continued my search.&lt;/p&gt;

&lt;p&gt;Something I had seen in the Marionette documentation was mention of a Python client. Now I make it very well known to people I talk to my extreme distaste for all things Python, but if it could help me figure out what methods the Marionette protocol had available it would be worth it. So I followed a link to their &lt;a href="https://searchfox.org/mozilla-central/source/testing/marionette/client/" rel="noopener noreferrer"&gt;reference client&lt;/a&gt; and dove into the Python code (which I was happy to find was actually very well written).&lt;/p&gt;

&lt;p&gt;After a little bit of digging I found what I was looking for! &lt;a href="https://searchfox.org/mozilla-central/source/testing/marionette/client/marionette_driver/marionette.py" rel="noopener noreferrer"&gt;This file&lt;/a&gt; includes most of the methods that the Python client uses for interacting with Marionette,including the names of the methods and the format in which messages are sent. And so began the process of building my own client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Client
&lt;/h2&gt;

&lt;p&gt;The main client functionality was fairly straightforward, seeing as I had a fully functioning Python client to work off of. I also managed to find a client &lt;a href="https://github.com/njasm/marionette_client" rel="noopener noreferrer"&gt;written in Go&lt;/a&gt; that was very similar, but not quite as powerful as the Python client. I still have never managed to find a list of RPC commands that Marionette accepts, but between those two clients I was able to build my own fairly easily.&lt;/p&gt;

&lt;p&gt;Now this project wouldn't have been possible, at least not in the amount of time I've been able to get it working, without the help of &lt;a href="https://neuralegion.com" rel="noopener noreferrer"&gt;NeuraLegion&lt;/a&gt;, my employer who is sponsoring its development.&lt;/p&gt;

&lt;p&gt;NeuraLegion is an application security company with a SASS AIAST solution powered by AI. Or, for people who don't speak penetration tester, a company that tests the security of websites and other applications using software that's powered by artificial intelligence. That software has to be capable of browsing the web in the same way as you or I, but it also needs to be able to do things you normally don't do in every day web browsing, such as modify HTTP headers, send attack payloads in a POST request to an open API route, etc. Because of this, just a standard Selenium type client wasn't good enough.&lt;/p&gt;

&lt;p&gt;We needed a proxy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Proxy
&lt;/h2&gt;

&lt;p&gt;There are two main types of proxy: a forward proxy which is used to forward outgoing requests from a private network or intranet to the Internet, usually through a firewall, and a reverse proxy which retrieves resources on behalf of a client from one or more servers; these resources are then returned to the client, appearing as if they originated from the proxy server itself.&lt;/p&gt;

&lt;p&gt;Firefox, and thereby marionette, has built in support for forward proxies. All you have to do is provide it with a address for the HTTP proxy, HTTPS proxy, and potentially FTP and SOCKS proxies and it will tunnel all requests through those before hitting the browser. Unfortunately this requires a separate proxy for each, and tunneling HTTPS requests turns out to be much more difficult. So it was decided that a reverse proxy would make more sense.&lt;/p&gt;

&lt;p&gt;I won't go into full detail about how the reverse proxy works, if you want to check out the code you can find it &lt;a href="https://github.com/watzon/marionette/blob/master/src/marionette/proxy.cr" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Basically what it all amounts to is this:&lt;/p&gt;

&lt;p&gt;When Marionette is launched with the &lt;code&gt;extended&lt;/code&gt; option set to &lt;code&gt;true&lt;/code&gt; a &lt;code&gt;Proxy&lt;/code&gt; object is instantiated and the server is launched. The &lt;code&gt;Browser#goto&lt;/code&gt; method then forwards all navigation requests to the proxy and tells it what page to fetch. The proxy fetches the resource and does a little &lt;code&gt;gsub&lt;/code&gt; magic on the page's content, replacing all internal links with a link to the proxy server instead. All internal resources are then tunneled though the proxy as they're fetched, allowing us to potentially be able to modify javascript, images, etc. before they reach the page. Everything is then packaged back up and returned to the browser as if nothing had happened.&lt;/p&gt;

&lt;p&gt;Basically what this means is that you can do whatever you want with pages before the browser even knows they've been touched, which can be very powerful for AppSec.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using It
&lt;/h2&gt;

&lt;p&gt;Ok so I've done enough boring you with how Marionette works under the hood, let's look at how you actually use it.&lt;/p&gt;

&lt;p&gt;First, in case it wasn't obvious or if you just jumped down to this section, Marionette requires Crystal to run. So if you don't have Crystal installed &lt;a href="https://crystal-lang.org/reference/installation/" rel="noopener noreferrer"&gt;you may want to go download it&lt;/a&gt; if you intend to follow along. You will also need Firefox installed.&lt;/p&gt;

&lt;p&gt;The first thing you'll need to do is fire up your terminal and create a new Crystal project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crystal init app browser
&lt;span class="nb"&gt;cd &lt;/span&gt;browser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add Marionette as a dependency in your &lt;code&gt;shard.yml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;marionette&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;github&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;watzon/marionette&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.1.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run &lt;code&gt;shards install&lt;/code&gt; in your terminal and Marionette should be installed to the &lt;code&gt;lib&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Now let's open up &lt;code&gt;src/browser.cr&lt;/code&gt; and add the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"marionette"&lt;/span&gt;

&lt;span class="no"&gt;Marionette&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://dev.to"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure Firefox is not currently running, if it is this won't work since Firefox only allows one instance at a time. Now in your terminal run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crystal run ./src/browser.cr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a few seconds you should see a bunch of debug statements in blue and in white&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEV Community 👩‍💻👨‍💻
https://dev.to/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congrats! It worked! But that's not even close to all Marionette has to offer. Why don't we do something fun, like take a screenshot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"marionette"&lt;/span&gt;

&lt;span class="no"&gt;Marionette&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://dev.to"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;save_screenshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"dev.to.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;full: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As of the time of writing, this is what "dev.to.jpg" looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FDtxmtCW.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FDtxmtCW.png" alt="dev.to"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;full: false&lt;/code&gt; option allowed us to just capture what's in the viewport. If you didn't have that option set to true you would end up with a very large image.&lt;/p&gt;

&lt;p&gt;For our last little test, let's visit a bunch of sites and then export a HAR file. A HAR file, for those that aren't aware, is a JSON-formatted archive file format for logging of a web browser's interaction with a site. Basically it is able to store all the details about a page load.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"marionette"&lt;/span&gt;

&lt;span class="no"&gt;Marionette&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://www.google.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://neuralegion.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://watzon.tech"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;export_har&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"multisite.har"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this finishes running you should have a file called &lt;code&gt;multisite.har&lt;/code&gt; in your current working directory. You can test that it worked correctly by using Google's &lt;a href="https://toolbox.googleapps.com/apps/har_analyzer/" rel="noopener noreferrer"&gt;HAR Analyzer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I have tried to document Marionette extremely well in the &lt;a href="https://github.com/watzon/marionette#readme" rel="noopener noreferrer"&gt;readme&lt;/a&gt; and in the &lt;a href="https://watzon.github.io/marionette/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;, so if you're interested in the project please go take a look. Contributions are always accepted, as are suggestions.&lt;/p&gt;

&lt;p&gt;Thanks for reading this. Please don’t forget to hit one of the the Ego Booster buttons (personally I like the unicorn), and if you feel so inclined share this to social media. If you share to twitter be sure to tag me at @_watzon.&lt;/p&gt;

&lt;p&gt;Some helpful links:&lt;br&gt;
&lt;a href="https://crystal-lang.org/" rel="noopener noreferrer"&gt;https://crystal-lang.org/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/kostya/benchmarks" rel="noopener noreferrer"&gt;https://github.com/kostya/benchmarks&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/kostya/crystal-benchmarks-game" rel="noopener noreferrer"&gt;https://github.com/kostya/crystal-benchmarks-game&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/crystal-lang/crystal" rel="noopener noreferrer"&gt;https://github.com/crystal-lang/crystal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Find me online:&lt;br&gt;
&lt;a href="https://medium.com/@watzon" rel="noopener noreferrer"&gt;https://medium.com/@watzon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/_watzon" rel="noopener noreferrer"&gt;https://twitter.com/_watzon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/watzon" rel="noopener noreferrer"&gt;https://github.com/watzon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://watzon.tech" rel="noopener noreferrer"&gt;https://watzon.tech&lt;/a&gt;&lt;/p&gt;

</description>
      <category>crystal</category>
      <category>firefox</category>
      <category>marionette</category>
      <category>automation</category>
    </item>
    <item>
      <title>Understating abstract classes</title>
      <dc:creator>Chris Watson</dc:creator>
      <pubDate>Sat, 27 Jul 2019 05:54:49 +0000</pubDate>
      <link>https://dev.to/watzon/understating-abstract-classes-4ejj</link>
      <guid>https://dev.to/watzon/understating-abstract-classes-4ejj</guid>
      <description>&lt;p&gt;Before we begin, mandatory dictionary definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ab·stract&lt;/strong&gt; [adj] /abˈstrakt,ˈabˌstrakt/&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;existing in thought or as an idea but not having a physical or concrete existence.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Abstractions are an extremely helpful, albeit difficult to understand concept in programming. After all, if abstractions were easy to understand they probably wouldn't be abstract... Would they?&lt;/p&gt;

&lt;p&gt;Abstract classes are just one form of abstraction that exists in programming, and the one I'll be going over in this post. This was inspired by a question from &lt;a class="mentioned-user" href="https://dev.to/girng"&gt;@girng&lt;/a&gt; on the &lt;a href="https://forum.crystal-lang.org/t/difference-between-abstract-def-and-def/998" rel="noopener noreferrer"&gt;crystal-lang forum&lt;/a&gt;. Since the original question was a Crystal question, and since Crystal is currently my favorite language I will be using Crystal examples, but a lot of the concepts transfer to other languages, even if the implementation is different.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are abstract classes?
&lt;/h2&gt;

&lt;p&gt;Abstract classes are classes which are meant to be inherited, but not instantiated. They act as a base for other classes by providing methods that are should exist on all child classes without actually implementing those methods.&lt;/p&gt;

&lt;p&gt;An example of a simple abstract class is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;
  &lt;span class="n"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case we have a class &lt;code&gt;Foo&lt;/code&gt; which has an abstract method &lt;code&gt;bar&lt;/code&gt;. The &lt;code&gt;bar&lt;/code&gt; method must accept a single string parameter and must return a string array. Note that if we try and create an instance of the &lt;code&gt;Foo&lt;/code&gt; class the compiler will throw an error. If we want &lt;code&gt;Foo&lt;/code&gt; to be useful we have to extend it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Baz&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Foo&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we've defined a class &lt;code&gt;Baz&lt;/code&gt; which implements the &lt;code&gt;bar&lt;/code&gt; method exactly as described. Let's try and make the compiler throw an error though.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This will throw an error since `bar` is not defined on `Baz`&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Baz&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Foo&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# This will throw an error since `bar` has the incorrect definition&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Baz&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Foo&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Abstract classes can also define actual methods to be included in child classes. Those methods can be initializers or any other type of method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; initalized"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Baz&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Foo&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;baz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Baz&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "Baz initalized"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where should I use them?
&lt;/h2&gt;

&lt;p&gt;Abstract classes are useful in a number of situations, but the number one example that springs to mind is with adapters, such as for different databases. Databases are a good example because they all have similar functionality, but they all do things in a slightly different way.&lt;/p&gt;

&lt;p&gt;Here is a super basic example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt;
  &lt;span class="c1"&gt;# Implementation&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Adapter&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@url&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Int64&lt;/span&gt;

  &lt;span class="c1"&gt;# Other methods...&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Mysql&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Adapter&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Insert stuff&lt;/span&gt;
    &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Postgres&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Adapter&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Insert stuff&lt;/span&gt;
    &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obviously this is not a functional example, but it should compile and illustrates the basic concept. For a working example you can check out &lt;a href="https://github.com/amberframework/granite/blob/master/src/adapter/base.cr" rel="noopener noreferrer"&gt;&lt;code&gt;Granite::Adapter::Base&lt;/code&gt;&lt;/a&gt; from &lt;a href="https://github.com/amberframework/granite" rel="noopener noreferrer"&gt;amberframework/granite&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading this. Please don’t forget to hit one of the the Ego Booster buttons (personally I like the unicorn), and if you feel so inclined share this to social media. If you share to twitter be sure to tag me at @_watzon.&lt;/p&gt;

&lt;p&gt;Some helpful links:&lt;br&gt;
&lt;a href="https://crystal-lang.org/" rel="noopener noreferrer"&gt;https://crystal-lang.org/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/kostya/benchmarks" rel="noopener noreferrer"&gt;https://github.com/kostya/benchmarks&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/kostya/crystal-benchmarks-game" rel="noopener noreferrer"&gt;https://github.com/kostya/crystal-benchmarks-game&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/crystal-lang/crystal" rel="noopener noreferrer"&gt;https://github.com/crystal-lang/crystal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Find me online:&lt;br&gt;
&lt;a href="https://medium.com/@watzon" rel="noopener noreferrer"&gt;https://medium.com/@watzon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/_watzon" rel="noopener noreferrer"&gt;https://twitter.com/_watzon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/watzon" rel="noopener noreferrer"&gt;https://github.com/watzon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://watzon.tech" rel="noopener noreferrer"&gt;https://watzon.tech&lt;/a&gt;&lt;/p&gt;

</description>
      <category>crystal</category>
      <category>abstract</category>
      <category>class</category>
      <category>programming</category>
    </item>
    <item>
      <title>Doing Crystal #3: Types, types, types</title>
      <dc:creator>Chris Watson</dc:creator>
      <pubDate>Thu, 23 May 2019 11:26:58 +0000</pubDate>
      <link>https://dev.to/watzon/doing-crystal-3-types-types-types-5gdf</link>
      <guid>https://dev.to/watzon/doing-crystal-3-types-types-types-5gdf</guid>
      <description>&lt;p&gt;Welcome to the third post in my Doing Crystal series. In this post I'll be focusing on Crystal's type system, it's benefits, and the drawbacks. If you haven't read the other articles in this series you can find them &lt;a href="https://dev.to/watzon/doing-crystal-1-a-ruby-comparison-4g9c"&gt;here&lt;/a&gt;, and &lt;a href="https://dev.to/watzon/doing-crystal-2-getting-started-with-crystal-13dk"&gt;here&lt;/a&gt; for posts one and two respectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static vs Dynamic Typing
&lt;/h2&gt;

&lt;p&gt;Static typing has existed in programming for years, going back as far as FORTRAN which was first released back in 1957. Now in truth all programming languages are typed, even languages such as JavaScript and Ruby have types such as Integers, Arrays, and Strings. This is necessary because in the real world things have specific properties which are unique to that thing. Numbers and strings are inherently different and, even though you could technically add a number to a string by taking the string down to its binary representation and adding the number to that, in real world terms it just doesn't make sense. Hence, we have types.&lt;/p&gt;

&lt;p&gt;The difference is in how the types are handled. With languages like JavaScript and Ruby types are handled dynamically. This allows you to do things like the following Ruby example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;first_and_last&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;first_and_last&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"fellow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"developers"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; ["Hello", "developers"]&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;first_and_last&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; NoMethodError (undefined method `length' for 42:Integer)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the method &lt;code&gt;first_and_last&lt;/code&gt; is supposed to accept an Array and return the first and last elements as a new Array. It works fine when handed the type of data it expects, but when handed a number it throws a runtime error &lt;code&gt;NoMethodError&lt;/code&gt;. Dynamic typing can be extremely handy, but it can also be detrimental as a large number of runtime errors (or errors that occur while your program is running as opposed to when it's compiled) occur when the program attempts to use a method that doesn't exist, or when a variable's type changes unexpectedly.&lt;/p&gt;

&lt;p&gt;Now let's look at the same code from before, but in Crystal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;first_and_last&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;U&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="no"&gt;U&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="no"&gt;U&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;first_and_last&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"fellow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"developers"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;first_and_last&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this one I didn't show an output. Why? Because the program won't compile. Let's go over the program line by line, and then I'll explain why the compilation fails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;first_and_last&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;U&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="no"&gt;U&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First we do a method definition. This is similar to the Ruby example, but there a a couple of important differences. First we have the weird &lt;code&gt;arr : Array(U)&lt;/code&gt; syntax. This is setting the property name to &lt;code&gt;arr&lt;/code&gt; and the type of &lt;code&gt;arr&lt;/code&gt; to an &lt;code&gt;Array&lt;/code&gt; of type &lt;code&gt;U&lt;/code&gt;. &lt;code&gt;U&lt;/code&gt; in this case is a placeholder type, and outside the scope of this tutorial, but suffice it to say it allows &lt;code&gt;U&lt;/code&gt; to be anything. The &lt;code&gt;forall U&lt;/code&gt; part at the end creates the &lt;code&gt;U&lt;/code&gt; generic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is exactly the same as the Ruby example save the slight method name change for getting the size of an array. In Ruby it's &lt;code&gt;length&lt;/code&gt; and in Crystal it's &lt;code&gt;size&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="no"&gt;U&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Crystal all things have a specific type. This prevents runtime errors and lowers memory usage since the program can allocate the resources it knows it needs. As such, all Arrays, Hashes, Sets, etc. have to be explicitly typed and that is what this line is doing. If the Array the method is handed doesn't have anything in it we just return an empty Array. Truthfully we probably should've returned the same array we were given, but I wanted to show an example of assigning an Array a type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;first_and_last&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"fellow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"developers"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line will work as expected and return &lt;code&gt;["Hello", "developers"]&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;first_and_last&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the line that breaks things. Our method expects an &lt;code&gt;Array&lt;/code&gt;, but instead we handed it an &lt;code&gt;Int32&lt;/code&gt;. Because of this breach of contract the compiler throws an exception.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;no overload matches &lt;span class="s1"&gt;'first_and_last'&lt;/span&gt; with &lt;span class="nb"&gt;type &lt;/span&gt;Int32
Overloads are:
 - first_and_last&lt;span class="o"&gt;(&lt;/span&gt;arr : Array&lt;span class="o"&gt;(&lt;/span&gt;U&lt;span class="o"&gt;))&lt;/span&gt;

  first_and_last&lt;span class="o"&gt;(&lt;/span&gt;42&lt;span class="o"&gt;)&lt;/span&gt;
  ^~~~~~~~~~~~~~
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, it's still an error, but this time it's happening before you release your code. Catching bugs early is a wonderful thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type Declaration in Crystal
&lt;/h2&gt;

&lt;p&gt;You've seen a little of how types are declared in Crystal, now let's look at some more examples. Types are almost always declared in the following way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="c1"&gt;# var_name : Type&lt;/span&gt;
&lt;span class="n"&gt;arr&lt;/span&gt;  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;str&lt;/span&gt;  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Hello, world!"&lt;/span&gt;
&lt;span class="n"&gt;int&lt;/span&gt;  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Int32&lt;/span&gt;                &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;span class="nb"&gt;hash&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"user"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"watzon"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like with Ruby, everything in Crystal is an Object and all Objects are valid Types, so custom classes, structs, etc. are also valid types. Now, there is another way to declare a type when it comes to Hashes and Arrays.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Int32&lt;/span&gt;
&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="no"&gt;Int32&lt;/span&gt;            &lt;span class="c1"&gt;# Assigning type declaration&lt;/span&gt;

&lt;span class="n"&gt;hsh&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;hsh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt; &lt;span class="c1"&gt;# Assigning type declaration&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With most types (Int, String, Class) you can just assign the object to a variable without explicitly declaring the type. This is called type inference and it's extremely handy. You can do the same with Arrays and Hashes as well, provided they contain data, but if they're empty as in the previous example you will have to explicitly declare the type of the Array or Hash.&lt;/p&gt;

&lt;h3&gt;
  
  
  Type Inference
&lt;/h3&gt;

&lt;p&gt;Type inference is a handy feature that almost gives the appearance of dynamic typing... sometimes. Let's use our first example again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;first_and_last&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;U&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="no"&gt;U&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="no"&gt;U&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because we explicitly declare that the parameter &lt;code&gt;arr&lt;/code&gt; is an Array we know that that parameter will have several helpful methods that allow us to act on the data stored in the Array. Array, however, is not the only class to contain many of those methods. There are other enumerable classes in Crystal that have &lt;code&gt;#size&lt;/code&gt;, &lt;code&gt;#first&lt;/code&gt;, and &lt;code&gt;#last&lt;/code&gt; methods such as &lt;code&gt;Set&lt;/code&gt; and &lt;code&gt;Deque&lt;/code&gt;. Currently though, you could not use any of those classes in our &lt;code&gt;first_and_last&lt;/code&gt; method. You could of course do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;first_and_last&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Indexable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;U&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="no"&gt;U&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="no"&gt;U&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now any class that includes the &lt;code&gt;Indexable&lt;/code&gt; module can be passed into &lt;code&gt;first_and_last&lt;/code&gt;, but there is an easier, albeit less explicit way to handle things.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;first_and_last&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;arr&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But wait, where did the types go? They're still there don't worry, but now instead of you having to explicitly declare the type of the parameter &lt;code&gt;arr&lt;/code&gt; the compiler will infer the type based on what operations you perform on it. There are several classes that have &lt;code&gt;#first&lt;/code&gt;, &lt;code&gt;#last&lt;/code&gt;, and &lt;code&gt;#size&lt;/code&gt; methods, and now all of them are valid inputs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Union Types
&lt;/h3&gt;

&lt;p&gt;One very powerful aspect of Crystal's type system is the ability to create type "unions". Here is an example of a union type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="no"&gt;Int32&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pipe &lt;code&gt;|&lt;/code&gt; operator creates a union between two types, allowing you to use either both &lt;code&gt;Int32&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt; types in that array. How awesome is that? Union types can also be generated dynamically by the compiler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Age"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variable &lt;code&gt;arr&lt;/code&gt; in this case would be assigned the type &lt;code&gt;Array(String, Int32)&lt;/code&gt; by the compiler. This also, of course, means that any operations performed on the data in the array have to check the type of the item before doing anything, unless they are doing something that is applicable to both types. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Age"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chars&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;chars&lt;/code&gt; is a method that exists on the &lt;code&gt;String&lt;/code&gt; class and returns an array of all the characters in the String. The method does not, however, exist on the &lt;code&gt;Int32&lt;/code&gt; class. Because of that this code will not compile. Instead you'd have to do something like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Age"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chars&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Things can definitely get messy when dealing with unions, so keep that in mind.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Crystal's type system is very powerful and I've really only scratched the surface. If you want to learn more about it I'd suggest looking at &lt;a href="https://crystal-lang.org/reference/syntax_and_semantics/types_and_methods.html" rel="noopener noreferrer"&gt;the Crystal reference&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please don’t forget to hit one of the the Ego Booster buttons (personally I like the unicorn), and if you feel so inclined share this to social media. If you share to twitter be sure to tag me at @_watzon.&lt;/p&gt;

&lt;p&gt;Some helpful links:&lt;br&gt;
&lt;a href="https://crystal-lang.org/" rel="noopener noreferrer"&gt;https://crystal-lang.org/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/kostya/benchmarks" rel="noopener noreferrer"&gt;https://github.com/kostya/benchmarks&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/kostya/crystal-benchmarks-game" rel="noopener noreferrer"&gt;https://github.com/kostya/crystal-benchmarks-game&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/crystal-lang/crystal" rel="noopener noreferrer"&gt;https://github.com/crystal-lang/crystal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Find me online:&lt;br&gt;
&lt;a href="https://medium.com/@watzon" rel="noopener noreferrer"&gt;https://medium.com/@watzon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/_watzon" rel="noopener noreferrer"&gt;https://twitter.com/_watzon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/watzon" rel="noopener noreferrer"&gt;https://github.com/watzon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://watzon.tech" rel="noopener noreferrer"&gt;https://watzon.tech&lt;/a&gt;&lt;/p&gt;

</description>
      <category>crystal</category>
      <category>tutorial</category>
      <category>series</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Doing Crystal #2: Getting started with Crystal</title>
      <dc:creator>Chris Watson</dc:creator>
      <pubDate>Wed, 22 May 2019 04:29:21 +0000</pubDate>
      <link>https://dev.to/watzon/doing-crystal-2-getting-started-with-crystal-13dk</link>
      <guid>https://dev.to/watzon/doing-crystal-2-getting-started-with-crystal-13dk</guid>
      <description>&lt;p&gt;Hello and welcome to another edition of Doing Crystal. In this article I’m going do a brief overview of the installation of Crystal, Crystal Shards, using the CLI, and setting up a new project.&lt;/p&gt;

&lt;p&gt;If you haven’t yet read the first part of this series you can check it out &lt;a href="https://dev.to/watzon/doing-crystal-1-a-ruby-comparison-4g9c"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Crystal is pretty easy to install, but sometimes there are hangups. As the language has matured (remember, it is only a 5 year old language) the installation process has gotten simpler and more OS’s are now supported than before. That being said, here are some things to keep in mind:&lt;/p&gt;

&lt;h3&gt;
  
  
  Windows Support
&lt;/h3&gt;

&lt;p&gt;This is probably the biggest hangup for a lot of people just getting started with Crystal. As of the writing of this article, Windows is not supported by Crystal. There are &lt;a href="https://github.com/crystal-lang/crystal/issues/26" rel="noopener noreferrer"&gt;ongoing efforts&lt;/a&gt; to port the compiler and make compiling on Windows possible, but for now you have 2 options if you want to get started with Crystal on Windows.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Install Linux. You can dual boot, use a VM, or just get rid of Windows all together, but Linux is definitely the best way to develop with Crystal.&lt;/li&gt;
&lt;li&gt; Use WSL. This is still using Linux technically, but a little easier. WSL (or the Windows Subsystem for Linux) is a native kernel compatibility layer that allows you to run real Linux inside of Windows. The one hangup here is editor support, which I tried to mitigate with my project &lt;a href="https://github.com/watzon/wsl-proxy" rel="noopener noreferrer"&gt;wsl-proxy&lt;/a&gt;. Support for WSL has also been added to the &lt;a href="https://marketplace.visualstudio.com/items?itemName=faustinoaq.crystal-lang" rel="noopener noreferrer"&gt;Crystal Language&lt;/a&gt; plugin for VS Code.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Compiling from Source
&lt;/h3&gt;

&lt;p&gt;Compiling from the source files can be quite difficult if you don’t know what you’re doing. There are several &lt;a href="https://github.com/crystal-lang/crystal/wiki/All-required-libraries" rel="noopener noreferrer"&gt;libraries&lt;/a&gt; that are required before you can build the compiler. On systems for which there are instructions, namely Ubuntu, Fedora, and OS X, it’s pretty easy to download and install the libraries you need, but for systems such as Arch or Alpine Linux finding the correct libraries can be a little more difficult.&lt;/p&gt;

&lt;p&gt;Luckily help is literally a &lt;a href="https://gitter.im/crystal-lang/crystal" rel="noopener noreferrer"&gt;click&lt;/a&gt; away.&lt;/p&gt;

&lt;p&gt;General installation instructions are located at &lt;a href="https://crystal-lang.org/reference/installation/" rel="noopener noreferrer"&gt;crystal-lang.org/reference/installation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shards
&lt;/h3&gt;

&lt;p&gt;Ruby has Bundler, NodeJS has NPM, Rust has Cargo, and Crystal has &lt;strong&gt;Shards&lt;/strong&gt;. Shards is a package manager and, like Crystal itself, is still in its infancy. That being said Shards is good at what it does: fetching and installing external Crystal libraries from a git repository.&lt;/p&gt;

&lt;p&gt;Shards should come pre-packaged with Crystal. To check if you have it installed, run &lt;code&gt;shards --help&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fy333zbu0ii83t0djs04m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fy333zbu0ii83t0djs04m.png" width="800" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have shards installed and it is correctly referenced on your PATH you should see this output. The available commands are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;build&lt;/strong&gt; — the build command checks your &lt;code&gt;shard.yml&lt;/code&gt; for binary definitions and builds them if any exist. You can use the &lt;code&gt;[targets]&lt;/code&gt; option to build specific targets.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;check&lt;/strong&gt;— checks that your dependencies are up to date.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;init&lt;/strong&gt; — generates a &lt;code&gt;shard.yml&lt;/code&gt; file in the current directory.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;install&lt;/strong&gt; — installs dependencies listed in your &lt;code&gt;shard.yml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;list&lt;/strong&gt; — lists installed shards.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;prune&lt;/strong&gt; — removes installed shards that are no longer needed.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;update&lt;/strong&gt; — updates shards.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;version&lt;/strong&gt; — gets the version of a project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unfortunately, installing binary shards (like you can with &lt;code&gt;gem install [gemname]&lt;/code&gt; in Ruby) is not yet supported, but hopefully someday it will be.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Crystal CLI
&lt;/h3&gt;

&lt;p&gt;The Crystal CLI is an interface to the compiler, the Crystal Playground, tools, documentation generation, test running, and more. First run &lt;code&gt;crystal --help&lt;/code&gt; to see if you have it installed correctly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fkx9z626a71wwiypc7ymy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fkx9z626a71wwiypc7ymy.png" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you see this then you’re good to go. Let’s review the CLI’s commands.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;init&lt;/strong&gt;— Generates a new Crystal project. You can use &lt;code&gt;crystal init lib [name]&lt;/code&gt; to generate a library project, or &lt;code&gt;crystal init app [name]&lt;/code&gt; to generate a binary project.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;build&lt;/strong&gt; — builds a file. In most cases you’ll run &lt;code&gt;crystal build ./src/project-name.cr&lt;/code&gt;, where &lt;code&gt;project-name.cr&lt;/code&gt; is the main file that was generated for you when you ran &lt;code&gt;crystal init&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;docs&lt;/strong&gt; — Crystal comes with a built in documentation generator. Personally I feel like there’s a lot missing where documentation generation is concerned, but you can pretty easily generate docs using your comments and type definitions just by running &lt;code&gt;crystal docs&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;env&lt;/strong&gt; — prints the environment information for Crystal. ENV vars include &lt;code&gt;CRYSTAL_CACHE_DIR&lt;/code&gt;, &lt;code&gt;CRYSTAL_PATH&lt;/code&gt;, &lt;code&gt;CRYSTAL_VERSION&lt;/code&gt;, and &lt;code&gt;CRYSTAL_LIBRARY_PATH.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;eval&lt;/strong&gt; — evaluates and runs Crystal code from the standard input.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;play&lt;/strong&gt; — starts a local Crystal Playground server. This is somewhat like the playground located at &lt;a href="https://play.crystal-lang.org/" rel="noopener noreferrer"&gt;https://play.crystal-lang.org/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;run&lt;/strong&gt; — builds and runs the supplied filename. Use like &lt;code&gt;crystal run [file]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;spec&lt;/strong&gt; — builds and runs specs located in the &lt;code&gt;/spec&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;tool&lt;/strong&gt; — runs one of the available Crystal tools. Available tools are &lt;code&gt;context&lt;/code&gt;, &lt;code&gt;expand&lt;/code&gt;, &lt;code&gt;format&lt;/code&gt;, &lt;code&gt;hierarchy&lt;/code&gt;, &lt;code&gt;implementations&lt;/code&gt;, and &lt;code&gt;types&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we’ve gone over the CLI a little, let’s set up a new project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Project
&lt;/h3&gt;

&lt;p&gt;Because it’s been deemed mandatory by the coding gods, let’s create a hello world application.&lt;/p&gt;

&lt;p&gt;First let’s open up our terminal of choice and &lt;code&gt;cd&lt;/code&gt; into a projects directory. In my case I’ll run &lt;code&gt;cd ~/Projects&lt;/code&gt;. Using the CLI, we’re going to generate a new project scaffold, and then &lt;code&gt;cd&lt;/code&gt; into our newly created project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fbjtpbuoa52mb6u9wd7rd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fbjtpbuoa52mb6u9wd7rd.png" width="800" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you run &lt;code&gt;ls&lt;/code&gt; you should see the following output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fputxi9g96r8ws21bj3ul.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fputxi9g96r8ws21bj3ul.png" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The important files here are &lt;code&gt;shard.yml&lt;/code&gt; and &lt;code&gt;src/hello_world.cr&lt;/code&gt;. First let’s take a look at &lt;code&gt;shard.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Flmm614wer9cqpatl5lb5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Flmm614wer9cqpatl5lb5.png" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I won’t go over this in detail, as most items should be self explanitory. If you need help with the available options in &lt;code&gt;shard.yml&lt;/code&gt; you can look at the spec &lt;a href="https://github.com/crystal-lang/shards/blob/master/SPEC.md" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s open our main file located at &lt;code&gt;src/hello_world.cr&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F8q7q1rhryw555wm48x89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F8q7q1rhryw555wm48x89.png" width="800" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the boilerplate content generated for all new Crystal projects. As you can see our project name of &lt;code&gt;hello_world&lt;/code&gt; has been PascalCased for the name of the base module. As a convention Crystal uses snake_case for project names, method names, variable names, etc. and PascalCase for constants such as module names and class names.&lt;/p&gt;

&lt;p&gt;Now, as convention dictates our hello world application must print something like “Hello, World!” to the console, so let’s make it happen.&lt;/p&gt;

&lt;p&gt;For the sake of this example we’ll be a little more verbose than we have to.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fmfmo2ko5a0qi1ji3bd35.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fmfmo2ko5a0qi1ji3bd35.png" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First we create a new class method in the &lt;code&gt;HelloWorld&lt;/code&gt; module called &lt;code&gt;say_hello&lt;/code&gt;. You can differentiate class and instance methods by looking for the &lt;code&gt;self.&lt;/code&gt; syntax. &lt;code&gt;def self.say_hello&lt;/code&gt; makes a class method, where &lt;code&gt;def say_hello&lt;/code&gt; makes an instance method.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;say_hello&lt;/code&gt; method takes one argument “name” which is assigned a default value of “World”. If we were to run &lt;code&gt;say_hello&lt;/code&gt; without any arguments the default value of “World” would be used.&lt;/p&gt;

&lt;p&gt;Next we go outside of the &lt;code&gt;HelloWorld&lt;/code&gt; module to run our new method. As &lt;code&gt;say_hello&lt;/code&gt; is an instance method we can call it with &lt;code&gt;HelloWorld.say_hello&lt;/code&gt;. Class methods can not be used directly on modules as modules cannot be instantiated.&lt;/p&gt;

&lt;p&gt;We finish things off by calling &lt;code&gt;HelloWorld.say_hello("Manas")&lt;/code&gt; to give a shoutout to the people at &lt;a href="https://manas.tech" rel="noopener noreferrer"&gt;Manas Tech&lt;/a&gt; who created Crystal.&lt;/p&gt;

&lt;p&gt;Let’s run our program and see the output.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fb6nn0w5kmyjvft05krex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fb6nn0w5kmyjvft05krex.png" width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The program will take a few seconds to run as it has to compile first, but you should be greeted with a “Hello, Manas!”. Congratulations! You have written your first Crystal program. Replace &lt;code&gt;run&lt;/code&gt; with &lt;code&gt;build&lt;/code&gt; to build a binary to your current directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Crystal is an extremely powerful language and we’ve only scratched the surface so far. Next time we’ll discuss one of the many things that makes Crystal so powerful, it’s type system.&lt;/p&gt;

&lt;p&gt;Please don’t forget to hit the Ego Booster button that looks like someone clapping, and if you feel so inclined share this to social media. If you share to twitter be sure to tag me at @_watzon.&lt;/p&gt;

&lt;p&gt;Some helpful links:&lt;br&gt;&lt;br&gt;
&lt;a href="https://crystal-lang.org/" rel="noopener noreferrer"&gt;https://crystal-lang.org/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/kostya/benchmarks" rel="noopener noreferrer"&gt;https://github.com/kostya/benchmarks&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/kostya/crystal-benchmarks-game" rel="noopener noreferrer"&gt;https://github.com/kostya/crystal-benchmarks-game&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/crystal-lang/crystal" rel="noopener noreferrer"&gt;https://github.com/crystal-lang/crystal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Find me online:&lt;br&gt;&lt;br&gt;
&lt;a href="https://medium.com/@watzon" rel="noopener noreferrer"&gt;https://medium.com/@watzon&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://twitter.com/chrystal_coder" rel="noopener noreferrer"&gt;https://twitter.com/_watzon&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/watzon" rel="noopener noreferrer"&gt;https://github.com/watzon&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://watzon.me" rel="noopener noreferrer"&gt;https://watzon.me&lt;/a&gt;&lt;/p&gt;

</description>
      <category>crystal</category>
      <category>tutorial</category>
      <category>series</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Doing Crystal #1: A Ruby Comparison</title>
      <dc:creator>Chris Watson</dc:creator>
      <pubDate>Wed, 22 May 2019 04:17:26 +0000</pubDate>
      <link>https://dev.to/watzon/doing-crystal-1-a-ruby-comparison-4g9c</link>
      <guid>https://dev.to/watzon/doing-crystal-1-a-ruby-comparison-4g9c</guid>
      <description>&lt;p&gt;Hello world, and welcome to this series of blog posts which I'm titling "Doing Crystal". Yes it is a meth joke, and yes you'd better have a sense of humor if you're going to be a part of this series. You've been warned.&lt;/p&gt;

&lt;p&gt;In this series of blog posts I will walk you through the beautiful world of Crystal, or as I like to call it, Ruby's over achieving younger sibling. If you haven't ever had a run in with Crystal then you're in for a treat, so sit down, buckle up, and enjoy the ride, Buttercup.&lt;/p&gt;

&lt;p&gt;So what is Crystal? Crystal is a statically typed, compiled, garbage collected language with a syntax that is hauntingly familiar to anyone that has ever touched Ruby. It uses LLVM to compile your beautiful Ruby-esque code down to machine code, and in benchmarks is consistently much closer in speed to C++ than Ruby. Crystal development started in 2014, so it is about 20 years younger than Ruby and still in pre-release status at the writing of this article, but that doesn't mean you shouldn't pay attention to it. On the contrary I think that Crystal has amazing potential.&lt;/p&gt;

&lt;p&gt;But if it's so much faster than Ruby, is a comparison really fair? Sure it is! I want to show you how you can take code that looks like Ruby and make it type-safe and make it 44x faster (based on the &lt;a href="https://github.com/kostya/benchmarks" rel="noopener noreferrer"&gt;&lt;/a&gt;). The Ruby ecosystem is still much more developed with 152,000 available Ruby gems as opposed to just over 4,000 Crystal shards, but such is to be expected from languages that are 20 years apart.&lt;/p&gt;

&lt;p&gt;So, without further ado, let's get down to business and compare these two amazing languages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crystal vs Ruby
&lt;/h2&gt;

&lt;p&gt;First let's start with what a lot of people, me included, consider the most important piece of any programming language. The syntax. Sure speed is nice and everything, but if your fast code ends up looking like a steaming pile of cow dung (I'm looking at you C++) then the maintainability factor for your project goes way down.&lt;/p&gt;

&lt;p&gt;Let's start with an example from the &lt;a href="https://crystal-lang.org" rel="noopener noreferrer"&gt;Crystal lang website&lt;/a&gt;, a super simple HTTP server.&lt;/p&gt;

&lt;p&gt;First the Ruby sample:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F4k069b9d4pm4d4x6bumj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F4k069b9d4pm4d4x6bumj.png" alt="Ruby HTTP Server" width="800" height="687"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creating a HTTP server in Ruby is interesting. It's not at all intuitive and makes life kind of difficult. Yes, in Ruby you can also just use Sinatra or any other gem to create a server, but this example is about doing it in pure Ruby.&lt;/p&gt;

&lt;p&gt;Now for Crystal:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fd65hay4th4hvwl1wzrz7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fd65hay4th4hvwl1wzrz7.png" alt="Crystal HTTP Server" width="800" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait, that's it? How simple is that. You import from http/server instead of socket, you use a block to handle the looping and the block hands you a context. There's no blocking loop, no need to manually define headers, and no real complexity.&lt;/p&gt;

&lt;p&gt;Ok so some API's are simplified, but what about this static typing? Let's take look at another couple examples.&lt;/p&gt;

&lt;p&gt;First the Ruby code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F1l0eob0qlgza4ic4e2k3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F1l0eob0qlgza4ic4e2k3.png" alt="Runtime Error" width="800" height="681"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now sure, any good Ruby dev would do a type check in the sum method to make sure that only integers are accepted, but that's extra work and even the best devs can miss things.&lt;/p&gt;

&lt;p&gt;How about some Crystal:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fm9xbzyxffjf423ai6utu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fm9xbzyxffjf423ai6utu.png" alt="Compile Error" width="800" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This still throws an error, but the difference is when. A compile error is much better than a runtime error, because runtime errors are usually caught by the end-user. The error thrown is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;no overload matches &lt;span class="s1"&gt;'Int32#+'&lt;/span&gt; with &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;Int32 | String&lt;span class="o"&gt;)&lt;/span&gt;
Overloads are:
 - Int32#+&lt;span class="o"&gt;(&lt;/span&gt;other : Int8&lt;span class="o"&gt;)&lt;/span&gt;
 - Int32#+&lt;span class="o"&gt;(&lt;/span&gt;other : Int16&lt;span class="o"&gt;)&lt;/span&gt;
 - Int32#+&lt;span class="o"&gt;(&lt;/span&gt;other : Int32&lt;span class="o"&gt;)&lt;/span&gt;
 - Int32#+&lt;span class="o"&gt;(&lt;/span&gt;other : Int64&lt;span class="o"&gt;)&lt;/span&gt;
 - Int32#+&lt;span class="o"&gt;(&lt;/span&gt;other : Int128&lt;span class="o"&gt;)&lt;/span&gt;
 - Int32#+&lt;span class="o"&gt;(&lt;/span&gt;other : UInt8&lt;span class="o"&gt;)&lt;/span&gt;
 - Int32#+&lt;span class="o"&gt;(&lt;/span&gt;other : UInt16&lt;span class="o"&gt;)&lt;/span&gt;
 - Int32#+&lt;span class="o"&gt;(&lt;/span&gt;other : UInt32&lt;span class="o"&gt;)&lt;/span&gt;
 - Int32#+&lt;span class="o"&gt;(&lt;/span&gt;other : UInt64&lt;span class="o"&gt;)&lt;/span&gt;
 - Int32#+&lt;span class="o"&gt;(&lt;/span&gt;other : UInt128&lt;span class="o"&gt;)&lt;/span&gt;
 - Int32#+&lt;span class="o"&gt;(&lt;/span&gt;other : Float32&lt;span class="o"&gt;)&lt;/span&gt;
 - Int32#+&lt;span class="o"&gt;(&lt;/span&gt;other : Float64&lt;span class="o"&gt;)&lt;/span&gt;
 - Number#+&lt;span class="o"&gt;()&lt;/span&gt;
Couldn&lt;span class="s1"&gt;'t find overloads for these types:
 - Int32#+(String)
arr.reduce(0) { |acc,i| acc + i }
                              ^
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, not only does it throw an error, but it tells you exactly what the problem is. In this case the problem is that you can't add an integer to a string, even a string that has an integer in it.&lt;/p&gt;

&lt;p&gt;And now you see some of Crystal's extremely powerful type system. All things in Crystal are typed, from Arrays to Hashes to variables. Because of this type safety the compiler absolutely will not allow you to make mistakes where types are concerned, and that means that runtime errors are basically nonexistent.&lt;/p&gt;

&lt;p&gt;Now I'm not saying that you can't make mistakes in Crystal. You can still do stupid things like creating an infinite loop, and stack overflows aren't nonexistent. Crystal is still pre-release software after all. But the amount of safety you get from Crystal as opposed to Ruby is astounding.&lt;/p&gt;

&lt;p&gt;That's it for this edition of Doing Crystal. Please remember to like, share, and subscribe, because yes, this is secretly a YouTube video and your life is a lie.&lt;/p&gt;

&lt;p&gt;View the next post in this series &lt;a href="https://dev.to/watzon/doing-crystal-2-getting-started-with-crystal-13dk"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some helpful links:&lt;br&gt;
&lt;a href="https://crystal-lang.org/" rel="noopener noreferrer"&gt;https://crystal-lang.org/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/kostya/benchmarks" rel="noopener noreferrer"&gt;https://github.com/kostya/benchmarks&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/kostya/crystal-benchmarks-game" rel="noopener noreferrer"&gt;https://github.com/kostya/crystal-benchmarks-game&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/crystal-lang/crystal" rel="noopener noreferrer"&gt;https://github.com/crystal-lang/crystal&lt;/a&gt;&lt;br&gt;
Find me online:&lt;br&gt;
&lt;a href="https://medium.com/@watzon" rel="noopener noreferrer"&gt;https://medium.com/@watzon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/chrystal_coder" rel="noopener noreferrer"&gt;https://twitter.com/chrystal_coder&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/watzon" rel="noopener noreferrer"&gt;https://github.com/watzon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://watzon.me" rel="noopener noreferrer"&gt;https://watzon.me&lt;/a&gt;&lt;/p&gt;

</description>
      <category>crystal</category>
      <category>tutorial</category>
      <category>ruby</category>
      <category>series</category>
    </item>
  </channel>
</rss>
