<?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: Omer van Kloeten</title>
    <description>The latest articles on DEV Community by Omer van Kloeten (@omervk).</description>
    <link>https://dev.to/omervk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3882%2F529d79ef-314e-4000-9760-9bf13b1a92a7.jpg</url>
      <title>DEV Community: Omer van Kloeten</title>
      <link>https://dev.to/omervk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/omervk"/>
    <language>en</language>
    <item>
      <title>Refactoring and Trust</title>
      <dc:creator>Omer van Kloeten</dc:creator>
      <pubDate>Thu, 05 Aug 2021 19:35:47 +0000</pubDate>
      <link>https://dev.to/omervk/refactoring-and-trust-282d</link>
      <guid>https://dev.to/omervk/refactoring-and-trust-282d</guid>
      <description>&lt;p&gt;Refactoring has many faces.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;When you start out,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;a fresh-faced developer, your only goal is to make your code Do The Thing. You forgot that semicolon or that loop was off-by-one and it took you the whole day to wade through those error messages to figure that stuff out and you’re on top of the world because you Fixed The Code and what do you mean change the code it WORKS NOW.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Some years pass,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;you’re now more confident in your work and start thinking about the patterns you start seeing emerge. You start practicing DRY and understanding the usefulness of design patterns. You’re slowly exposed to the practice of refactoring - changing the code’s structure without changing its external interfaces - extracting a method here, an interface there, moving methods up the hierarchy, … You’re no longer designing your code, you’re redesigning it as both you and it change.&lt;/p&gt;

&lt;p&gt;Most people do it out of either fun, pedantry or both. Fun, because you’re curious and it’s experience and the code just never quite looks right but the journey is interesting and you don’t have to worry about those pesky new product requirements while you’re fiddling around. Pedantry, because the two beasts of That’s Not The Way I Would Have Done It and It Must Be Done Right rear their heads. It’s Your Code and you can’t do anything until it’s Right. IT HAUNTS YOU!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O8YvgjEN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8fszhjp7hdz30xpvct60.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O8YvgjEN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8fszhjp7hdz30xpvct60.jpg" alt="It Haunts Us by CommitStrip"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(&lt;strong&gt;&lt;a href="https://www.commitstrip.com/en/2021/06/22/it-haunts-us/"&gt;It Haunts Us by CommitStrip&lt;/a&gt;&lt;/strong&gt;, the reason this blogpost was written in the first place)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Your Engineering Manager and your Product Manager? They just don’t understand you. They don’t understand that it NEEDS to happen. But you can FEEL it! They don’t own the code, they don’t write it, they don’t understand how terrible it is and how wonderful it would be once you’re done refactoring...&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Some more years pass,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;you’ve been programming for quite a bit of time now, and have been in a few teams, working on a few different projects and products. You no longer see the code you write as an artifact that could ever be complete. No, it’s all about forward motion and tradeoffs, what you can design relatively well and what you can’t, for now.&lt;/p&gt;

&lt;p&gt;This understanding helps you more easily explain why not refactoring would be detrimental to this forward motion. You’ve learned to stand your ground when you understand the returns outweigh the investment, but also to accept when it’s not the right time. Refactoring is still fun and you’re still just as pedantic as you were, but you’ve gained PERSPECTIVE.&lt;/p&gt;

&lt;p&gt;Your Engineering Manager and your Product Manager? Yeah, they still don’t understand refactoring. Their ears prick up when they hear that word. There’s always the next feature that needs to happen yesterday and the refactoring always takes a long time and I mean Those Pesky Developers Always Want To Refactor Everything. Oh, and worst of all, there’s never any result that can be measured. I mean, you can’t build the next feature, then go back to the old version of the code and build the feature again and show that it would have taken longer, right? Right? I meaaaaan… no, no, that’s just cutting off your nose to spite your face.&lt;/p&gt;

&lt;p&gt;There are lots of reasons for this mindset from EMs and PMs, but I’d like to propose one of them -&lt;/p&gt;

&lt;p&gt;Trust.&lt;/p&gt;

&lt;p&gt;Sure, they trust you to do your job, churning out features, hunting down bugs and handling outages, but do they trust you as a Professional? To them, a Professional would not waste time on frivolous activities, like tinkering with the code just to see if it looks nicer or changing it just because it Doesn’t Feel Right. But wait, that was you just a few years back. Oh crap, maybe that’s the kind of behavior that was imprinted on them by their past experience with developers? I mean, these Past Yous aren’t wrong - they’re just learning - like you did.&lt;/p&gt;

&lt;p&gt;How can you build that kind of trust? Well, that’s beyond the scope of this post. Maybe at a later time.&lt;/p&gt;

&lt;p&gt;One last thing - I don’t know if that’s the pain your specific EM and PM are feeling. It might be. You should probably ask them. It’s a great start.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Debugging Lua inside Openresty inside Docker with IntelliJ IDEA</title>
      <dc:creator>Omer van Kloeten</dc:creator>
      <pubDate>Mon, 31 May 2021 11:01:25 +0000</pubDate>
      <link>https://dev.to/omervk/debugging-lua-inside-openresty-inside-docker-with-intellij-idea-2h95</link>
      <guid>https://dev.to/omervk/debugging-lua-inside-openresty-inside-docker-with-intellij-idea-2h95</guid>
      <description>&lt;p&gt;I was challenged to find a way to step through some code. Usually I’d just fire up my IDE and start debugging, but this case was a bit more complicated than that. You see, this code is &lt;a href="http://www.lua.org/" rel="noopener noreferrer"&gt;Lua&lt;/a&gt; code, running inside a custom version of &lt;a href="https://www.nginx.com/" rel="noopener noreferrer"&gt;NGINX&lt;/a&gt; called &lt;a href="https://openresty.org/" rel="noopener noreferrer"&gt;Openresty&lt;/a&gt;, running inside a &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; container as part of a &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt; app. Oh, and I needed to step through it using IntelliJ IDEA.&lt;/p&gt;

&lt;p&gt;Can’t be too hard, right?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How do other people do it?&lt;/li&gt;
&lt;li&gt;Last thing’s first&lt;/li&gt;
&lt;li&gt;
The process

&lt;ul&gt;
&lt;li&gt;Starting out&lt;/li&gt;
&lt;li&gt;Bootstrapping the debugger&lt;/li&gt;
&lt;li&gt;The Local Dynamic Library&lt;/li&gt;
&lt;li&gt;Listening on localhost&lt;/li&gt;
&lt;li&gt;Let’s step!&lt;/li&gt;
&lt;li&gt;Matching sources&lt;/li&gt;
&lt;li&gt;Works on my machine&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Summing it all up

&lt;ul&gt;
&lt;li&gt;A word of warning&lt;/li&gt;
&lt;li&gt;What changed?&lt;/li&gt;
&lt;li&gt;Next steps&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Bonus: Hot reloading the Lua code&lt;/li&gt;

&lt;li&gt;Parting words&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  How do other people do it?
&lt;/h1&gt;

&lt;p&gt;I sat down and read a lot of material online and most of it boiled down to one of two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;a href="https://studio.zerobrane.com/" rel="noopener noreferrer"&gt;ZeroBrane Studio&lt;/a&gt;, an entirely different IDE with a debugger named &lt;a href="https://github.com/pkulchenko/MobDebug" rel="noopener noreferrer"&gt;mobdebug&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Print debugging to the logs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Neither one of those things were what I wanted to do, which got me thinking that, in order of likeliest to least:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Someone got it working but never documented it,&lt;/li&gt;
&lt;li&gt;It’s a terrible idea that I shouldn’t even consider trying, or;&lt;/li&gt;
&lt;li&gt;It’s never been done.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After a few days of work, I found the way to do it and the following is an explanation of how you could do it yourself.&lt;/p&gt;

&lt;h1&gt;
  
  
  Last thing’s first
&lt;/h1&gt;

&lt;p&gt;If you don’t really care about the journey and why these things actually work, you can jump over to Summing it all up and see the end result there.&lt;/p&gt;

&lt;h1&gt;
  
  
  The process
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Starting out
&lt;/h2&gt;

&lt;p&gt;I’m assuming that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You have IntelliJ IDEA.&lt;/li&gt;
&lt;li&gt;You have a working Docker Compose app with an Ubuntu-based Docker container named &lt;em&gt;nginx&lt;/em&gt; running Openresty with your custom Lua code that you want to debug.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fire up IntelliJ IDEA and install the &lt;a href="https://plugins.jetbrains.com/plugin/9768-emmylua" rel="noopener noreferrer"&gt;EmmyLua plugin for IntellIJ&lt;/a&gt;. Note that this is not the &lt;a href="https://plugins.jetbrains.com/plugin/5055-lua" rel="noopener noreferrer"&gt;Lua plugin&lt;/a&gt;, which I couldn’t get to work in the latest version of the IDE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bootstrapping the debugger
&lt;/h2&gt;

&lt;p&gt;To start debugging, you’ll have to create a new Debug configuration. Go to &lt;em&gt;Run → Edit Configurations...&lt;/em&gt; and add a new &lt;em&gt;Emmy Debugger&lt;/em&gt; config.&lt;/p&gt;

&lt;p&gt;Set Connection to &lt;em&gt;Tcp ( IDE connect debugger )&lt;/em&gt;, and Keep Host and Port as &lt;em&gt;localhost&lt;/em&gt; and &lt;em&gt;9966&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The dialog is kind enough to generate a snippet of code you can copy and paste to your Lua code to bootstrap the debugger in its context.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbh2d6j5slmxt5kihwt6x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbh2d6j5slmxt5kihwt6x.png" alt="Run/Debug Configurations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What &lt;em&gt;IDE connect debugger&lt;/em&gt; means is that the code will start listening on port 9966 for incoming connections, then block until the IDE attaches to it when we run this Debug configuration.&lt;/p&gt;

&lt;p&gt;Here’s the code I copied from that textbox verbatim:&lt;/p&gt;


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


&lt;p&gt;We’ll have to add this code to the file we’re debugging so that it can wait for the IDE to attach, after which we’ll theoretically be able to step through it, right?&lt;/p&gt;

&lt;p&gt;There are a few red flags here. Let’s break them down one by one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first line references a local file that is also a Mac-only &lt;code&gt;dylib&lt;/code&gt; (Dynamic Library) and we’ll be running a Linux-based container (which means we need an &lt;code&gt;so&lt;/code&gt; file - a Shared Object). We won’t be able to load that file.&lt;/li&gt;
&lt;li&gt;The debugger is listening on &lt;em&gt;localhost&lt;/em&gt;, but we’ll be inside a container.&lt;/li&gt;
&lt;li&gt;If we have multiple code paths that run this code one after the other, we’ll have errors since the port is a shared resource.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While the port contention (#3) can be solved with either closing the port quickly (using &lt;code&gt;dbg.stop()&lt;/code&gt;) or using a random port, the first two merit some more detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Local Dynamic Library
&lt;/h2&gt;

&lt;p&gt;We’ll need a local binary inside the container to load, and it has to be the right one.&lt;/p&gt;

&lt;p&gt;While Emmy releases Linux SO files for Emmy Core &lt;a href="https://github.com/EmmyLua/EmmyLuaDebugger/releases/tag/1.0.16" rel="noopener noreferrer"&gt;as part of their builds&lt;/a&gt;, they’re not necessarily compatible with whatever flavor of Linux your container will have. We’ll have to &lt;em&gt;build it from source&lt;/em&gt; as part of building the image:&lt;/p&gt;


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


&lt;p&gt;The above gets the latest released version of the source code (1.0.16 is the latest at the time this is written) and builds it according to the script in the repo’s &lt;a href="https://github.com/EmmyLua/EmmyLuaDebugger/blob/master/.travis.yml" rel="noopener noreferrer"&gt;.travis.yml file&lt;/a&gt; (lines 7-8). It then copies the SO file to the easily reachable /usr/local/emmy (lines 9-10) before removing the downloads (line 13).&lt;/p&gt;

&lt;p&gt;Like me, you might not be able to build it because you have an older version of CMake than is required. In that case, add the correct one before compiling the Emmy Debugger SO:&lt;/p&gt;


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


&lt;p&gt;Here we download the latest version of CMake 3 which is required to build Emmy Core (line 1), then build it from source (lines 5-7), remove the downloads (line 9) and update Ubuntu to use it instead of the default CMake (line 10).&lt;/p&gt;

&lt;p&gt;Back to the code we used to bootstrap the debugger:&lt;/p&gt;


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


&lt;p&gt;Let’s change line 1 to match the new Container-local Emmy Core:&lt;/p&gt;


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


&lt;h2&gt;
  
  
  Listening on localhost
&lt;/h2&gt;

&lt;p&gt;We told our code to bind to localhost on port 9966, but that doesn’t help us since we’re inside a Docker container. Let’s expose that port to the host computer so that it’s reachable.&lt;/p&gt;

&lt;p&gt;In your docker-compose.yaml, add the following lines 3-4:&lt;/p&gt;


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


&lt;p&gt;This exposes 9966 as a port local to the host machine. When the IDE opens a connection to it, that connection is proxied into the container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s step!
&lt;/h2&gt;

&lt;p&gt;After doing all of that, let’s give it a try! Let’s place a breakpoint after the &lt;code&gt;dbg.waitIDE()&lt;/code&gt; line, start our Docker Compose app, then call the endpoint that includes the code to debug and, as it waits for us to connect, run the Debug Configuration.&lt;/p&gt;

&lt;p&gt;That doesn’t work, though. The code waits for the debugger, the debugger successfully connects and then disconnects. Our breakpoint isn’t even hit!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejhgcthf6s4syothuwjp.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejhgcthf6s4syothuwjp.gif" alt="[1] debugging fails"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Matching sources
&lt;/h3&gt;

&lt;p&gt;The issue here is that when we place a breakpoint in the IDE in the file &lt;code&gt;/Users/omer_van_kloeten/my_project/src/lua/something.lua&lt;/code&gt;, the debugger will never stop there, because that path doesn’t exist in the container. Instead, this file will be somewhere like &lt;code&gt;/etc/nginx/lua/something.lua&lt;/code&gt;. How can we make that translation?&lt;/p&gt;

&lt;p&gt;I scoured the documentation, but found no API that could do that. Begrudgingly, I started trudging through the debugger’s source code and eventually found &lt;a href="https://github.com/EmmyLua/EmmyLuaDebugger/blob/3f8853897fe001250e6e8a80ace5b603b1caccd8/emmy_core/emmy_debugger.cpp#L428" rel="noopener noreferrer"&gt;a public API hook, with only a single line example&lt;/a&gt;. Was this the right API? I read through the sources and tried it and &lt;em&gt;it just worked&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;Here it is - this code should be placed before loading the debugger:&lt;/p&gt;


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


&lt;p&gt;The &lt;code&gt;fixPath&lt;/code&gt; function gets a file’s path and ‘fixes’ it to look like the paths the IDE expects.&lt;/p&gt;

&lt;p&gt;Looks like this will solve it. Let’s try again to place a breakpoint after the &lt;code&gt;dbg.waitIDE()&lt;/code&gt; line, start our Docker Compose app, then call the endpoint that includes the code to debug and, as it waits for us to connect, run the Debug Configuration.&lt;/p&gt;

&lt;p&gt;It works!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgb9qgiimyjw94ch8fgo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgb9qgiimyjw94ch8fgo.gif" alt="[2] debugging works"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Works on my machine
&lt;/h2&gt;

&lt;p&gt;This was exciting, but committing this kind of code would get me tarred and feathered. Let’s make sure this works on everyone’s machine. But how can we know, from inside a running container, where the host machine’s source code is located? Let’s use an environment variable.&lt;/p&gt;

&lt;p&gt;Let’s make a couple changes to the code above:&lt;/p&gt;


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


&lt;p&gt;First off, we added line 1, which fetches the environment variable. We’ve also changed line 4 to use the value from that environment variable.&lt;/p&gt;

&lt;p&gt;This means we’ll need to get the value &lt;code&gt;/Users/omer_van_kloeten/my_project/src&lt;/code&gt; into the variable.&lt;/p&gt;

&lt;p&gt;It’s not that trivial to get that environment variable into the code, because Nginx strips away almost all environment variables. We’ll have to whitelist it in nginx.conf:&lt;/p&gt;


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


&lt;p&gt;Now we’ll want to send it into the container at runtime. Inside docker-compose.yaml, let’s make sure our local environment variable is pushed to the container as a local environment variable:&lt;/p&gt;


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


&lt;p&gt;We’ve added the environment variable in line 4, but didn’t give it a value. That means it will pick up the value from the host environment when it’s started.&lt;/p&gt;

&lt;p&gt;Before we docker compose up our app, we’ll need to first export the environment variable:&lt;/p&gt;


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


&lt;p&gt;Stepping through the code will now work on all of our colleagues’ computers!&lt;/p&gt;

&lt;h1&gt;
  
  
  Summing it all up
&lt;/h1&gt;

&lt;h2&gt;
  
  
  A word of warning
&lt;/h2&gt;

&lt;p&gt;This guide covers only the first steps towards making robust debuggable code. You &lt;strong&gt;do not&lt;/strong&gt; want to ship your code with debugger binaries listening on a port for connections.&lt;/p&gt;

&lt;p&gt;This guide is far from comprehensive and doesn’t allude to being one-size-fits-all. I’d love to hear how you fixed issues with it in the comments. Come share your personal progress!&lt;/p&gt;

&lt;h3&gt;
  
  
  What changed?
&lt;/h3&gt;

&lt;p&gt;Here’s all of the changes we made to our code in easily copy-paste-able gist form:&lt;/p&gt;


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


&lt;h3&gt;
  
  
  Next steps
&lt;/h3&gt;

&lt;p&gt;This way of debugging means that the code waits for the debugger to connect to it, when it uses &lt;code&gt;tcpListen&lt;/code&gt;. However, this is not that great because it waits for user interaction (starting the Debug Configuration). If we used &lt;code&gt;tcpConnect&lt;/code&gt;, we would be able to start the debugger and have the process connect directly to it when it needs to, without user interaction. Unfortunately, I was unable to make that work within a reasonable timeframe when listening on &lt;code&gt;0.0.0.0&lt;/code&gt; and attempting to connect to &lt;code&gt;host.docker.internal&lt;/code&gt; from inside the Docker container. Perhaps you will.&lt;/p&gt;

&lt;h1&gt;
  
  
  Bonus: Hot reloading the Lua code
&lt;/h1&gt;

&lt;p&gt;A lot of the above included frequently changing Lua code and rebuilding the container, causing the feedback loop to be frustratingly long. If we can edit the files inside the container, that would make things much easier, right?&lt;/p&gt;

&lt;p&gt;To do that, let’s attach our sources as a volume to the container in docker-compose.yaml:&lt;/p&gt;


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


&lt;p&gt;In line 3 we’re effectively replacing the files that exist inside the container with a live link to our local ones.&lt;/p&gt;

&lt;p&gt;However, Openresty has a &lt;a href="https://openresty-reference.readthedocs.io/en/latest/Directives/#lua_code_cache" rel="noopener noreferrer"&gt;Lua code cache&lt;/a&gt; which will cache the code once it’s been run. Thankfully, we can turn that off in our nginx.conf:&lt;/p&gt;


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


&lt;p&gt;Unfortunately, this neat trick breaks the reproducibility of Docker images, so these patches to docker-compose.yaml and nginx.conf should never reach your CI server.&lt;/p&gt;

&lt;p&gt;Note that you may also break your code if you turn off the Lua cache, due to &lt;a href="https://openresty-reference.readthedocs.io/en/latest/Directives/#lua_code_cache" rel="noopener noreferrer"&gt;its side effects&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Parting words
&lt;/h1&gt;

&lt;p&gt;Please remember that this guide only outlines bootstrapping the ability to step inside the code, and therefore should probably not be used as-is. It was a fun challenge to take up and I sincerely hope that this guide is some day useful to someone other than myself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://twitter.com/omervk" rel="noopener noreferrer"&gt;Omer van Kloeten&lt;/a&gt; is a Principal Software Engineer at &lt;a href="https://forter.com" rel="noopener noreferrer"&gt;Forter&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>lua</category>
      <category>openresty</category>
      <category>nginx</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
