<?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: Jump24</title>
    <description>The latest articles on DEV Community by Jump24 (@jump24).</description>
    <link>https://dev.to/jump24</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%2Forganization%2Fprofile_image%2F2840%2F9a91799d-6761-4935-b551-41dc19bcca21.png</url>
      <title>DEV Community: Jump24</title>
      <link>https://dev.to/jump24</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jump24"/>
    <language>en</language>
    <item>
      <title>Laravel Blade Components</title>
      <dc:creator>Daniel Newns</dc:creator>
      <pubDate>Sun, 28 May 2023 09:46:28 +0000</pubDate>
      <link>https://dev.to/jump24/laravel-blade-components-3hbh</link>
      <guid>https://dev.to/jump24/laravel-blade-components-3hbh</guid>
      <description>&lt;p&gt;&lt;a href="https://laravel.com/docs/10.x/blade"&gt;Laravel Blade&lt;/a&gt; is a powerful templating engine that allows developers to create dynamic and reusable views in a Laravel application. One of the key features of Blade is the ability to create reusable and composable components, which can help speed up front-end development. By enabling the creation of reusable components that provide consistent styles and behaviour, developers can avoid the need to construct elements from scratch. Instead, they can simply make use of the components that already exist.&lt;/p&gt;

&lt;p&gt;In this article we will create a basic form that shows you some benefits and techniques of blade components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating your first component
&lt;/h2&gt;

&lt;p&gt;There are two types of components: class-based and anonymous. Class-based components have a class and a view template, while anonymous components only have a view template. In most cases, anonymous components are sufficient, and I tend to use class-based components only when I need to use dependency injection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:component layouts.app --view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the above command will create our first component, a layout file named resources/views/components/layouts/app.blade.php. This file will be the layout of the app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/layouts/app.blade.php --&amp;gt;

&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="{{ str_replace('_', '-', app()-&amp;gt;getLocale()) }}"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="utf-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1"&amp;gt;

    &amp;lt;title&amp;gt;Laravel Blade Components&amp;lt;/title&amp;gt;

    &amp;lt;script src="https://cdn.tailwindcss.com"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    {{ $slot }}
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&amp;lt;!-- /resources/views/example.blade.php --&amp;gt;

&amp;lt;x-layouts.app&amp;gt;
    Hello World!
&amp;lt;/x-layouts.app&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;{{ $slot }}&lt;/code&gt; will render whatever we pass to it. For example, passing Hello World! will render it on the page. Slots are what make blade components composable. We can pass components to other components and even use &lt;a href="https://laravel.com/docs/10.x/blade#slots"&gt;named slots&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a form
&lt;/h2&gt;

&lt;p&gt;Run the following to create our anonymous index component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:component form.index --view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normally to group components together you would have to have a form component then have the rest of the forms components inside a folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/resources/views/components/form.blade.php
/resources/views/components/form/group.blade.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anonymous index components allow you to group your components together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/resources/views/components/form/index.blade.php
/resources/views/components/form/group.blade.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage would look like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;x-layouts.app&amp;gt;
    &amp;lt;x-form&amp;gt;
        &amp;lt;x-form.group&amp;gt;
            Hello!
        &amp;lt;/xform.group&amp;gt;
    &amp;lt;/x-form&amp;gt;
&amp;lt;/x-layouts.app&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/form/index.blade.php --&amp;gt;

@props([
    'method' =&amp;gt; 'POST',
    'action',
    'hasFiles' =&amp;gt; false,
])

&amp;lt;form
    method="{{ $method !== 'GET' ? 'POST' : 'GET' }}"
    action="{{ $action }}"
    {!! $hasFiles ? 'enctype="multipart/form-data"' : '' !!}
    {{ $attributes-&amp;gt;except(['method', 'action']) }}
&amp;gt;
    @csrf
    @method($method)

    {{ $slot }}
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We define the props we want the component to accept. We are able to set some sensible defaults. Most forms have the method as &lt;code&gt;POST&lt;/code&gt; so we set that as default. When forms are sending files we need to have the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/enctype"&gt;enctype&lt;/a&gt; attribute. Instead of typing it out every time we make the component add this attribute on when we need it.&lt;/p&gt;

&lt;p&gt;We want to make sure the developer passes an action when using this component so we set action as a prop but set no default value. When no action is passed Laravel will throw an error if we do not do an &lt;code&gt;isset()&lt;/code&gt; check.&lt;/p&gt;

&lt;p&gt;Echoing out &lt;code&gt;$attributes&lt;/code&gt; allows us to pass any additional attributes we need without having to define them in the props.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;x-form action="/users"&amp;gt;&amp;lt;/x-form&amp;gt;
&amp;lt;x-form :action="route('users.store')"&amp;gt;&amp;lt;/x-form&amp;gt;

&amp;lt;x-form method="GET"&amp;gt;&amp;lt;/x-form&amp;gt;

&amp;lt;x-form has-files&amp;gt;&amp;lt;/x-form&amp;gt;

&amp;lt;x-form class="border border-red-200"&amp;gt;&amp;lt;/x-form&amp;gt;

&amp;lt;x-form 
    :action="route('photos.store')"
    has-files
    class="p-5"
&amp;gt;
    //
&amp;lt;/x-form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example we use the &lt;code&gt;:action&lt;/code&gt; attribute. We use the : prefix to denote that it is a PHP expression or variable. We could also do &lt;code&gt;:action="$someRoute"&lt;/code&gt;. If it is a hardcoded or primitive value we  do &lt;code&gt;action="/"&lt;/code&gt; like normal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create text input
&lt;/h2&gt;

&lt;p&gt;When working with inputs I like to create a group component that can take the input component. This group will display the label, help text and any errors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:component input.group --view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are setting a default class using &lt;code&gt;$attributes-&amp;gt;class(['block'])&lt;/code&gt;. If we were to pass the class attribute any classes would be merged with block.&lt;/p&gt;

&lt;p&gt;We use &lt;code&gt;@class()&lt;/code&gt; to conditionally set classes. &lt;code&gt;text-gray-700 inline-block mb-1&lt;/code&gt; is always displayed, &lt;code&gt;text-red-500&lt;/code&gt; is only merged into the default when &lt;code&gt;$error&lt;/code&gt; is present.&lt;/p&gt;

&lt;p&gt;If we don’t pass a prop in then it is not defined, that is why we use &lt;code&gt;@isset($help)&lt;/code&gt; and &lt;code&gt;@isset($error)&lt;/code&gt; to check if they are set. We could also set the props to have &lt;code&gt;null&lt;/code&gt; as their default value and check for that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/input/group.blade.php --&amp;gt;

@props([
    'label',
    'for',
    'help',
    'error',
])

&amp;lt;label
    {{ $attributes }}
    {{ $attributes-&amp;gt;class(['block']) }}
    for="{{ $for }}"
&amp;gt;
    &amp;lt;span
        @class([
            'text-gray-700 inline-block mb-1',
            'text-red-500' =&amp;gt; isset($error)
        ])
    &amp;gt;{{ $label ?? '' }}&amp;lt;/span&amp;gt;
    &amp;lt;div class="mt-1"&amp;gt;
        {{ $slot }}
    &amp;lt;/div&amp;gt;
    @isset($help)
        &amp;lt;p class="mt-2 text-sm text-gray-500" id="{{ $for }}"&amp;gt;{{ $help }}&amp;lt;/p&amp;gt;
    @endif
    @isset($error)
        &amp;lt;div class="mt-1 text-red-500 text-sm"&amp;gt;{{ $error }}&amp;lt;/div&amp;gt;
    @endif
&amp;lt;/label&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we will create a text input&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:component input.text --view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This component uses &lt;code&gt;@aware()&lt;/code&gt;. This allows the child component to &lt;a href="https://laravel.com/docs/10.x/blade#accessing-parent-data"&gt;access data in the parent component&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/input/text.blade.php --&amp;gt;

@aware([
    'error',
])

@props([
    'value',
    'name',
    'for',
])

&amp;lt;input
    {{ $attributes-&amp;gt;class([
        'shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md',
        'border-red-500' =&amp;gt; $error
    ]) }}
    @isset($name) name="{{ $name }}" @endif
    type="text"
    @isset($value) value="{{ $value }}" @endif
    {{ $attributes }}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create button
&lt;/h2&gt;

&lt;p&gt;Finally we can create a button to submit our form. We will use an anonymous index component again. This is because I don’t want to access the button directly, instead I want to use this component inside &lt;code&gt;primary&lt;/code&gt;, &lt;code&gt;secondary&lt;/code&gt; buttons.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:component button.index --view&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/button/index.blade.php --&amp;gt;

@aware([
    'type',
])

&amp;lt;button
    type="{{ $type }}"
    {{ $attributes-&amp;gt;class([
        'inline-flex items-center border font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2',
    ]) }}
&amp;gt;
    {{ $slot }}
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we create our &lt;code&gt;primary&lt;/code&gt; button. You can see that we are using the &lt;code&gt;x-button&lt;/code&gt; inside our &lt;code&gt;primary&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:component button.primary --view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/button/primary.blade.php --&amp;gt;

@props([
    'type' =&amp;gt; 'button',
])

&amp;lt;x-button
    {{ $attributes-&amp;gt;merge(['class' =&amp;gt; 'border-transparent shadow-sm text-white bg-indigo-600 hover:bg-indigo-700']) }}&amp;gt;
    {{ $slot }}
&amp;lt;/x-button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Separating the &lt;code&gt;x-button&lt;/code&gt; component means that we can re-use it in multiple places, even using it on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it all together
&lt;/h2&gt;

&lt;p&gt;Now we have created our components we can start to use them together. We first use our form component to wrap all our inputs, in this instance we only need to pass the route as the action. Next we have a couple of input groups, these take a label, for and an error. The error comes from the &lt;a href="https://laravel.com/docs/10.x/validation#working-with-error-messages"&gt;validation error bag&lt;/a&gt; that is available to all views. Passed to the input groups slot is the input. In this example we are using automatic attributes to pass along the old value to the value attribute. Lastly we use our button to submit the form.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;x-form :action="route('users.store')"&amp;gt;
    &amp;lt;x-input.group label="Email" for="email" :error="$errors-&amp;gt;first('email')"&amp;gt;
        &amp;lt;x-input.email name="email" :value="old('email')" /&amp;gt;
    &amp;lt;/x-input.group&amp;gt;
    &amp;lt;x-input.group label="Password" for="password" :error="$errors-&amp;gt;first('password')"&amp;gt;
        &amp;lt;x-input.password name="password" :value="old('password')" /&amp;gt;
    &amp;lt;/x-input.group&amp;gt;
    &amp;lt;x-button.primary&amp;gt;
      Submit
    &amp;lt;/x-button.primary&amp;gt;
&amp;lt;/x-form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can mix blade components with plain HTML as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;x-form action="/photo" has-files&amp;gt;
    &amp;lt;div class="p-3 border border-slate-200"&amp;gt;
      &amp;lt;x-input.group label="Password" for="photo" :error="$errors-&amp;gt;first('photo')"&amp;gt;
          &amp;lt;input type="file" name="photo" /&amp;gt;
      &amp;lt;/x-input.group&amp;gt;
      &amp;lt;button&amp;gt;Submit&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/x-form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bonus Tips
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://laravel.com/docs/10.x/blade#short-attribute-syntax"&gt;Short Attribute Syntax&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{-- Short attribute syntax... --}}
&amp;lt;x-input.text $name /&amp;gt;

{{-- Is equivalent to... --}}
&amp;lt;x-input.text name="{{ $name }}" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://laravel.com/docs/10.x/blade#slots"&gt;Named Slots&lt;/a&gt; - You can have multiple slots in a component by giving them names.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;x-modal&amp;gt;
    &amp;lt;x-slot:header&amp;gt;
      Hello World!
    &amp;lt;/x-slot&amp;gt;

    Some lovely content

    &amp;lt;x-slot:footer&amp;gt;
      Goodbye World!
    &amp;lt;/x-slot&amp;gt;
&amp;lt;/x-modal&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’d achieve this by doing the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/modal/index.blade.php --&amp;gt;

&amp;lt;div&amp;gt;
  &amp;lt;header&amp;gt;
    {{ $header }}
  &amp;lt;/header&amp;gt;
  &amp;lt;main&amp;gt;
    {{ $slot }}
  &amp;lt;/main&amp;gt;
  &amp;lt;footer&amp;gt;
    {{ $footer }}
  &amp;lt;/footer&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>laravel</category>
      <category>blade</category>
      <category>php</category>
    </item>
    <item>
      <title>Brum Tech Tapas: A Retrospective</title>
      <dc:creator>James Seconde</dc:creator>
      <pubDate>Thu, 27 May 2021 07:54:29 +0000</pubDate>
      <link>https://dev.to/jump24/brum-tech-tapas-a-retrospective-5g7b</link>
      <guid>https://dev.to/jump24/brum-tech-tapas-a-retrospective-5g7b</guid>
      <description>&lt;p&gt;Launching a new event for the city, towards what will be hopefully the end of the COVID crisis was always going to be a daunting task. Wary of the dreaded ‘Zoom fatigue’, numbers for online events have slowly been dropping over the past year or so. But, with a huge push from the team at Jump24, we did it - and our building excitement before launching was satisfied with something we really enjoyed and are proud of.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jump24.co.uk/journal/running-and-speaking-at-online-events-what-weve-learned/"&gt;We previously wrote a blog post&lt;/a&gt; on launching online events, and what we’d learned in the process. Building on that, it makes sense to write up what we learned during the launch of Brum Tech Tapas (and we learned a lot!). There is, however, a lot to take in. So, in the spirit of “tapas” being “bitesize chunks”, we thought we split our thoughts into three natural categories. First up, it’s:&lt;/p&gt;

&lt;h1&gt;
  
  
  BRUM
&lt;/h1&gt;

&lt;p&gt;This is a local event, created for the community here, with a line up of speakers doing work in the region. &lt;/p&gt;

&lt;h2&gt;
  
  
  Selecting Speakers
&lt;/h2&gt;

&lt;p&gt;The speakers really provide the core content of the whole event, and drive the direction of the event – so our speaker selection was very carefully planned. As a team, we created a shortlist (which became a very long list in a matter of hours!) of who we wanted to invite. Our lists contained people expert in the areas outlined in the introduction – so for a quick reminder:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4vPFhojC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/04/image-4-1024x531.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4vPFhojC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/04/image-4-1024x531.png" alt="Image of me speaking at Brum Tech Tapas" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We approached people in a number of ways – Twitter Direct Messages, LinkedIn Direct Messages, email addresses we found on websites. Communication is hard when so many channels are available, but really Twitter was probably the most effective. There is reasoning behind this – one of the targets for Brum Tech Tapas content from speakers was to get the “inside story” or honest account of what they work on rather than the sales pitch. For some speakers, this doesn’t apply, but for those operating in corporate spaces it certainly rings true.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diversity / Inclusion
&lt;/h2&gt;

&lt;p&gt;In our world of tech, the demographics of those speaking at meetups and conferences are still massively skewed towards middle-aged white men – commonly known as ‘manels’. Well, you won’t see one of those at Brum Tech Tapas. This is an event for the West Midlands, so it is essential to the mission that speaker selection represents the region correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code of Conduct
&lt;/h2&gt;

&lt;p&gt;We believe that a Code of Conduct (CoC) is absolutely vital. We adapted the one used by PyCon US (&lt;a href="https://us.pycon.org/2020/about/code-of-conduct/"&gt;https://us.pycon.org/2020/about/code-of-conduct/&lt;/a&gt;) for Brum Tech Tapas that you can find here (&lt;a href="https://brumtechtapas.co.uk/code-of-conduct/"&gt;https://brumtechtapas.co.uk/code-of-conduct/&lt;/a&gt;). Launching the event online means applying the CoC somewhat differently, so Chris, Dan and Ollie moderated the YouTube chat room. Thankfully CoC violations are rare (especially for a new event) but given our ambition to grow, we made sure we were doing things the right way. It didn’t go unnoticed, given that several of our attendees gave positive feedback that we had a CoC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Promotion
&lt;/h2&gt;

&lt;p&gt;The principal driver behind how we conceived and executed Brum Tech Tapas comes from the world of Developer Relations. You can read a decent outline on what this looks like from Matthew Revell’s Hoopy consultancy &lt;a href="https://developerrelations.com/strategy-and-metrics/the-four-pillars-of-developer-relations"&gt;here&lt;/a&gt;. Like with any good event, it’s about putting the community first.&lt;/p&gt;

&lt;p&gt;Interesting things happened as a result, some of which we couldn’t have predicted but were delighted to see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asset Reuse
&lt;/h2&gt;

&lt;p&gt;We contacted several tech organisations in the city to see if they were interested in promoting the event. It may sound like I’m easy to please, but given how hard it is to collaborate and promote ourselves within the region, it was a genuine delight to see our assets being reused without any ask in return.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZT2fDtUf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/04/image-5-1024x536.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZT2fDtUf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/04/image-5-1024x536.png" alt="Image created by Birmingham Tech to promote Brum Tech Tapas" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iDxmt1YB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/04/image-6-1024x573.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iDxmt1YB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/04/image-6-1024x573.png" alt="Image created by Innovation Alliance to promote Brum Tech Tapas" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The top image comes courtesy of &lt;a href="https://birmingham.tech/"&gt;Birmingham Tech&lt;/a&gt;, who promoted our event through their platform and created this promo image themselves – and it looks great! The second image appeared to our surprise from &lt;a href="https://innovationwm.co.uk"&gt;Innovation Alliance&lt;/a&gt; – while we didn’t have any direct contact with them, I suspect this was the work of &lt;a href="https://twitter.com/tn_midlands"&gt;Naomi Nash&lt;/a&gt; at &lt;a href="https://technation.io/"&gt;Tech Nation&lt;/a&gt; who helped us promote through their network. Both Naomi and &lt;a href="https://twitter.com/yiannismaos"&gt;Yiannis&lt;/a&gt; had generated interest through their spheres of influence, which put my mind at ease that people were indeed interested in what we were putting together.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Wider Audience
&lt;/h2&gt;

&lt;p&gt;Now, this was harder. We could do promotion through our tech network but our speaker pool lay outside of our comfort zone. Our starting point was to get word-of-mouth out there from people who we have approached about speaking or promoting. You can’t suddenly declare yourself as a connected expert in the art world of Birmingham, for instance, so instead we had a lot of conversations with people who ARE expert in those spaces. We pitched Brum Tech Tapas as a concept to them, and if they liked what they see – they could speak or recommend speakers to us. Because, after all, the event is for the community.&lt;/p&gt;

&lt;p&gt;Rather than plan, plan and plan with massive ambitions for Brum Tech Tapas, we just wanted to launch the event and get the momentum going for more events. As such, we didn’t set massive targets, because really just launching the event and getting attendees could be seen as a success. We also made it free, to encourage participation and send a message that this is a not-for-profit event.   So, we set relatively low targets – 50 tickets ‘sold’ through EventBrite, with perhaps a 45-50% turnout from that. We were absolutely delighted when around 60 people watched the live event during most of its 2 ½ hour duration . We most definitely counted that as a win.&lt;/p&gt;

&lt;p&gt;On the subject of tickets – when sales started coming in, we saw many familiar faces of colleagues, friends and peers within tech. However, shortly after launch we were selling tickets to people totally unfamiliar to us, mostly in waves after using social media to promote other organisations and interesting people, which brings us neatly onto:&lt;/p&gt;

&lt;h2&gt;
  
  
  Promoting the Region
&lt;/h2&gt;

&lt;p&gt;One of the approaches we wanted to take was to give shout outs to all the amazing people and organisations that we want to connect with, potentially as speakers or who would know people in their own industries that could speak (or attend!). In doing so, we &lt;a href="https://www.youtube.com/watch?v=Porng9S0nRk"&gt;discovered so much more about these areas of the city’s creative ecosystem&lt;/a&gt;. Here are a couple of examples:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Fbvx5REV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/04/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Fbvx5REV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/04/image-2.png" alt="Image of tweets about Civic Square scheme" width="582" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hk54pdol--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/04/image-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hk54pdol--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/04/image-3.png" alt="Image of Digbeth" width="581" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The conclusion here is that we achieved what we set out to do, and that promoting the people and organisations that we see doing great stuff establishes the connections we want to make for future events. Put your trust in the community before your own requirements, and people will take you seriously.&lt;/p&gt;

&lt;p&gt;Next up, we’ll cover the “tech” part of Tech Tapas. After all, we’re a tech company streaming an event online-only for now, so there was bound to be some interesting snags along the way, right?&lt;/p&gt;

</description>
      <category>community</category>
      <category>devrel</category>
    </item>
    <item>
      <title>Remote Code Pairing with PHPStorm</title>
      <dc:creator>James Seconde</dc:creator>
      <pubDate>Fri, 07 May 2021 09:25:27 +0000</pubDate>
      <link>https://dev.to/jump24/remote-code-pairing-with-phpstorm-gbe</link>
      <guid>https://dev.to/jump24/remote-code-pairing-with-phpstorm-gbe</guid>
      <description>&lt;p&gt;Among the many challenges developers face when working 100% remote are those times when you face a problem that results in you staring at your IDE blankly for minutes on end.&lt;/p&gt;

&lt;p&gt;The ability to swivel your chair around and quickly throw out “have you got 2 minutes to rubber duck this bit of code please?” has become a distant memory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7LO_P1xl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/02/ducks-1024x683.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7LO_P1xl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/02/ducks-1024x683.png" alt="Loads of rubber ducks in a factory" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pair programming is a practice that I have encountered far less than I feel is acceptable within agency software development. As always, everything evolves around time; from what I have experienced across this sector, if it’s not coding that feature and getting it out the door as quickly as possible, it’s not worth the company’s time.&lt;/p&gt;

&lt;p&gt;Of course, at Jump24 we don’t operate like that, because investing time in &lt;a href="https://jump24.co.uk/journal/tools-of-our-trade/"&gt;our tooling&lt;/a&gt; is part of what we do. We can’t all be &lt;a href="https://twitter.com/skirani/status/1149302828420067328"&gt;10x Engineers&lt;/a&gt; and so, with the company completely remote, how do we solve the rubber duck problem?&lt;/p&gt;

&lt;p&gt;Remote pair programming tools have been around for some time – Saros, which is available for IntelliJ and Eclipse, has &lt;a href="https://github.com/saros-project/saros/releases/tag/v0.8"&gt;been in development since 2006&lt;/a&gt; for example. One of the other IDEs we use at Jump24 is VSCode (or &lt;a href="https://vscodium.com/"&gt;VSCodium&lt;/a&gt;, which is VSCode with Microsoft’s telemetrics reporting taken out) has several extensions available that also do remote sessions – CodeTogether is a solid choice in my experience.&lt;/p&gt;

&lt;p&gt;Like many organisations, 2020’s COVID crisis has propelled some of these tools to the forefront of developers’ consciousness – and it seems Jetbrains responded by accelerating development on it’s remote pairing plugin. While it’s already been mentioned that VSCode has remote pairing extensions available, the same features were astonishingly requested in Jetbrains’ Issue Tracker as long ago as 2004. Spearheaded presumably by COVID demands from remote workers, finally on 2020-09-18 &lt;a href="https://blog.jetbrains.com/blog/2020/09/28/code-with-me-eap/"&gt;Code With Me&lt;/a&gt; was released.&lt;/p&gt;

&lt;p&gt;So, when trying to debug a particularly tricky set of &lt;a href="https://jump24.co.uk/our-work/"&gt;feature tests&lt;/a&gt; with &lt;a href="https://twitter.com/_pads"&gt;Ben Paddock&lt;/a&gt;, it seemed like the perfect time for us to experiment with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Before
&lt;/h2&gt;

&lt;p&gt;What would the next steps have previously been before Code With Me, then? Well, choose your video conferencing suite of choice, share screen and one of you drives the session. It’s not the most intuitive of solutions, but it does at least mean your partner can see and dictate potential changes with you over video.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problems
&lt;/h2&gt;

&lt;p&gt;The biggest blocker for this type of pairing is that the ‘client’ human has no control over the IDE. Indeed, this is true of real life: when trying to think of potential solutions in code, one of you can only dictate to the other who is driving. I’m sure many readers would agree that, sometimes, dictating code and code changes is hard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;Code With Me has a couple of advantages over similar plugins such as CodeTogether. Here’s the two key features at Jump24 we found that were essential:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Because it uses a remote Java client developed by Jetbrains, it sandboxes the whole IDE on the host to the client. This means that the client doesn’t need to have the codebase. In our development where individual developers work on large, split codebases with entire Docker stacks, this gives a massive boost by not necessarily needing the entire project downloaded, dependencies from Javascript and PHP run and docker-compose spun up.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Because this client replaces the functionality of what ssh would be doing if you were to remote pair in something like, for example, vim and tmux, it means you both have 100% keypress access to the same remote terminal. If you were both debugging on a remote server, sure this doesn’t seem special. But, couple this with our large Docker stacks and both of you can run a command line ssh’d within the Docker stack on the host machine.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Aha! But Security!
&lt;/h2&gt;

&lt;p&gt;So, in terms of security and given that you can share an entire codebase with another “dumb IDE”, what’s going with those comms under the hood?&lt;/p&gt;

&lt;p&gt;The answer is: they’re going through Jetbrains’ servers. The infosec managers cry “ISO27001!” and if you’re in a large MegaCorp your pairing dreams are over. But, one of the really lovely features rolled out with this plugin is you can &lt;a href="https://www.jetbrains.com/help/cwm/code-with-me-quick-setup.html"&gt;run your own Code With Me server&lt;/a&gt;. Take that, MegaCorp!&lt;/p&gt;

&lt;h2&gt;
  
  
  Similar approaches: VSCode
&lt;/h2&gt;

&lt;p&gt;It’s worth noting that, &lt;a href="https://xkcd.com/378/"&gt;because I have some streak of masochism about me&lt;/a&gt;, I actually use two IDEs: PhpStorm for backend development in PHP and React/Vue and VSCodium for node.js and vanilla JS.&lt;/p&gt;

&lt;p&gt;CodeTogether has been available for VSCode for quite some time now, and while you might be tempted to scoff that users of that IDE have been ahead of the game, the two key features noted (remote shared terminal, run your own server) make Code With Me just take the edge. I expect these features to likely be on the way, mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: more joyful pairing
&lt;/h2&gt;

&lt;p&gt;Zoom calls and Skype screen sharing in the time of COVID have become tiresome, but switching to this toolset makes remote pairing a world of difference for the better. There’s just too many upsides to ignore here – as well as key features mentioned, it’s just the little things when trying to untangle your spaghetti. When you’ve both got the IDE running rather than one transmitted across via screen share, your linter works, both of you can use code completion and can navigate through classes – the list goes on.&lt;/p&gt;

&lt;p&gt;And, more to the point: surely anything is better than trying to dictate to the user what code to write.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mODLx34l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/02/joyfulpairing-768x432.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mODLx34l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jump24.co.uk/uploads/2021/02/joyfulpairing-768x432.png" alt="A Turtle on a keyboard, because finding images is hard" width="768" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Running and speaking at Online Events: what we’ve learned</title>
      <dc:creator>James Seconde</dc:creator>
      <pubDate>Mon, 07 Dec 2020 14:09:23 +0000</pubDate>
      <link>https://dev.to/jump24/running-and-speaking-at-online-events-what-we-ve-learned-4dij</link>
      <guid>https://dev.to/jump24/running-and-speaking-at-online-events-what-we-ve-learned-4dij</guid>
      <description>&lt;p&gt;My start at Jump24 was never going to be straightforward – the United Kingdom was in full COVID-19 lockdown, bringing down tech meetups and conferences worldwide at the point when I was fully launching into a Developer Relations role, which would immediately have to be redefined to make our developer outreach work. But: we currently have a talk and live code demo session currently on tour – so how did we do it, and what experience have we gained? But first: some observations about the impact of COVID-19 on our communities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Slow to adapt: how tech got caught napping
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8jxazabxwnzmn7znj66f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8jxazabxwnzmn7znj66f.png" alt="Screenshot of events being cancelled on meetup.com" width="606" height="154"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s hardly a surprising outcome with what happened after the Prime Minister announced full lockdown on 24th March. 34 tech events happened in the first two months in the West Midlands region in the UK, including regulars from DevOps, AWS, Ruby, Javascript, Xamarin/.NET, Docker and ProductTank. After lockdown in April and May, just 6 of the regular meetups happened after switching online, almost all of them Zoom calls. &lt;/p&gt;

&lt;p&gt;This was only for our region of course: the unexpected overhead of suddenly needing to organise and promote on entirely digital platforms meant that grassroots meetups dropped off all over the world and conferences got cancelled with no time to arrange alternative online setups.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speaking: Turbocharged development with Xdebug, Docker &amp;amp; PhpStorm
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa4dsgxtgtzan4u5w1llv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa4dsgxtgtzan4u5w1llv.png" alt="Screenshot of James Seconde giving Xdebug talk" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, the first question we had to ask was that if some usergroups were being continued online, should we go ahead with the idea of delivering a talk we’d prototyped internally? First, we’d have to solve the elephant in the room: this was due to be a live code demo. So, to deliver this talk we’d need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A speaker, me&lt;/li&gt;
&lt;li&gt;Google Slides, using Chrome&lt;/li&gt;
&lt;li&gt;A bash terminal&lt;/li&gt;
&lt;li&gt;PhpStorm&lt;/li&gt;
&lt;li&gt;Firefox&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do you juggle all this in virtual form, and how do you make it presentable? Step forward Jump24’s Ollie Matthews: Operations Manager and avid gaming streamer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons from the gaming world
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Finpaul9j17hjsllqvqzb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Finpaul9j17hjsllqvqzb.jpg" alt="Photo of our streaming setup" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Multiple input sources to create a slick streaming platform, you say? Well, it came as no surprise that professional gamers have had this mastered for quite some time. Ollie outlined the equipment needed, so here’s how we built the home studio for streaming:&lt;/p&gt;

&lt;h2&gt;
  
  
  The office streaming setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Macbook Pro 2016 (Touchbar)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://everymac.com/systems/apple/macbook_pro/specs/macbook-pro-core-i9-2.3-eight-core-15-mid-2019-touch-bar-specs.html"&gt;https://everymac.com/systems/apple/macbook_pro/specs/macbook-pro-core-i9-2.3-eight-core-15-mid-2019-touch-bar-specs.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the field of web application development, particularly in the realms of PHP, Javascript/Node and Ruby, the dominant Operating System on a user level tends to be skewed towards macOS. We use Macs for developing in Laravel, so it’s worth noting that our experience in putting together a streaming setup is already going to differ from the gaming world, where Windows is by far the dominant platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Elgato Stream Deck
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.elgato.com/en/gaming/stream-deck"&gt;https://www.elgato.com/en/gaming/stream-deck&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnh8hmb8cyyt8aaporzop.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnh8hmb8cyyt8aaporzop.jpg" alt="Photo of our Stream Deck" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Elgato’s Steam deck is really the keystone feature of the setup – the ability to create a custom setup that can control lighting, desktop applications (so this tackled the quick switch between terminal, IDE, Firefox and Google Slides on Chromium), Twitch, and OBS (in particular scenes &amp;amp; transitions) is a gamechanger. This bit of kit is no stranger to the gaming world: streamers use it regularly for Twitch (and other socials integration such as Twitter), recording and scene control. Elgato has recently opened up the button marketplace, adding new control sets such as integration for VSCode.&lt;/p&gt;

&lt;h3&gt;
  
  
  Elgato Key Light
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.elgato.com/en/gaming/key-light"&gt;https://www.elgato.com/en/gaming/key-light&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr75xtzksz8jt8j53r0ej.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr75xtzksz8jt8j53r0ej.jpg" alt="Photo of our Key Light" width="768" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Despite many people’s beliefs, lighting is one of, if not the most important part of any streaming setup. So, the next thing we went for in the Elgato family is the Key light. Yes, this may seem a little expensive compared to other LED panels or ring lights but this particular light seamlessly integrates into the rest of our setup – including the Stream Deck.&lt;/p&gt;

&lt;p&gt;With its sleek design it can fit into any space or desk setup, and hooking it up to your PC via wifi allows you to tweak the brightness and temperature to best suit your needs.&lt;/p&gt;

&lt;p&gt;Despite the premium nature of this product, the setup wasn’t all plain sailing. The Key Light requires a 2.4ghz banded Wifi and doesn’t work with 5ghz. I have a dual band router, so when I switched on 2.4ghz it firstly had a weak signal despite not being far away (common with poor routers dished out by providers). Secondly, my new TV fights with the Key Light over who gets to be connected to the network.&lt;/p&gt;

&lt;p&gt;For more advanced colour options, you might want to consider the Elgato Ring Light, but still has the same potential burden regarding control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rode NT-USB with boom or Elgato Wave:3
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.rode.com/microphones/nt-usb"&gt;https://www.rode.com/microphones/nt-usb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.elgato.com/en/wave-3"&gt;https://www.elgato.com/en/wave-3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgw8npf3xaluzff3qnm48.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgw8npf3xaluzff3qnm48.jpg" alt="Photo of our Elgato Wave 3" width="768" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Originally I’d purchased the Blue Yeti on the back of many recommendations, but it shipped broken. Rode’s USB mic might not have the multi pattern recording modes that the Yeti does, but it does come with a decent pop filter and reasonable price tag. In the office setup we use the Elgato Wave:3 with a boom and filter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logitech Streamcam
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.logitech.com/en-gb/products/webcams/streamcam.960-001281.html"&gt;https://www.logitech.com/en-gb/products/webcams/streamcam.960-001281.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjvwzuqdd1zyoxq4p8xq0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjvwzuqdd1zyoxq4p8xq0.jpg" alt="Photo of our Streamcam" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choices for HD streaming are vast, and so sifting through the pages of 1080p cameras can be daunting. The important bit here is to answer the glaring question: “do I need a 1080 webcam?”. Well, what we wanted at Jump24 was as professional a setup as we could get, which included a 1080 cam. However, it’s worth pointing out that if your scenes are mostly a small corner box with a slide deck taking centre stage (or on a live demo like ours – a terminal, browser etc.) then realistically any cam will likely be sufficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  Elgato Green Screen
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.elgato.com/en/gaming/green-screen"&gt;https://www.elgato.com/en/gaming/green-screen&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is something new we have added to our setup but yet to implement. Using a green screen will allow us to expand our Overlay options when doing events, from branded backdrops, animations to simply removing a messy background. &lt;/p&gt;

&lt;p&gt;A green screen can be something that eliminates issues; add a chrome key filter in your broadcasting app of choice and, just like magic: the background has disappeared.&lt;/p&gt;

&lt;h3&gt;
  
  
  OBS Studio
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://obsproject.com/"&gt;https://obsproject.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open Broadcaster Studio has been at the forefront of game streaming for at least five years. It’s ability to take almost any media input and generate an output for streaming, and for free as Open Source Software makes it an industry standard of sorts. There are disadvantages, however – the majority of its users tend to be on Windows platforms, so if you’re using the MacOS or Linux ports it can be a little more buggy. In order to hook up OBS to various hosting platforms where no integration with OBS is possible, it needs the ‘Virtual Camera’ feature, that will take the OBS output and pipe it into a virtual device. The likelihood is that if you are in control of your stream, you can hook up OBS to YouTube or Twitch with API keys directly and thus won’t need to use the Virtual Camera, but when you are being hosted and control is out of your hands it will be needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Being Hosted: your meetup’s tech stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Zoom / Skype
&lt;/h3&gt;

&lt;p&gt;Zoom capitalised on their new found advantage by offering unlimited free tier calls. It’s probably not that much of a surprise then that Zoom seems to have become the default. I’ve done the talk a couple of times now on Zoom with OBS’s Virtual Camera output and not found any issues with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Jitsi
&lt;/h3&gt;

&lt;p&gt;Jitsi would absolutely not play ball with the OBS Virtual camera output – problems included output resolution and “flipping” the output image. What made Jitsi unusable for us, however, is that there is a tendency for meetups using it to have the free tier (for understandable reasons). Unlike the resource Zoom has to throw at free tier usage, it was clear that the servers were heavily throttling the connection. That’s not a problem if you’re doing a brief meeting, but presenting and pulling down docker containers? Nope.&lt;/p&gt;

&lt;h3&gt;
  
  
  Streamyard
&lt;/h3&gt;

&lt;p&gt;Streamyard is a popular option, and from a speakers’ perspective has decent features: a backstage broadcasting area and a screenshare perspective that takes care of the scene layout for you. There is, however, a disadvantage to this (as we discovered) in that you can’t use OBS’s virtual camera output. The image resolution is cropped awkwardly, but more importantly with OBS you’re trying to replicate a feature that Streamyard is designed for. This is where there’s a big difference in Streamyard between speaking and hosting: as a speaker, you don’t have control whereas when hosting you can include backdrops with branding.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkif1rjugg1tr1zctkpg3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkif1rjugg1tr1zctkpg3.png" alt="Jitsi, Zoom and Streamyard logos" width="763" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosting: Tech stack options with Kevin Lewis
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwt7h7gm5kwwpffyvl28i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwt7h7gm5kwwpffyvl28i.png" alt="Preview of Jump24 tweet about forthcoming events" width="585" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, we’ve covered being the speaker in virtual meetups, but what about hosting your own? Before COVID hit, we were planning to launch a new tech, art &amp;amp; culture event in the city, BrumTech Tapas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvwxzps2dcwk5n3jk6yti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvwxzps2dcwk5n3jk6yti.png" alt="BrumTechTapas design banner" width="800" height="84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the switch to virtual, we needed to think about our options from an organisers’ view. Rather than go into this foray blindly, I spoke to Vonage’s &lt;a href="https://twitter.com/_phzn"&gt;Kevin Lewis&lt;/a&gt;, whom I knew had a mountain of experience in this area due to his events work with the &lt;em&gt;You Got This Conference&lt;/em&gt; Series, &lt;em&gt;Women of React&lt;/em&gt; and &lt;em&gt;Vonage’s Developer Day&lt;/em&gt;.&lt;/p&gt;




&lt;p&gt;Online events provide some really exciting opportunities to build experiences that just wouldn’t be possible in a physical space, for the affordances that tech brings. When organizing events, you can try and emulate offline events complete with networking setups, work towards an Apple WWDC-style highly-produced live TV show, or create more novel experiences such as Roguelike Celebration. &lt;/p&gt;

&lt;p&gt;When choosing your setup, there are five core considerations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Complexity of Operation – how confident is your team to use more complex tooling?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creative Flexibility – how customized do you need the output to be? &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Moderation Bandwidth – how much people-power do you have for moderation, and how does the choice of platforms impact this?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Attendee Experience – what is an ideal experience for attendees? Do you want to facilitate networking? Should it all be in one platform?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Speaker Experience – how involved or complex can your speaker experience be while still being appropriate for who you have invited?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Some of these items are inextricably linked – having more creative flexibility is likely to increase complexity, for example. &lt;/p&gt;

&lt;p&gt;My first full-scale online conference was Women of React back in April. We used Skype (with NDI) and OBS for managing the stream, YouTube for hosting the stream and Discord for community interactions. We got a really lovely set of custom scenes and full control over what was seen or heard, but it was a pain to keep on top of. The speakers and MC had to really work through all of the technical quirks (which they did fantastically), but it was difficult. &lt;/p&gt;

&lt;p&gt;Using a video call, piping data into OBS via the NDI protocol and pushing out a completed stream to your host means your one device will be doing lots of computationally-expensive operations, and if it fails to deliver the whole event will suffer. There are contingencies to this – such as renting a more powerful cloud-hosted machine and completing the work on it, but this comes at an additional cost and setup time.&lt;/p&gt;

&lt;p&gt;My team at Vonage chose to use a platform called Remo for Vonage Developer Day – which has a networking component aiming to emulate offline events. Attendees can gather and move around tables – each a small video call between groups. &lt;/p&gt;

&lt;p&gt;Through all the events I’ve run, I still believe Streamyard provides the best overall setup for publishing livestreams. While you are creatively limited to just the 7 pre-set layouts provided, they are designed with care and almost every use case in mind. &lt;/p&gt;

&lt;p&gt;Also consider the need for networking in the long, long year that is 2020. I am a fan of giving people spaces to meet, but nothing will replace being in the same room. Many folks have screen fatigue, and many will be motivated only by consuming the organized content. Consider if this is true in your community and whether you can place somewhat-forced networking efforts aside for a happier time. &lt;/p&gt;

&lt;p&gt;If you want to find out more about the considerations and outcomes around Women of React, Vonage Developer Day and You Got This From Your Couch – you can &lt;a href="https://www.youtube.com/watch?v=56rvtjZ9x3g"&gt;watch my talk&lt;/a&gt; from DevRelCon Earth earlier this year.&lt;/p&gt;

&lt;h2&gt;
  
  
  Event Branding – design considerations
&lt;/h2&gt;

&lt;p&gt;The new branding for Brum Tech Tapas along with the website had just been completed before we went into the first lockdown. The idea was to keep it simple and not focus solely on the tech community. A lot of this was achieved by building the website and the photography we used to represent the diverse cultural scene in Birmingham. &lt;/p&gt;

&lt;p&gt;The next design aspect we had to tackle was moving the talks over to Twitch. Something as designers we had no experience in. We started taking a look at other Twitch coder accounts and noticed that the aesthetics weren’t always a priority, something we wanted to avoid. As this was something relatively new for tech talks in Birmingham we wanted to make sure we put our best foot forward, using our branding to create something aesthetically pleasing whilst allowing for multiple speakers to be shown and live coding to be clear and visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Virtual means more accessible options
&lt;/h2&gt;

&lt;p&gt;The equipment we put together and time invested in designs etc. comes at a cost. The decisions that we made are based on the notion that you don’t have to invest much to get a polished, professional setup that looks no different from international tech firms’ branding and content delivery.&lt;/p&gt;

&lt;p&gt;While that’s certainly the conclusion for what we were looking for, it’s important to bear in mind that to speak at a meetup or to host one, you technically don’t need any of this. This is vital to know if you’re starting out speaking and need some exposure, or you’re booting up a new usergroup (or transitioning online for the first time). All you actually need is an internet connection, a webcam and people to join. As with most things, the end goals of what you want to achieve dictate the requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Virtual meetups and conferences: advantages and disadvantages
&lt;/h2&gt;

&lt;p&gt;So, given that we’ve gone through planning, let’s have a bit of a postmortem on the key things to think about when it comes to running virtual tech events. As we approach tech events from a Developer Relations perspective – raising awareness of our work and doing developer outreach for education, it’s now very apparent what can run smoothly and what snagging points you can encounter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Speaker Pools
&lt;/h4&gt;

&lt;p&gt;The rules have now been redefined – you can officially contact someone elsewhere on the planet and ask if they want to speak at your meetup. It’s worth noting that, while there is an element of truth to that sentence, many of the meetups I have spoken at have very much stuck to a pool of speakers already within their network. While it might have potentially opened more doors to speakers, it’s also worth considering that it doesn’t give you an immediate ‘yes’ from everyone.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cost
&lt;/h4&gt;

&lt;p&gt;The cost of what you’re looking at has pretty much been outlined in the article. In-person meetups require spaces, the oh-so-stereotypical “Pizza for 30 developers” and drinks sponsorships. If you’ve got a fancier meetup, you might have catering. The cost of running a meetup can be £0 if you want it to be; even the price of a conference is suddenly astonishingly low considering the speakers you might have been able to virtually pull in.&lt;/p&gt;

&lt;h4&gt;
  
  
  Potential Reach
&lt;/h4&gt;

&lt;p&gt;The point of a local usergroup is that you form smaller communities around common themes – the convenience of opening it up without a physical form means that your attendance might well spike. In the usergroups we’ve spoken at on our current talk, it’s noticeable how the attendance is actually higher. In the PHP world this does however have a drawback – one of the reasons you’ll see more one some of the events is because PHP developers are aware of other local usergroups. There is a scenario playing out right now that we’ve seen. A point Raised by one of the usergroups we spoke at stated that the same talks are going round the circuit and thus someone from Bristol might not want to watch a talk on at PHPSW: because they already saw it at PHPMiNDS in Nottingham.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disadvantages
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhe2g3e5lqioqdxejbjuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhe2g3e5lqioqdxejbjuw.png" alt="Cartoon by Tom Fishburne on standard Zoom meeting nightmares" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Loss of 1-2-1 interaction
&lt;/h4&gt;

&lt;p&gt;Developer Relations still thrives on in-person 1-2-1 interactions – from my experience personally this is still the best way to network and create a hub of people with similar interests to get feedback and opinions off. Without that, the hardest part of expanding your network has pretty much gone. Yes, in speaking to event organisers, recreating this part of outreach has been attempted, but as of yet not many that I’ve spoken to have reported a successful method for doing it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Internet speeds
&lt;/h4&gt;

&lt;p&gt;This one stands out by a country mile. If COVID has shown us anything, it’s how reliant in the tech world we are for the Internet for software development beyond the obvious limitations of CI pipelines and Docker pulls. &lt;/p&gt;

&lt;p&gt;Your speaker’s connection goes down 5 hours before the event because someone drilled through a pipe. Your speaker’s connection goes down during the event while speaking because geese have attacked the exchange. What do you do?&lt;/p&gt;

&lt;p&gt;That’s only from the speakers’ perspective. During the tour of our current talk, my internet speed was fairly poor, and an unexpected need to pull an nginx container resulted in my best Minecraft look. But what if you encounter this when you’re on StreamYard and hosting the whole event? Well, then you’ve not really got any options. But you can prepare by making sure you host from a high speed connection, especially if you have speakers from across the globe, and especially if they’re not in the standard Western world tech bubble.&lt;/p&gt;

&lt;h4&gt;
  
  
  The curse of remote working
&lt;/h4&gt;

&lt;p&gt;This is one of the biggest issues with moving virtual. You’ve just spent eight hours of your day on Zoom calls, JIRA and your IDE open in front of you, barely moving apart from the get the occasional coffee which is also now done in silence.&lt;/p&gt;

&lt;p&gt;Come 6:30pm, is opening up a Zoom call with 30 people in to have a virtual tech talk (that, in some cases, is being recorded and will be available at any point in the future you choose anyway) really how you want to spend your evening?&lt;/p&gt;

&lt;h4&gt;
  
  
  Losing outreach: Slack/Discord
&lt;/h4&gt;

&lt;p&gt;This is Developer Relations. Marketing people might well not see the problem with throwing out “for discussions, sign up to our Slack/Discord!”, but we know the pain of being told for the 10th time in a month to sign into a new social media platform for one event that will be used once.&lt;/p&gt;

&lt;p&gt;This particular subject has been covered recently by &lt;a href="https://twitter.com/jna_sh"&gt;Joe Nash&lt;/a&gt;, offering to open up discussions as to why &lt;em&gt;Let’s Just Create a New Slack&lt;/em&gt; really isn’t the one-size-fits-all solution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgik66mw5qe0nht33uua3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgik66mw5qe0nht33uua3.png" alt="Screenshot Joe Nash's Twitter feed saying please don't create another slack" width="591" height="648"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://twitter.com/jna_sh/status/1326514552251568130"&gt;https://twitter.com/jna_sh/status/1326514552251568130&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more fitting options, specifically around the biggest sticking point of live feedback/community comms – moderation – check out Joe’s tweets and subsequent discussions on why certain platforms have advantages over Slack. What’s interesting is that Discord comes up time and time again in conversations – another crossover from the gaming world.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: A more versatile outreach
&lt;/h2&gt;

&lt;p&gt;So, what are the results of what we did? Well, like most people I expect, we’re ready for physical events again for sure. But for now, I’ll put it this way: we’re now equipped and experienced in hosting and delivering virtual content. This is something we certainly couldn’t do before, and besides: without the COVID crisis many large tech companies did have the ability to create content in this way. So, by preparing for virtual content and calling in advice across disciplines both internally and externally – Jump24 has a far more versatile outreach capability. Which, after all, is the point of Developer Relations, isn’t it?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;With thanks to Ollie Matthews, Anneka Mistry, Kevin Lewis and Joe Nash.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Turbocharged PHP Development with Xdebug, Docker &amp; PHPStorm.</title>
      <dc:creator>James Seconde</dc:creator>
      <pubDate>Thu, 13 Aug 2020 07:48:59 +0000</pubDate>
      <link>https://dev.to/jump24/turbocharged-php-development-with-xdebug-docker-phpstorm-1n6c</link>
      <guid>https://dev.to/jump24/turbocharged-php-development-with-xdebug-docker-phpstorm-1n6c</guid>
      <description>&lt;h3&gt;
  
  
  It all started out with that oh-so-modern cause of a community backlash: the humble tweet.
&lt;/h3&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%2Fcdn.jump24.co.uk%2Fuploads%2F2020%2F08%2Ftweet.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%2Fcdn.jump24.co.uk%2Fuploads%2F2020%2F08%2Ftweet.png" alt="Derick Trolling people"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://twitter.com/derickr/status/1274134192155131905" rel="noopener noreferrer"&gt;https://twitter.com/derickr/status/1274134192155131905&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quite the controversial “hot-take” from Derick, and while it certainly caused quite the stir (that it was probably designed to), it made me think. I thought, &lt;strong&gt;‘Do I need to revisit Xdebug?’&lt;/strong&gt;, and I realised that I’d fallen into Derick’s trap. But think I did.&lt;/p&gt;

&lt;p&gt;Let’s clear up some existing thoughts I had on Xdebug – some readers might nod in agreement or have/had similar experiences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Like many PHP developers with significant experience: &lt;strong&gt;I know of Xdebug&lt;/strong&gt;. It’s been around years – I started writing PHP professionally in 2016, by which time Xdebug had existed for 14 years. It’s not like it was some obscure or new tool being talked about.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;I’d tried Xdebug before at some point&lt;/strong&gt; – I can’t recall when, and had an experience that left me thinking that understanding what you could do with it would take far too much time up for me to learn. Plus, things like custom “bookmark” browser extensions made it feel like you had to jump through a lot of hoops to use it effectively. A lot has changed since I started – I use Jetbrains PHPStorm as my IDE, and develop with Docker. It was a pain trying to set it up manually before, but what about now, where Xdebug runs a server on an IP, but it will be running in Docker?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://devtheatre.net/blog/psysh/" rel="noopener noreferrer"&gt;I’ve previously written an article&lt;/a&gt; on how superb PsySh is as an application’s command line. Given that when used as part of Laravel’s &lt;code&gt;tinker&lt;/code&gt; it boots up the whole app into a REPL environment, does that render something like Xdebug somewhat redundant?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lastly, but most importantly for developers: why bother when you can use &lt;code&gt;var_dump()&lt;/code&gt; or Symfony’s &lt;code&gt;dump()&lt;/code&gt; or Laravel’s &lt;code&gt;dd()&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These thoughts of mine were also circulated in others’ replies to the tweet, but it was when Tighten’s Matt Stauffer and Twilio’s Gary Hockin stepped in to offer livestreams with Derick to set it up that I took notice – the resulting content is now excellently documented at &lt;a href="https://learnxdebug.com" rel="noopener noreferrer"&gt;https://learnxdebug.com&lt;/a&gt; with others’ contributions.&lt;/p&gt;

&lt;p&gt;So, I thought: why not give it a go again? And so I did, going step by step though Gary and Derick’s video, with the goal to implement it into our development process for our Open Source project &lt;a href="https://awe-der.net" rel="noopener noreferrer"&gt;Awe-der&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How hard can it be?
&lt;/h2&gt;

&lt;p&gt;One of the things that most articles I’d read or tried to follow miss out one core thing that frustrated me: most have the “how”, but not the “why”. That is to say: what is this thing I’m doing and why does it work?&lt;/p&gt;

&lt;p&gt;Bearing that in mind, here is how I implemented the stack, step by step with a little bit more info than just your average set of instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&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%2Fi%2Ff4x8yoqa5t001wq2khxv.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%2Fi%2Ff4x8yoqa5t001wq2khxv.png" alt="Logos of tech used, will read now"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MacOS 10.15 (Catalina)&lt;/li&gt;
&lt;li&gt;PHPStorm 2020.1&lt;/li&gt;
&lt;li&gt;PHP 7.4.4 (from official PHP Dockerfile)&lt;/li&gt;
&lt;li&gt;Docker 19.03.8 (engine) 1.25.5 (compose)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step One: Installing Xdebug
&lt;/h3&gt;

&lt;p&gt;Part of what made the installation significantly easier for me was that the project it was being installed on was already using a Dockerfile as part of the stack. So, to install Xdebug, you need to include it with pecl (you can still -only- use pecl for operating system-level dependencies at the time of writing). Our project had this in our Dockerfile to install redis and imagick:&lt;/p&gt;

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

RUN docker-php-source extract &amp;amp;&amp;amp; \
   pecl install redis &amp;amp;&amp;amp; \
   pecl install imagick &amp;amp;&amp;amp; \
   docker-php-ext-enable imagick &amp;amp;&amp;amp; \
   docker-php-ext-enable redis &amp;amp;&amp;amp; \
   docker-php-source delete


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

&lt;/div&gt;

&lt;p&gt;It’s at this point you want to install it with pecl, so add pecl install Xdebug into the run commands for the container:&lt;/p&gt;

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

RUN docker-php-source extract &amp;amp;&amp;amp; \
   pecl install redis &amp;amp;&amp;amp; \
   pecl install xdebug &amp;amp;&amp;amp; \
   pecl install imagick &amp;amp;&amp;amp; \
   docker-php-ext-enable imagick &amp;amp;&amp;amp; \
   docker-php-ext-enable redis &amp;amp;&amp;amp; \
   docker-php-source delete


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

&lt;/div&gt;

&lt;p&gt;You can see the actual live Dockerfile (with the correct install command) at: &lt;a href="https://github.com/awe-der/aweder-core/blob/release/table-ordering/docker/php/Dockerfile" rel="noopener noreferrer"&gt;https://github.com/awe-der/aweder-core/blob/release/table-ordering/docker/php/Dockerfile&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step Two: Configuring Xdebug
&lt;/h3&gt;

&lt;p&gt;Before Docker, Xdebug was relatively straightforward to configure on a platform, in that it was a new set of the php.ini parameters – you’d either just edit the existing php.ini, or load in a custom ini or override. Now we’re running PHP and fpm in a container, so we need to inject the configuration in with docker-compose.&lt;/p&gt;

&lt;p&gt;First, create the file to inject and save it in the project root – let’s call it xdebug-local.ini.&lt;/p&gt;

&lt;p&gt;Here’s what to put in it:&lt;/p&gt;

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

zend_extension=xdebug
xdebug.remote_enable=1
xdebug.remote_autostart=1
xdebug.remote_port=9001
xdebug.remote_host=host.docker.internal


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

&lt;/div&gt;

&lt;p&gt;I said this wouldn’t just be a copy and paste article, so: what are these parameters?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Zend_extension&lt;/code&gt; has always been the PHP ini file parameter name for adding in extensions – it hooks the pecl extension (or extensions installed with other tools like PEAR) installed to the runtime, so things like zip, redis, curl and the like use the same parameter to enable them.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;xdebug.remote_enable&lt;/code&gt; and &lt;code&gt;xdebug.autostart&lt;/code&gt; are more interesting. Remember me mentioning “bookmarklets” in the browser earlier? You have to use an extension to keep a server connection alive with your Xdebug session – for example, for Firefox:&lt;br&gt;
&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/xdebug-helper-for-firefox/" rel="noopener noreferrer"&gt;https://addons.mozilla.org/en-US/firefox/addon/xdebug-helper-for-firefox/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sound clunky? You bet. Is it required? Absolutely not. Enable remote triggering of the Xdebug server and set autostart to true when either a breakpoint is hit in the code or you’ve set the break to be at the entry point to your application’s code and: bingo. It triggers your debugging session. Do I wish I’d have known about this years ago? For sure.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Xdebug.remote_port&lt;/code&gt; has an interesting quirk in that if you don’t set the parameter, it defaults to port 9000. I guess it’s an interesting aspect that shows Xdebug’s history in that it was probably chosen as a default port before the CGI adopted replacement php-fpm used port 9000. So, it’s important to set the remote port to 9001 (or whichever free port you wish) to stop clashes.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Xdebug.remote_host&lt;/code&gt; is the point at which our Docker configuration starts making the process perhaps a little convoluted. In our case, we develop as a company with Macs, so it’s handy that Docker has a reserved handle (&lt;code&gt;host.docker.internal&lt;/code&gt;) to route into the correct IP. Windows does the same at the time of writing, but Linux distributions might need a bit of research to get the correct address in here to connect into Docker.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step Three: Inject Config to Docker
&lt;/h3&gt;

&lt;p&gt;So, using &lt;code&gt;docker-compose&lt;/code&gt;, we now inject the local ini file into the php container’s conf.d directory. The docker-compose file should look something like this:&lt;/p&gt;

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

php:
   container_name: my_container
   build: ./path/to/my/php/dockerfile
   environment:
       PHP_MEMORY_LIMIT: '128M'
       DB_HOST: 'mysql'
       DB_USER: 'root'
       DB_PASSWORD: 'root'
       DB_NAME: 'if_your_app_has_a_db'
       PHP_IDE_CONFIG: 'serverName=myapp.url'
   volumes:
       - ./:/var/www/vhost/:cached
       - ./xdebug-local.ini:/usr/local/etc/php/conf.d/xdebug-local.ini


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

&lt;/div&gt;

&lt;p&gt;There are two things here to point out. Firstly, the docker volumes – it’s this line that’s going to enable Xdebug:&lt;/p&gt;

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

./xdebug-local.ini:/usr/local/etc/php/conf.d/xdebug-local.ini


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

&lt;/div&gt;

&lt;p&gt;The second one was a big gotcha: PHPStorm will need to match the incoming Xdebug server request to the webserver that’s set up in the IDE.&lt;/p&gt;

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

PHP_IDE_CONFIG: 'serverName=myapp.url'


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

&lt;/div&gt;

&lt;p&gt;I hadn’t actually set up the webserver on PHPStorm because I personally find a lot of the CLI and server setups for it extremely complex and hard to understand. But, because this environment variable is used to match to PHPStorm’s webserver setup, it cannot match the file structure without it – but more on that in a bit.&lt;/p&gt;

&lt;p&gt;It’s time to check that Xdebug is working: rebuild your Docker stack&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 build build &amp;amp;&amp;amp; docker-compose up -d

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

&lt;/div&gt;

&lt;p&gt;And to check, debug by throwing phpinfo(); into an entrypoint to your app. Navigate to Xdebug on the page and you should see the following:&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%2Fi%2F6rr484iurlkfyga13bh2.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%2Fi%2F6rr484iurlkfyga13bh2.png" alt="Xdebug config in phpinfo"&gt;&lt;/a&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%2Fi%2Fdt4uk7s9ggozzaiq3fvf.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%2Fi%2Fdt4uk7s9ggozzaiq3fvf.png" alt="Xdebug set config values"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step Four: Set up PHPStorm
&lt;/h3&gt;

&lt;p&gt;I briefly mentioned that you need to set up your web server on PHPStorm first – so do that first. You can find pretty comprehensive and complete docs from Jetbrains on this here: &lt;a href="https://www.jetbrains.com/help/phpstorm/creating-local-server-configuration.html#example1" rel="noopener noreferrer"&gt;https://www.jetbrains.com/help/phpstorm/creating-local-server-configuration.html#example1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we get PHPStorm to listen to port 9001 which we set in the config. You can change that like so:&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%2Fi%2Fdya8lazptc1msqbxmqb8.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%2Fi%2Fdya8lazptc1msqbxmqb8.png" alt="PHPStorm Xdebug settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Path mapping is important – PHPStorm has no way from the incoming request of knowing how the application is structured. Here’s an example of the configuration for Awe-der:&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%2Fi%2F9aw73oec5g6pjbv1a5a8.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%2Fi%2F9aw73oec5g6pjbv1a5a8.png" alt="Web server setup in PHPStorm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The absolute path on the server is what you need to change – make sure you change it to the root path served by your Docker stack (in our case, where nginx is serving the root of the application). This is an important step because PHPStorm assumes that the root directory from the incoming request is the public folder (if using either Symfony or Laravel). Make sure you also choose Xdebug as the debugger and use the appropriate HTTP port. Now, set PHPStorm to listen.&lt;/p&gt;

&lt;p&gt;It’s time for the moment of truth: you’re listening for connections, you’re mapped, you’ve setup the Xdebug server: showtime. Add a breakpoint in PHPStorm (preferablly at the entry point of your app, so you know it’ll get hit), fire a request in the browser and IF everything is OK you’ll get an incoming connection from Xdebug in the IDE. Happy days if you did, don’t despair if you don’t: there are a lot of gotchas here. If nothing happens, the other tutorials at &lt;a href="https://learnxdebug.com/" rel="noopener noreferrer"&gt;https://learnxdebug.com/&lt;/a&gt; will probably have the answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  As promised: Turbocharged Development
&lt;/h3&gt;

&lt;p&gt;So, here’s what you actually came here for, right? As with debugging in other interpreted languages, your start point will be a breakpoint (you can actually set PHPStorm to hit a breakpoint whenever a new file entry point is detected as well).&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%2Fi%2F2rhq99j1qie2tovw0t7e.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%2Fi%2F2rhq99j1qie2tovw0t7e.png" alt="Code with breakpoint"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s a breakpoint set in our Awe-der project. We’re listening for connections – so, all being well we hit the Controller when loading the page, and hey presto! PHPStorm’s debugging pane appears.&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%2Fi%2F48qj6qupm2281fb7z5z8.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%2Fi%2F48qj6qupm2281fb7z5z8.png" alt="Debugging pane in PHPStorm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we’re at a paused moment in the runtime, let’s check out what we can do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Console / Evaluate expression
&lt;/h3&gt;

&lt;p&gt;You get a console that can run executable PHP within the runtime you’re in. That is… absolutely magic. Here’s an example of using the console live within Xdebug that will save you a mountain of &lt;code&gt;var_dump()&lt;/code&gt; calls:&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%2Fi%2F3ppexh58aw64wi1yfsah.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%2Fi%2F3ppexh58aw64wi1yfsah.png" alt="Console printed code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Putting a variable straight into the console will print it, in exactly the same way that Javascript does it with console.log in a browser console.&lt;/p&gt;

&lt;p&gt;We can change something on any variable at runtime in the console. Take for instance this line:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$orderItem-&amp;gt;fill($apiPayload);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That’s Laravel’s Eloquent ORM. Why not see what happens at runtime when you do something else with it in the console?&lt;/p&gt;

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

$orderItem-&amp;gt;toArray()
‌array (
  'order_id' =&amp;gt; 1,
  'inventory_id' =&amp;gt; 2,
  'variant_id' =&amp;gt; 1,
)

$orderItem-&amp;gt;fill(['order_id' =&amp;gt; 234523523]);

$orderItem-&amp;gt;toArray()
‌array (
  'order_id' =&amp;gt; 3333,
  'inventory_id' =&amp;gt; 2,
  'variant_id' =&amp;gt; 1,
)


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

&lt;/div&gt;

&lt;p&gt;Done. We’ve just messed around with an entity on the fly.&lt;/p&gt;

&lt;p&gt;The console has everything set &amp;amp; booted (assuming you’re using Composer’s autoload) to the point it’s activated – so crucially local scope variables are available. You can also navigate the stack as well via. the frames in the debugger. Laravel has pretty detailed stack traces when you use Blade, but they’re not interactive ones like we can get in the IDE:&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%2Fi%2Fz2xuaq0o3dncpmzm32gd.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%2Fi%2Fz2xuaq0o3dncpmzm32gd.png" alt="Debugging pane with frames"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is next level debugging. You can navigate the frame pane to the left to view the executed stack. When you select a frame from it, the editor pane will navigate to the function call in the code and the variable pane will update to everything that has been set at that point. For big monolith stacks full of services and function calls all over the place, you’ve now got far more visibility. Pretty neat, huh?&lt;/p&gt;

&lt;h3&gt;
  
  
  Conditional Breakpoints
&lt;/h3&gt;

&lt;p&gt;An underrated feature is the ability to set breakpoints conditionally. For an example, let’s say that we only want to trigger the breakpoint to debug if an incoming request to a controller has a “search” term set.&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%2Fi%2Fjwrtk90s8r85l1bf4o5z.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%2Fi%2Fjwrtk90s8r85l1bf4o5z.png" alt="Code with conditional breakpoint set"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Done. Another joy of this in PHPStorm is that the Condition window behaves like any other console window, so you get application-wide autocompletion and local variable autocompletion.&lt;/p&gt;

&lt;p&gt;So, if we hit the URL:&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%2Fi%2Fiedpdi8dd8yzgu3cl8f4.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%2Fi%2Fiedpdi8dd8yzgu3cl8f4.png" alt="Awe-der dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Loads as expected, but add the search term in to the URL:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://awe-der.net/admin/dashboard?search=test&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%2Fi%2Fu6yxx2hxmqnusaeyks8d.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%2Fi%2Fu6yxx2hxmqnusaeyks8d.png" alt="Hit the breakpoint"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Watchers
&lt;/h3&gt;

&lt;p&gt;Common debugging nightmares include mutable objects being hit -somewhere- in the stack. We have visibility of the stack, but that’s not much help when tracking a specific object. To set a watcher, add an expression in the watcher pane to the left. It will be evaluated with each step you trigger. A good example to see it in action would be the classic C loop:&lt;/p&gt;

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

public function testWatcher(): void
{
   $variableToWatch = 45;

   for ($i = 1; $i &amp;lt; 5; $i++) {
       $variableToWatch = $variableToWatch + rand(0, 200);
   }
}


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

&lt;/div&gt;

&lt;p&gt;Set a watcher on &lt;code&gt;$variableToWatch&lt;/code&gt;, and check out the watcher doing it’s magic just like any Javascript browser watcher as you step over the 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%2Fi%2F9pm5krh0eukb6iketx4b.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%2Fi%2F9pm5krh0eukb6iketx4b.png" alt="Active watcher window"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step &amp;amp; Cursor controls:
&lt;/h3&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%2Fi%2Fs0znw0ps9avhlmem6z1x.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%2Fi%2Fs0znw0ps9avhlmem6z1x.png" alt="Cursor controls in PHPStorm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The five controls are as follows:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step over&lt;/strong&gt;: run to the next line of code&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step into&lt;/strong&gt;: run into the next line, moving the cursor if entering a method call&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Force step into&lt;/strong&gt;: same as Step into, but runs with calls into vendor/3rd party code for deeper debugging&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step out&lt;/strong&gt;: complete the current method and stop at the next line after the method that called it&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run to cursor&lt;/strong&gt;: For me, this is the most important one, and I’ll tell you why:&lt;/p&gt;

&lt;p&gt;If you’re debugging something quite straightforward in that it’s your own code entirely, or something like the Slim framework with as little code as possible, stepping through the code is pretty logical. However, for those using a big framework – Laravel, Symfony, Cake, WordPress etc. there are calls, pipelines and event handlers all over the app. That magic has got to happen somehow, and if you try and step into it, you can see it in action.&lt;/p&gt;

&lt;p&gt;Don’t want to see all the handlers resolve? Cool. Move the cursor to the next line you want, so you can see the result piped into the variable frame. Hit run to cursor, job done.&lt;br&gt;
Probably the most important: modifying the output&lt;/p&gt;

&lt;p&gt;Modifying the output is, in my opinion, what makes Xdebug so powerful. We’ve looked at the fact that you can change variables and interact with the code at runtime, but what hasn’t been mentioned is that if you instruct the debugger to complete, the output is the changed output. To see it in action, here are two use cases:&lt;/p&gt;

&lt;h3&gt;
  
  
  Blade templates
&lt;/h3&gt;

&lt;p&gt;We have a variable named &lt;code&gt;$dashboardMetrics&lt;/code&gt; that’s passed into our template for rendering. Here it is rendered:&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%2Fi%2Fky5rm4fclg2gvllne4yf.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%2Fi%2Fky5rm4fclg2gvllne4yf.png" alt="Dashboard on Aweder displaying the variable"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And, with a breakpoint set in the debugger, here is the payload printed out at the point it’s about to be loaded into the template:&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%2Fi%2Fas8g7p3ojnbwmtoiy0jg.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%2Fi%2Fas8g7p3ojnbwmtoiy0jg.png" alt="Breakpoint for debugging the variable"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, I’m going to change “Processing” to 999. Hitting the breakpoint again, I’ll use the console to set it:&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%2Fi%2Fx97eltkbeh1lo6sv4b5x.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%2Fi%2Fx97eltkbeh1lo6sv4b5x.png" alt="Console in PHPStorm changing the variable value"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the left hand side of the debugger pane you have the a “Resume Program” button. It allows you to complete the incoming request, so hit that and:&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%2Fi%2Fowm63ku9dhnpy98bp1q9.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%2Fi%2Fowm63ku9dhnpy98bp1q9.png" alt="Updated dashboard with modified data"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Request completed, you’ve modified runtime to change it.&lt;/p&gt;

&lt;h3&gt;
  
  
  API calls
&lt;/h3&gt;

&lt;p&gt;Exactly the same logic applies to changing the output of an API request. Here I’m using Postman to get an entity via. A UUID:&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%2Fi%2F8x8bpcya464g2ebr4l0d.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%2Fi%2F8x8bpcya464g2ebr4l0d.png" alt="Custom request in Postman"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using the same method as the browser request, we’ll put a breakpoint into the API method and modify the output. Here’s the method response:&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%2Fi%2Fhjpuxuim6qr1373rsx5z.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%2Fi%2Fhjpuxuim6qr1373rsx5z.png" alt="API response in codebase"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Protip for Laravel – don’t do this, always use Laravel Resources!)&lt;/p&gt;

&lt;p&gt;So, at the breakpoint let’s change the entity making the available_time now instead of the dummy date using the Carbon library:&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%2Fi%2Feq3f2tzjkrsgo7h2ycfo.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%2Fi%2Feq3f2tzjkrsgo7h2ycfo.png" alt="Console output after changing dates"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Resume runtime, and check out the result from Postman:&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%2Fi%2F9b1ynrr28hg5itdph6se.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%2Fi%2F9b1ynrr28hg5itdph6se.png" alt="Altered API response in Postman"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Magic.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I came into this with some thoughts and assumptions, so I’ll tie up my new experience with Xdebug in some key points that answer those questions.&lt;br&gt;
Conclusions&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Why use Xdebug when you can var_dump()?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A: Because it allows you to manipulate the runtime. If you use something like var_dump() you need to fire the CLI constantly or hit refresh on a browser over and over to get to the same point. Instead, you now have the chance to dynamically change and modify the stack – which is a big timesaver.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: You mentioned PsySh, why not use that?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A: Xdebug and PsySh are very different beasts. Whilst PsySh is labelled somewhat of a debugger, I don’t really treat it as such. It’s vital as a booted command line for your app, similar to manage.py for Django, but it’s not a pure debugger like Xdebug is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: This is still hard to set up still, isn’t it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A: I’d say it’s probably less of a mystery now that I’ve looked at it, and not as hard as most developers think. Plus the toolset for everyday use is so powerful, it’ll save you or your team a big chunk of valuable time and cognitive load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Are there downsides to using Xdebug?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A: The biggest downside I found was execution time. With the configuration in this article, the Xdebug server is always on – for a full PHPUnit test suite to run (if it’s pretty comprehensive) it will take a -big- performance hit. Luckily, there are workarounds for this in Docker, such as running commands with a custom ini to switch the Xdebug server off. If you’re in Production this is a real no-no.&lt;/p&gt;

&lt;p&gt;Overall, I’d say the tradeoff for time was well worth the effort. Something like this should be part of a developers’ tool chain – sure, it’s not always needed. If you’re doing an MVP in Laravel that’s mainly just CRUD operations, there’s probably not much justification for it.&lt;/p&gt;

&lt;p&gt;However, I’ve found that for many modern practises – comprehensive unit tests with large coverage from TDD, interface-based development and well-separated call stacks from considered single-responsibility principle controllers really do mean Xdebug gives you a decent edge.&lt;/p&gt;

&lt;p&gt;If you’re working on a legacy application in Zend Framework 2 or 10,000 line controllers in someone’s 2006 bespoke framework and you’re not using Xdebug, I’d come to the conclusion that you love the punishment, and like it that way, you massochist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What’s the outcome of trying it out?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A: Development with TDD and Xdebug felt incredibly empowering, so we’re going to look to make it part of the default development environment &amp;amp; process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How much does Xdebug cost?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A: It’s free. Although, it depends on what the definition of “free” is – as it’s Derick’s Open Source project, it costs vast amounts of personal development time. If you want to try it out from reading this article (or you want to try it out with a different platform – check &lt;a href="https://learnxdebug.com" rel="noopener noreferrer"&gt;https://learnxdebug.com&lt;/a&gt; for other tutorials) then considering supporting his work:&lt;br&gt;
&lt;a href="https://xdebug.org/support" rel="noopener noreferrer"&gt;https://xdebug.org/support&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy debugging!&lt;/p&gt;

</description>
      <category>php</category>
      <category>docker</category>
      <category>debugging</category>
    </item>
  </channel>
</rss>
