<?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>Forem: Tom Cools</title>
    <description>The latest articles on Forem by Tom Cools (@tomcools).</description>
    <link>https://forem.com/tomcools</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%2F330732%2F998836c3-68e3-4999-9642-bc442df31c1f.png</url>
      <title>Forem: Tom Cools</title>
      <link>https://forem.com/tomcools</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tomcools"/>
    <language>en</language>
    <item>
      <title>Playwright: Wordle, with no hands!</title>
      <dc:creator>Tom Cools</dc:creator>
      <pubDate>Sun, 16 Jan 2022 00:00:00 +0000</pubDate>
      <link>https://forem.com/tomcools/playwright-wordle-with-no-hands-2l45</link>
      <guid>https://forem.com/tomcools/playwright-wordle-with-no-hands-2l45</guid>
      <description>&lt;p&gt;Using Playwright to automatically play Wordle. I recently decided to give UI Automation another try live on Twitch. I’ve used Selenium in the past but that always felt like a hassle. So this time, I wanted to try out a new competitor on the scene of UI Automation Libraries: Playwright. And what better way to get a feel for a library then by using it in a fun project. As this is the point in time where the online game Wordle is immensely popuplar… why not try and automate that?&lt;/p&gt;

&lt;p&gt;See full article at: &lt;a href="https://www.tomcools.be/post/jan-2022-playwright-wordle/" rel="noopener noreferrer"&gt;https://www.tomcools.be/post/jan-2022-playwright-wordle/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Coffee 'Break' Conundrum</title>
      <dc:creator>Tom Cools</dc:creator>
      <pubDate>Sun, 16 Jan 2022 00:00:00 +0000</pubDate>
      <link>https://forem.com/tomcools/the-coffee-break-conundrum-ola</link>
      <guid>https://forem.com/tomcools/the-coffee-break-conundrum-ola</guid>
      <description>&lt;p&gt;I've been hearing a lot of similar stories lately. They usually go like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"Should I clock out of work if I take a small break? Technically I'm not being productive... so..."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"You are getting a lot of coffee... and then you just stand there looking out the window. We don't pay you for this."&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this blog, I won't talk about the regular Coffee Break Conundrums &lt;em&gt;(Black or with milk? What cookie should I eat with this? Should fake drinking out of an empty coffee cup be allowed on camera?&lt;/em&gt; @BillyKorando 🤔 &lt;em&gt;)&lt;/em&gt;.&lt;br&gt;
I want to spend some time reflecting and thinking out loud about the "break" part.&lt;br&gt;
Is a "coffee break" a break at all... and what arguments could be put forward to support the claim that "coffee breaks = work time"?&lt;/p&gt;

&lt;p&gt;Let's see where we end up with this!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This blog is reflection on something I've seen happen around me as a software consultant and through stories from fellow consultants. &lt;br&gt;
This is very much me thinking out loud and crystallizing my thoughts on this topic, usually a dangerous thing to do publicly on the internet.&lt;br&gt;
Not everything comes from my personal experience &lt;strong&gt;but&lt;/strong&gt; I've written this post from my perspective. &lt;br&gt;
&lt;strong&gt;If you think differently about this topic or if you feel I've missed something, please be so kind to point out my fallacies or biases in the comments. I'm here to learn.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  How we learn and solve problems
&lt;/h1&gt;

&lt;p&gt;Let's start with the idea that you are paid to solve problems. &lt;br&gt;
This seems like the most general description I could use to include as many of you, the readers of this post, as possible.&lt;br&gt;
You are all problem solvers... be it writing code to automate solutions, writing code to test that code or determining what should be built in the first place.&lt;/p&gt;

&lt;p&gt;As humans, we unfortunately have to rely on that thing inside our bodies called "our brain" to solve problems.&lt;br&gt;
The problem is, the brain is full of biases and tries to take shortcuts where it can... some shortcuts useful, some counterproductive.&lt;br&gt;
Our brain is sometimes erratic, weird and uncooperative. These rebellious acts of the brain happen more often for some of us (ex. &lt;em&gt;ADD/ADHD&lt;/em&gt;) than others (ex. &lt;em&gt;neurotypical&lt;/em&gt;), but they do impact us all.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Great books to read on this topic are "Thinking Fast and Slow" and "The Idiot Brain"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So lets first take a step back and look into how solving problems (and learning) actually manifests itself.&lt;br&gt;
As presented in one of the first chapters of the magnificent ("can't believe this stuff is FREE"-level) course &lt;a href="https://www.coursera.org/learn/learning-how-to-learn" rel="noopener noreferrer"&gt;Learning to Learn&lt;/a&gt; our brain operates in 2 modes: &lt;em&gt;Focused&lt;/em&gt; and &lt;em&gt;Diffuse&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I'll be listing only an extremely simplified explanation of the two modes here... for more detail, &lt;a href="https://www.brainscape.com/academy/focused-vs-diffuse-thinking-learning/" rel="noopener noreferrer"&gt;look at this blog post.&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Focused mode&lt;/em&gt; is single track. You experience this mode of thinking when you are working on a task and everything around you seems to fade away into the background;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Diffuse mode&lt;/em&gt; is all over the place and allows you to look at the broader picture. You are not focussed on 1 thing but let your mind wander;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ever had a really though problem you spent hours on, only to solve it in a couple of minutes the next day or after a visit to the bathroom?&lt;br&gt;
That phenomenon, which is almost a meme / cliché in our industry, can be attributed to the &lt;em&gt;diffuse mode&lt;/em&gt; of thinking.&lt;br&gt;
By letting your mind wander, you give it the necessary room to form important connections, see the bigger picture again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.tomcools.be%2Fpost%2Foct-2021-coffee-breaks%2Fcoffee.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.tomcools.be%2Fpost%2Foct-2021-coffee-breaks%2Fcoffee.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is enough research out there from people much smarter than me to confirm that &lt;em&gt;focused and diffuse modes&lt;/em&gt; are a real thing, so let's continue our story with the reasonable assumption the theory is valid.&lt;/p&gt;

&lt;h1&gt;
  
  
  Efficieny: Focussed vs Diffuse thinking
&lt;/h1&gt;

&lt;p&gt;When looking at the work place, usually a place where we need to find solutions for problems, you really need both &lt;em&gt;diffuse and focused modes&lt;/em&gt; of thinking.&lt;br&gt;
Sometimes you want to be in "in the zone", focused on implementing that feature which is described in your user story.&lt;/p&gt;

&lt;p&gt;If you run into a problem however, chances are your brain is now fixated on the solution you had in your head... and it's really hard to pull yourself away from it.&lt;br&gt;
That's the moment where you can benefit if you succeed in switching your brain into the &lt;em&gt;diffuse mode&lt;/em&gt;, taking a step back, see the bigger picture and try to figure out some alternative solution.&lt;/p&gt;

&lt;p&gt;Unfortunately, there is no easy switch hidden somewhere on your head to flip between these two modes.&lt;br&gt;
What is know however, is that diffuse thinking usually occurs when you do &lt;em&gt;other things&lt;/em&gt;. Take a shower, go for a walk or go grab some coffee.&lt;br&gt;
Looking at it this way, taking a break is a way to get your brain to switch to &lt;em&gt;diffuse mode&lt;/em&gt;... which would make &lt;strong&gt;taking breaks an integral and important part of solving problems&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;Given all this information, isn't it weird then that so many managers only consider you "at work" when you are in &lt;em&gt;focused mode&lt;/em&gt; behind your desk?&lt;br&gt;
Isn't it strange that coffee breaks or just walking around the office to give your brain a rest is considered &lt;em&gt;lazy &amp;amp; unproductive&lt;/em&gt;?&lt;br&gt;
What is happening here?&lt;/p&gt;

&lt;p&gt;One explanation could be it's an &lt;strong&gt;availability/measurement bias&lt;/strong&gt;: It's easy to measure the amount of time you sit behind your desk.&lt;br&gt;
Measuring the value of your &lt;em&gt;diffuse thinking&lt;/em&gt; is much harder, but it might be much higher than you anticipate!&lt;br&gt;
I've personally saved companies hours (if not weeks or months) of work by stepping back and shutting down the &lt;em&gt;focused mode&lt;/em&gt; for a short while.&lt;br&gt;
Some things that happened when I was activating my &lt;em&gt;diffuse mode&lt;/em&gt;, aka taking a breather:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;I realized some features on our backlog are unnecessary or could be built in an easier way;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Realized what a potential solution could be for a problem I'd been struggling with;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Remembered a collegue who had a similar project, contacted them, found better solution than the one I had in mind;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Measuring work efficiency is a hard task.&lt;/em&gt; If you read my experiences above, you know those actions saved a ton of time and money.&lt;br&gt;
However, that saved time will never make it on a sprint report, burndown chart or work log... and unless I specifically mention it to my manager, chances are they'll never know.&lt;/p&gt;

&lt;h1&gt;
  
  
  Should I be paid if I figure out a problem in my sleep?
&lt;/h1&gt;

&lt;p&gt;The content of this post so far could be used as an argument that companies should pay you for your &lt;em&gt;diffuse thinking time&lt;/em&gt; as well as your &lt;em&gt;focused time&lt;/em&gt;.&lt;br&gt;
I believe this to be true on a certain level but let's refine that idea (&lt;em&gt;being paid for diffuse thinking time&lt;/em&gt;) for a second and look at what that might mean.&lt;br&gt;
If we ask to be paid for our diffuse thinking as well... what would that say about &lt;strong&gt;overtime&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.tomcools.be%2Fpost%2Foct-2021-coffee-breaks%2Ftime.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.tomcools.be%2Fpost%2Foct-2021-coffee-breaks%2Ftime.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The trope mentioned earlier &lt;em&gt;("I went home, slept on it, and now I have a solution")&lt;/em&gt; implies you did some &lt;em&gt;diffuse thinking&lt;/em&gt; at home which benefited your company.&lt;br&gt;
Should you get paid for that as well? Where does the working day stop in this case? For hourly workers: How long did your &lt;em&gt;diffuse thinking&lt;/em&gt; take to come up with that solution? &lt;br&gt;
As you might imagine, trying to quantify &lt;em&gt;diffuse thinking time&lt;/em&gt; would lead to an organisational nightmare.  So what can we do?&lt;/p&gt;

&lt;p&gt;If we believe the research on this topic, both &lt;strong&gt;&lt;em&gt;focused and diffuse thinking&lt;/em&gt; are needed to solve problems&lt;/strong&gt;.&lt;br&gt;
This certainly makes a case that it might be beneficial to &lt;strong&gt;allow room for &lt;em&gt;diffuse thinking&lt;/em&gt; during the regular workday&lt;/strong&gt;.&lt;br&gt;
Consider the following two scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Person X can solve a problem in 3 hours but they took a 30 minute walk to let their brain wander;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Person X can solve the problem, struggling 5 hours, focussed on their screen, then goes home to "sleep on it" to only solve it the next day;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which situation was more productive? What instance is going to be more taxing on the employee?&lt;br&gt;
When was the most value provided to the company?&lt;br&gt;
The answer seems clear.&lt;/p&gt;

&lt;h1&gt;
  
  
  What are you being paid for?
&lt;/h1&gt;

&lt;p&gt;It's important to note that I'm not advocating employees should be allowed to just walk about the whole day, every day.&lt;br&gt;
&lt;em&gt;The economic reality is that in order to get paid, you need to provided value, either to your company or directly to your customers.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You are being paid to be as productive as you are able to be. &lt;br&gt;
As a professional you should do whatever you think is necessary... even if what you think is needed is to take a break.&lt;br&gt;
As I've talked about in this post, taking breaks is important to let your brain switch gears.&lt;/p&gt;

&lt;p&gt;So if you need one, take one and remember, &lt;em&gt;you can't spell "breakthrough" without "break"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.tomcools.be%2Fpost%2Foct-2021-coffee-breaks%2Fbridge.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.tomcools.be%2Fpost%2Foct-2021-coffee-breaks%2Fbridge.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I am fully aware I leave a lot of open discussion space with this blog and if I triggered a response within you, please leave a comment! There are a lot of things I don't have an answer for.&lt;/p&gt;

&lt;p&gt;If you need a lot more breaks to get the job done than your colleague, that might be a bad look but should it be?&lt;br&gt;
There is a lot to be said about the value of neurodiverse teams, something I will be exploring next as I don't know enough about neurodiversity to see how this discussion is appropriate for the many ways in which people can be different.&lt;/p&gt;

&lt;p&gt;I also realize I'm in a situation and profession where taking a break is not really frowned upon that much but it's still interesting to think about this topic.&lt;br&gt;
If your company has a policy for this, please drop a comment! I want to learn how to think about this absorbing as many perspectives as possible.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
    </item>
    <item>
      <title>Getting through the Q&amp;A section of your presentation</title>
      <dc:creator>Tom Cools</dc:creator>
      <pubDate>Sun, 24 May 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/tomcools/getting-through-the-q-a-section-of-your-presentation-2o6m</link>
      <guid>https://forem.com/tomcools/getting-through-the-q-a-section-of-your-presentation-2o6m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This post was written from a white-cis-male perspective. If anything in this post doesn't match your previous experiences with Q&amp;amp;A, please leave a comment! I would like to know what kind of hardships my priviledge has spared me from. &amp;lt;3 to all of you!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine being at a conference or meetup giving a talk. You completely ace it (&lt;em&gt;I believe you will, even if you don't, you badass!&lt;/em&gt;) but then you feel anxiety setting in. You can feel it coming for you, slowly, surely: the end of your talk. Which means... &lt;strong&gt;it's time for Q&amp;amp;A&lt;/strong&gt;: Questions and (hopefully) your Answers.&lt;/p&gt;

&lt;p&gt;Q&amp;amp;A is the most dreaded part of a presentation for some while being indispensable for others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's talk about that.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  It's not 1 vs N
&lt;/h2&gt;

&lt;p&gt;Let's discuss the "fear" part of the Q&amp;amp;A first because let's not deny it, it can be quite daunting.&lt;/p&gt;

&lt;p&gt;Sometimes it makes you feel like you are in the middle of a technical interview. Instead of one interviewer, you have ... an audience. Maybe 10 people, maybe 50, maybe way more than that. The chances are, there is someone in the audience who knows way more about the topic than you do. Maybe the person who wrote THE book on Java is in your audience while you are giving a Java talk. Now that is scary.&lt;/p&gt;

&lt;p&gt;And yet, &lt;strong&gt;all of that does not matter&lt;/strong&gt;. Because it is not a technical interview. Your Q&amp;amp;A is not a place where people will ask you questions to bring you down a notch. &lt;/p&gt;

&lt;p&gt;Here is the truth about Q&amp;amp;A (and your entire talk in general): &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your audience wants you to succeed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Q&amp;amp;A is not a "1 vs All" proposition, it's a collaborative moment. That person who knows more about the topic than you do... no matter how scary their presence may seem to you at first, &lt;br&gt;
they might be the ones to jump in and help you answer those questions. Just be sure to thank them for their help afterwards.&lt;/p&gt;
&lt;h2&gt;
  
  
  The biggest mistake in Q&amp;amp;A
&lt;/h2&gt;

&lt;p&gt;It is normal to not know the answer to every question. Don't let that distract you. Don't let it get to you! You are still the presenter! You know enough about that topic to be there! &lt;/p&gt;

&lt;p&gt;There is only one thing you should never do:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never pretend to know the answer when you don't&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I see people struggling with this. Some get so caught up in the idea that they are supposed to be "ultimate master experts" they have trouble handling the &lt;em&gt;perceived emberrasment&lt;/em&gt; of not knowing the answer to a question. So they start inventing answers, to keep up appearances. Problem is: &lt;em&gt;People know&lt;/em&gt;. Your audience can sense that you are making stuff up from a mile away. Especially people who have more knowledge on the topic than you do.&lt;/p&gt;

&lt;p&gt;There is only one thing you can answer in this situation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"I'm sorry, I don't know the answer to that question..."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, people expect you to be able to answer basic questions but if you have prepared a talk on something, you &lt;em&gt;will&lt;/em&gt; be able to answer those questions.&lt;br&gt;
So it's actually pretty straightforward: either you know, or you admit you don't know. There is no shame in any of those two outcomes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Q&amp;amp;A beyond your talk
&lt;/h2&gt;

&lt;p&gt;Having been to quite some conferences now, I have noticed that the Q&amp;amp;A is often my favorite part. It gives me the opportunity to ask questions to people who know a lot more about the topic than I do. Even if I have no questions myself, I will often just sit there and listen to the questions other people come up with. &lt;/p&gt;

&lt;p&gt;Don't forget: You have a room filled with people, each with a slightly different background and perspective. You'll notice that often one of them ask a question that will make you think: &lt;em&gt;"Oh... never even considered that."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jEiVEner--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tomcools.be/post/may-2020-do-a-qanda/q%26a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jEiVEner--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tomcools.be/post/may-2020-do-a-qanda/q%26a.jpg" alt="Q&amp;amp;A"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Despite the Q&amp;amp;A being a great moment of opportunity and collaboration, most speakers only share 2 things: Code and Slides. While you should be grateful they are willing to share their hard work, the Q&amp;amp;A part of the talk often gets lost to history. This can be extra frustrating for members of the audience who asked a question that was left unanswered.&lt;/p&gt;

&lt;p&gt;When I started doing talks, I decided I wanted to do it differently. &lt;strong&gt;That is why, for every talk I give, I create a page containing, Slides, Code and the Q&amp;amp;A.&lt;/strong&gt; &lt;a href="https://tomcools.be/talks/fallacies-jvmcon/"&gt;See this example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This allows me to take whatever great interactions I had during the talk and bring it, at least partially, online for everyone to see.&lt;br&gt;
I can't recommend this enough! It has so many great side effects.&lt;/p&gt;

&lt;p&gt;First of all, it enables you to say: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"I'm sorry, I don't know the answer to that question but I will figure it out for you!&lt;/strong&gt;".&lt;/p&gt;

&lt;p&gt;By posting the Q&amp;amp;A online, you're effectively extending it beyond your timeslot. This gives you the time to figure out answers to the questions you couldn't answer during the talk. That way, you are still helping your audience, which is what this is all about! &lt;/p&gt;

&lt;p&gt;Secondly it also greatly benefits yourself! By keeping track of all the questions people have asked and answering them, &lt;strong&gt;you are effectively creating an amazing resource of information&lt;/strong&gt;. Questions that are asked frequently are a nice indicator that your presentation is missing some content. Knowing what is missing, you can add that information to your slides to make your talk even more awesome!&lt;/p&gt;

&lt;p&gt;After giving a talk a couple of times, I notice I often open my own website and go to a Q&amp;amp;A page of a previous talk and I use that content to answer questions. That's not bad presenting, that's giving your audience the content they are looking for.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This entire post originated because of a tweet by Angie Jones (a fellow badass!). In the tweet, she talks about being unable to answer some questions and how she handled it by researching the questions and writing a blog post about the answers.&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--X0wjKgHC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1141742921240104961/ylpMiYrr_normal.jpg" alt="Angie Jones profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Angie Jones
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="comment-mentioned-user" href="https://dev.to/techgirl1908"&gt;@techgirl1908&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--52oNvK_0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-ff4bdab814039c4cb172a35ea369e0ea9c6a4b59b631a293896ae195fa26a99d.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Many speakers are hesitant to do Q&amp;amp;A bc it takes you out of your comfort zone&lt;br&gt;&lt;br&gt;During Q&amp;amp;A for my last talk, I gave educated guesses for many Qs bc I just didn't know&lt;br&gt;&lt;br&gt;After, I took those questions, researched (while live) &amp;amp; made it a blog post&lt;br&gt;&lt;br&gt;So, new content! &lt;a href="https://twitter.com/hashtag/LemonsToLemonade"&gt;#LemonsToLemonade&lt;/a&gt; &lt;a href="https://t.co/xS2UWarDTT"&gt;twitter.com/techgirl1908/s…&lt;/a&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      21:40 PM - 21 May 2020
    &lt;/div&gt;

      &lt;div class="ltag__twitter-tweet__quote"&gt;
        &lt;div class="ltag__twitter-tweet__quote__header"&gt;
          &lt;span class="ltag__twitter-tweet__quote__header__name"&gt;
            Angie Jones
          &lt;/span&gt;
          &lt;a class="comment-mentioned-user" href="https://dev.to/techgirl1908"&gt;@techgirl1908&lt;/a&gt;

        &lt;/div&gt;
        Angie Jones - live via https://t.co/kmDTWCFaxf https://t.co/Xh1zQWUZ49
      &lt;/div&gt;

    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1263585455439634432" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-reply-action.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1263585455439634432" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-retweet-action.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      20
      &lt;a href="https://twitter.com/intent/like?tweet_id=1263585455439634432" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-like-action.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
      121
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;It made me realize that I had been doing exactly the same thing for a while but never talked about it, assuming more people were already doing it anyway.&lt;br&gt;
Turns out I was wrong. I should have been advocating for sharing Q&amp;amp;A's online and following up on unanswered questions a bit more.&lt;/p&gt;

&lt;p&gt;With that at least partially corrected now by posting this, &lt;strong&gt;I hope to see more content out there. Not because a presenter succeeded in answering questions but because they failed and handled it with grace.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>qa</category>
      <category>presentations</category>
    </item>
    <item>
      <title>Great stuff is Loom-ing on the Horizon for Java</title>
      <dc:creator>Tom Cools</dc:creator>
      <pubDate>Thu, 21 May 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/tomcools/great-stuff-is-loom-ing-on-the-horizon-for-java-33h0</link>
      <guid>https://forem.com/tomcools/great-stuff-is-loom-ing-on-the-horizon-for-java-33h0</guid>
      <description>&lt;p&gt;Almost two years ago now, I was at Oracle Code One in San Francisco. It was there that I first heard about Project Loom, a project that would introduce some kind of new way to do concurreny in Java. At that point, Loom was just a concept, a promise to make concurrency in Java easier. &lt;/p&gt;

&lt;p&gt;Fast forward to today and Loom has changed quite a bit since that initial presentation. The time to catch up with Project Loom.&lt;/p&gt;

&lt;h2&gt;
  
  
  Old choices sometimes hurt in Java
&lt;/h2&gt;

&lt;p&gt;Ever since Java 1.0 we've had the &lt;a href="https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/Thread.html"&gt;Thread&lt;/a&gt; class. This class is a representation of an OS resource, namely an OS thread.&lt;br&gt;
OS threads are limited to a couple thousand at a time. This wasn't much of a problem 25 years ago. It is however a huge problem now, where some applications need to handle tens of thousands of requests (or more) at the same time. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;By linking what can be done concurrently in Java to OS Threads, Java has extremely limited it's own scalability.&lt;/strong&gt;&lt;br&gt;
To add to the problem: Threads are costly to make. Just creating them for a single run and disposing them again isn't viable.&lt;br&gt;
This is why we have started using Thread Pools, groups of re-usable threads we keep alive in our applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The real problems begin when we have to block a thread&lt;/strong&gt;. This happens whenever we do an API call, connect to a database or read from a file.&lt;br&gt;
At those moments, our thread isn't doing anything. &lt;strong&gt;It is just "waiting"&lt;/strong&gt; for something. As threads are costly AND limited, this becomes a serious bottleneck if we want to get the most out of our hardware.&lt;/p&gt;
&lt;h2&gt;
  
  
  Loom to the rescue
&lt;/h2&gt;

&lt;p&gt;So what is Project Loom going to bring us? &lt;/p&gt;
&lt;h3&gt;
  
  
  Backwards compatibility
&lt;/h3&gt;

&lt;p&gt;When Loom was first introduced, we were also introduced to the concept of &lt;strong&gt;Fibers&lt;/strong&gt;, a new concept that was dubbed "Threads revisited". This sparked a bit of controversy in the Java Community, as worries grew about replacing &lt;em&gt;Thread.class&lt;/em&gt; everywhere by &lt;em&gt;Fiber.class&lt;/em&gt;, which would require a lot of code to be changed. As the project went on the Java team realized that if it looked like a thread, and worked like a thread, then maybe it should just be Thread!&lt;/p&gt;

&lt;p&gt;That's what they did. Instead of creating a totally new concept, Loom introduces us to &lt;strong&gt;Virtual Threads&lt;/strong&gt;.&lt;br&gt;
Unlike the current &lt;a href="https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/Thread.html"&gt;Thread&lt;/a&gt; implementation, virtual threads are no longer a one-on-one mapping to OS threads. Instead, virtual threads are a concept managed by the JVM. This means we no longer have to worry about them as much as we had to in the past.&lt;/p&gt;

&lt;p&gt;Here is a basic example on how to run something on a virtual thread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startVirtualThread&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Do something in a Virtual Thread&lt;/span&gt;
    &lt;span class="o"&gt;});&lt;/span&gt;

    &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;virtual&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Do something in a Virtual Thread&lt;/span&gt;
    &lt;span class="o"&gt;}).&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you think that code looks awfully familiar you are absolutly correct. &lt;br&gt;
By keeping the current name and class, &lt;strong&gt;we can effectively keep all our code and our tools the same!&lt;/strong&gt;&lt;br&gt;
While some libraries will need to change to make use of virtual threads, the impact of that change is extremely limited.&lt;br&gt;
When using the &lt;strong&gt;ExecutorServices&lt;/strong&gt;, &lt;em&gt;which you should be doing anyway&lt;/em&gt;, chances are all that needs to be changed is the implementation of the Executor!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// Classic fixed thread pool&lt;/span&gt;
    &lt;span class="nc"&gt;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFixedThreadPool&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Threadpool with unlimited virtual threads&lt;/span&gt;
    &lt;span class="nc"&gt;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newUnboundedVirtualThreadExecutor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;So hardly any change in code required to switch to Virtual Threads! That's the kind of backwards compatibility we've grown to love (and expect) from our favorite programming language!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Unlimited (virtual) threads :o
&lt;/h2&gt;

&lt;p&gt;In case you are wondering, you did read that previous code example correctly: "newUNBOUNDEDVirtualThreadExecutor". Unbounded means "a lot!", but how does that translate to OS Threads? Well, to reiterate: Unlike the current &lt;a href="https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/Thread.html"&gt;Thread&lt;/a&gt; implementation, virtual threads are no longer a one-on-one mapping to OS threads. The JVM does the heavy lifting of making sure our virtual threads eventually run on actual OS threads. &lt;/p&gt;

&lt;p&gt;So, if virtual threads are a concept in the JVM... how many can we run at the same time? &lt;br&gt;
According to the &lt;a href="https://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part1.html"&gt;"State of Loom" post by Ron Pressler (May 2020)&lt;/a&gt;: &lt;strong&gt;Millions!&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nzDi2B5w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pseyo9at22moph0pp1xh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nzDi2B5w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pseyo9at22moph0pp1xh.jpg" alt="Under high load, we will see the true power of Loom."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because these virtual threads are cheap to create, there is no real need for pooling anymore. With Loom, we are entering a world where we will be creating a (virtual) thread for a single action and then just disposing it again. In fact, the &lt;strong&gt;UnboundedVirtualThreadExecutor&lt;/strong&gt; above does exactly that! Whenever you use it, you get a shiny new virtual thread which will be destroyed once it's done with its task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blocking code is no longer an issue
&lt;/h2&gt;

&lt;p&gt;In recent years we saw the rise of frameworks who claim to have bypassed the restrictions of the Java Concurrency model. These "non blocking" frameworks have seen quite some success, Vert.x being the one I personally fell in love with. The main idea behind them was often to write code in such a way that only a limited amount of Threads would be blocked at the same time. This left other threads to be continuously busy. Those threads are never blocked leading to greater overall performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Those benefits, like everything in life, came at a cost&lt;/strong&gt;. Quite often those frameworks required a different programming style, something a lot of programmers (including myself) struggled with. Whenever I do reactive programming, I feel like I'm no longer programming Java. It has always felt alienating to me. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With Project Loom we might no longer need reactive, non-blocking programming&lt;/strong&gt; as it is known today.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In plain terms reactive programming is about non-blocking applications that are asynchronous and event-driven and &lt;strong&gt;require a small number of threads to scale&lt;/strong&gt;. - docs.spring.io&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because we can create MILLIONS of virtual threads, each of which can be used for a single action, &lt;strong&gt;the cost of blocking a virtual thread is close to zero!&lt;/strong&gt;&lt;br&gt;
With that cost gone... &lt;strong&gt;imagine the possibilities&lt;/strong&gt;! We can write synchronous/blocking code, without having the decrease in performance or scalability. That seemed impossible just a few years ago, yet now with Project Loom it's becoming reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;When Project Loom is completed and finds it's permanent spot in the JDK, it'll change how we look at building high-performant Java applications forever.&lt;br&gt;
Removing the cost of blocking threads while still being backwards compatible is a masterpiece of engineering by the project team. &lt;/p&gt;

&lt;p&gt;I have been trying out the Early Access build and was just baffled by how intuitive the API feels. &lt;strong&gt;This is my new #1 of amazing things to come for Java!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In short: "Project Loom allows Java to once again become the Java we fell in love with: boring but highly performant &amp;lt;3."&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Addendum:
&lt;/h2&gt;

&lt;p&gt;Try yourself! &lt;a href="https://jdk.java.net/loom/"&gt;Download the Early Access Build&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Read more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part1.html"&gt;State of Loom&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part2.html"&gt;State of Loom: Part 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>projectloom</category>
      <category>jdk</category>
    </item>
    <item>
      <title>Building a Twitch Chat Integrated Game</title>
      <dc:creator>Tom Cools</dc:creator>
      <pubDate>Mon, 27 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/tomcools/building-a-twitch-chat-integrated-game-1l0j</link>
      <guid>https://forem.com/tomcools/building-a-twitch-chat-integrated-game-1l0j</guid>
      <description>&lt;p&gt;Being in Corona isolation, I have been watching some Twitch streams and was wondering if it would be something I'd like to do as well.&lt;br&gt;
I love teaching and since we're all pretty much stuck in our homes, maybe I should give it a shot.&lt;br&gt;
It could be kind of like giving a talk at a conference only more limited in interaction... but that's what I love most about teaching...interaction.&lt;/p&gt;

&lt;p&gt;So, maybe Twitch just isn't for me... unless...&lt;br&gt;
&lt;em&gt;What if I could do something to make Twitch a more interactive place?&lt;/em&gt;&lt;br&gt;
&lt;em&gt;What if I could somehow create something streamers could use to entertain their viewers in a more interactive way?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time to build something Twitchy!&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Requirements
&lt;/h2&gt;

&lt;p&gt;To keep myself focused, here are the guidelines I set for myself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The bar of entry should be low;&lt;/li&gt;
&lt;li&gt;The owner of the stream needs to have control;&lt;/li&gt;
&lt;li&gt;Whatever I make should not draw attention away from the stream, it should be the stream;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These requirements pushed me towards the following preliminary design:&lt;/p&gt;

&lt;p&gt;IMG&lt;/p&gt;

&lt;p&gt;To keep the bar of entry low, I'm going to create some kind of web-based game.&lt;br&gt;
Making it in Javascript/HTML makes it more accessible, since all users would need is a browser.&lt;br&gt;
I've had some &lt;a href="https://www.tomcools.be/post/feb-2020-plushy-game-1" rel="noopener noreferrer"&gt;previous experience with p5.js&lt;/a&gt;, so I'm going to use that again for this project.&lt;/p&gt;

&lt;p&gt;All I needed to do then was find a way to integrate with Twitch... somehow.&lt;/p&gt;
&lt;h2&gt;
  
  
  Read the chat!
&lt;/h2&gt;

&lt;p&gt;Scouting around on some Twitch streams, I quickly noticed that &lt;strong&gt;the way most Twich users interact with the streamer is through the chat&lt;/strong&gt;.&lt;br&gt;
If that is the common way of doing things, I'm not going to fight that. I'm going to embrace it.&lt;/p&gt;

&lt;p&gt;So now I just need to integrate with the Twitch Chat and use that as input for whatever I'm making.&lt;br&gt;
I was a bit worried this might be a difficult task. I really didn't want to use some screen-scraping tooling or whatnot to get the chat messages.&lt;br&gt;
Those feelings quickly went away when I learned the good news:&lt;/p&gt;

&lt;center&gt;&lt;h2&gt;Twitch uses IRC!&lt;/h2&gt;&lt;/center&gt;

&lt;blockquote&gt;
&lt;p&gt;For those of you who might not know this...&lt;a href="https://tools.ietf.org/html/rfc1459" rel="noopener noreferrer"&gt;IRC, or Internet Relay Chat,&lt;/a&gt; is an Application Layer Protocol built on TCP.&lt;br&gt;
It's a fairly simple text based protocol which has been around for 30 years now and is still used today.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nice! Since IRC is so common, I only had to find a way to connect my front-end to the IRC chat and we are good to go.&lt;br&gt;
&lt;strong&gt;And that is kind of where my original plan fell apart.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You see, IRC uses TCP. Javascript, at least the sort of Javascript running in the browser, can't make regular TCP socket connections.&lt;br&gt;
This may sound surprising with the popularity of WebSockets. &lt;br&gt;
WebSockets however always start out as a HTTP request and get "upgraded" to TCP.&lt;br&gt;
WebSockets are a separate application layer protocol, just like IRC is an application layer protocol. &lt;br&gt;
Unfortunately, they do not magically play well together.&lt;/p&gt;

&lt;p&gt;So...back to the drawing board!&lt;/p&gt;
&lt;h2&gt;
  
  
  The Java IRC Client
&lt;/h2&gt;

&lt;p&gt;It seems like I had no other choice than to put a custom Backend between my Frontend and the Twitch Chat.&lt;br&gt;
I chose for a Spring Boot application, &lt;em&gt;always good to keep some familiar technologies close when you are building something unfamiliar.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;IMG&lt;/p&gt;

&lt;p&gt;To connect to the Twitch IRC, I decided to use the &lt;a href="https://github.com/pircbotx/pircbotx" rel="noopener noreferrer"&gt;PircBotX&lt;/a&gt; library.&lt;br&gt;
I'm not going to duplicate their documentation... but I will show you what settings I used to connect to Twitch.&lt;/p&gt;

&lt;p&gt;First off, you'll need a Twitch account and get an Access Token for your application.&lt;br&gt;
&lt;a href="https://twitchapps.com/tmi/" rel="noopener noreferrer"&gt;This website will give you one if you log in.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, you need to setup &lt;a href="https://github.com/pircbotx/pircbotx" rel="noopener noreferrer"&gt;PircBotX&lt;/a&gt; to use the correct configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;authToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"oauth:YOUR_TOKEN"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Your oauth password from http://twitchapps.com/tmi&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"#tomcools"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// The IRC channel name = Twitch Channel name&lt;/span&gt;
    &lt;span class="nc"&gt;Listener&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;PIRCBOT&lt;/span&gt; &lt;span class="nc"&gt;Listener&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// Extend the ListenerAdapter Class&lt;/span&gt;

    &lt;span class="nc"&gt;Configuration&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Configuration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAutoNickChange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//Twitch doesn't support multiple users&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setOnJoinWhoEnabled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//Twitch doesn't support WHO command&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCapEnabled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addCapHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EnableCapHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"twitch.tv/tags"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="c1"&gt;// Twitch by default doesn't send JOIN, PART, and NAMES unless you request it, &lt;/span&gt;
            &lt;span class="c1"&gt;// see https://dev.twitch.tv/docs/irc/guide/#twitch-irc-capabilities&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addCapHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EnableCapHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"twitch.tv/membership"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addServer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"irc.twitch.tv"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setServerPassword&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authToken&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addAutoJoinChannel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//Some twitch channel ex. #tomcools&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;buildConfiguration&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;bot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PircBotX&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startBot&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Next we need to add a Listener which will be called whenever a new message arrives on the IRC channel.&lt;br&gt;
&lt;strong&gt;There is a convenient abstract class you can inherit&lt;/strong&gt;. You only need to override the methods you actually want to use.&lt;br&gt;
In our case, we're interested receiving messages and some feedback on connect/disconnect events.&lt;br&gt;
&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TwitchIrcChatListener&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ListenerAdapter&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ChatMessageListener&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;TwitchIrcChatListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ChatMessageListener&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onGenericMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GenericMessageEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onChatMessageReceived&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ChatMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUser&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getNick&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onConnect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConnectEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onConnect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onConnect&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onDisconnect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DisconnectEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onDisconnect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onDisconnect&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;As you can see, I provided a &lt;em&gt;ChatMessageListener&lt;/em&gt; in the constructor and all I do is pass the message on to this listener. &lt;br&gt;
The definition of that interface is pretty simple.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ChatMessageListener&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onChatMessageReceived&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChatMessage&lt;/span&gt; &lt;span class="n"&gt;chatMessage&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onConnect&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onDisconnect&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;blockquote&gt;
&lt;p&gt;While this may seem like an unneeded layer of indirection, &lt;br&gt;
it allows us to decouple the rest of the application from the &lt;a href="https://github.com/pircbotx/pircbotx" rel="noopener noreferrer"&gt;PircBotX&lt;/a&gt; framework.&lt;br&gt;
This way, we're free to change it out with anyother framework without the need to refactor too much. &lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  STOMP for the Win
&lt;/h2&gt;

&lt;p&gt;Now that we're getting the chat messages in the Bootiful backend, we still needed a way to get them to my Javascript Frontend.&lt;br&gt;
The game we're building needs to be usable by multiple different users, each with their own session, their own part of the system.&lt;br&gt;
&lt;strong&gt;I almost instinctively reached for Websockets to complete that task... but something stopped me.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When doing these projects, I always try to limit the amount of new things I'm learning.&lt;br&gt;
Trying to mash too much new shinies in a project always slows me down to a pace which I no longer enjoy. I need a sense of progress.&lt;br&gt;
Having the IRC integration behind me, I did feel it was time for something new, specially since &lt;strong&gt;I had the feeling Websockets weren't a good fit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is when I discovered &lt;a href="https://stomp.github.io/" rel="noopener noreferrer"&gt;Simple Text Orientated Messaging Protocol, or STOMP&lt;/a&gt; for short.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;STOMP provides an interoperable wire format so that STOMP clients can &lt;br&gt;
communicate with any STOMP message broker to provide easy and widespread messaging interoperability among many languages, platforms and brokers.&lt;br&gt;
&lt;br&gt;&lt;br&gt; From: &lt;a href="https://stomp.github.io/" rel="noopener noreferrer"&gt;https://stomp.github.io/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;STOMP resembles IRC in one very convenient way for our application&lt;/strong&gt;. &lt;br&gt;
They use different terminology for this, but they both allow messages to be sent to a named location.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In IRC, messages can be sent to &lt;em&gt;CHANNELS&lt;/em&gt; users can *JOIN&lt;/strong&gt;*.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In STOMP, messages can be sent to &lt;em&gt;DESTINATIONS&lt;/em&gt; users can &lt;em&gt;SUBSCRIBE&lt;/em&gt; on&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While there are some difference between the two, &lt;strong&gt;it's this similarity that caught my attention.&lt;/strong&gt;&lt;br&gt;
Remember, what I wanted to do originally is to connect my frontend game directly to IRC. &lt;br&gt;
What can be done instead is to connect the frontend through STOMP to the Spring Boot backend and use that backend as a Bridge to IRC.&lt;/p&gt;

&lt;p&gt;IMG&lt;/p&gt;



&lt;p&gt;Lucky for us, Spring has built in support for running a STOMP broker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;springframework&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;boot&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;spring&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;boot&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;starter&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;springframework&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;boot&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;spring&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;boot&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;starter&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;artifactId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nd"&gt;@Configuration&lt;/span&gt;
    &lt;span class="nd"&gt;@EnableWebSocketMessageBroker&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebSocketConfig&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;WebSocketMessageBrokerConfigurer&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;configureMessageBroker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MessageBrokerRegistry&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enableSimpleBroker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/topic"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;registerStompEndpoints&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StompEndpointRegistry&lt;/span&gt; &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addEndpoint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/stomp-websocket"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAllowedOrigins&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;withSockJS&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configures a simple message broker and a STOMP endpoint with &lt;a href="https://www.javascripting.com/view/sockjs-client" rel="noopener noreferrer"&gt;SockJS&lt;/a&gt; support.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;SockJS is a library which provides WebSocket-like features, it even uses WebSockets by default. &lt;br&gt;
It will however fallback to different protocols and strategies if WebSockets are not available for whatever reason.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Because the backend will function as a bridge between STOMP and IRC, &lt;br&gt;
it is only natural we want to start/stop the IRC connection at the same time the connection with STOMP starts/stops.&lt;br&gt;
To achieve this, we can listen to &lt;strong&gt;Spring Events which will be fired when a session is started/stopped.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@Autowired&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;through&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;SimpMessagingTemplate&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@EventListener&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleSessionConnected&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SessionConnectEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Get channel out of event&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SessionEventHelper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;extractChannel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Start a new Chatbridge (see code for details)&lt;/span&gt;
        &lt;span class="n"&gt;chatBridge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chatMessage&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Whenever a message arrives, send it to /topic/CHANNEL_NAME through STOMP&lt;/span&gt;
            &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;convertAndSend&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/topic/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chatMessage&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@EventListener&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleSessionDisconnect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SessionDisconnectEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Stop Chatbridge&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whenever an IRC message is received on a certain channel &lt;em&gt;(#channel-name)&lt;/em&gt;, our bridge will place the message on a STOMP destination&lt;br&gt;
with the same name &lt;em&gt;(/topic/channel-name)&lt;/em&gt;. Keeping the name mapping between IRC and STOMP 1 to 1 makes it just a tad easier to manage.&lt;/p&gt;


&lt;h2&gt;
  
  
  Connecting the frontend
&lt;/h2&gt;

&lt;p&gt;Now that's all settled... let's have a quick look at the front-end.&lt;/p&gt;

&lt;p&gt;The way the frontend connects to Spring is by using the endpoint we configured earlier.&lt;br&gt;
We use the SockJS library and wrap it with a Stomp Client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SockJS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/stomp-websocket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;stompClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Stomp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;over&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;twitchHandle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="c1"&gt;// Read from field;&lt;/span&gt;
    &lt;span class="nx"&gt;stompClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;twitchHandle&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Connected: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;stompClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/topic/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;twitchHandle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;textReceived&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Function our game uses to handle received messages&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Roundup
&lt;/h2&gt;

&lt;p&gt;The rest of the frontend doesn't matter that much to be honest. &lt;br&gt;
It's just a simple frontend game in Javascript written with p5.js.&lt;br&gt;
&lt;strong&gt;What does matter is that we have some way to get the Twitch Chat messages all the way to Javascript.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The project is available &lt;a href="https://wordcrash.tomcools.be" rel="noopener noreferrer"&gt;on my website&lt;/a&gt;. Check it out if you're a streamer.&lt;br&gt;
While it is just a simple game, it was fun to see people participate on my own stream.&lt;/p&gt;

&lt;p&gt;If you build some cool Twitch Chat integrated game or application after reading this post, &lt;strong&gt;I'd love to try it!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Full Code is available &lt;a href="https://github.com/TomCools/Wordcrash" rel="noopener noreferrer"&gt;on Github&lt;/a&gt;. &amp;lt;3&lt;/p&gt;

&lt;p&gt;Some usefull resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.twitch.tv/docs/irc/guide#connecting-to-twitch-irc" rel="noopener noreferrer"&gt;Twitch IRC Connection guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spring.io/guides/gs/messaging-stomp-websocket/" rel="noopener noreferrer"&gt;Spring Message STOMP guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stomp.github.io/" rel="noopener noreferrer"&gt;STOMP documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pircbotx/pircbotx" rel="noopener noreferrer"&gt;PircBotX documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>irc</category>
      <category>twitch</category>
      <category>stomp</category>
    </item>
    <item>
      <title>Static access to your Spring Beans</title>
      <dc:creator>Tom Cools</dc:creator>
      <pubDate>Sun, 19 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/tomcools/static-access-to-your-spring-beans-46g</link>
      <guid>https://forem.com/tomcools/static-access-to-your-spring-beans-46g</guid>
      <description>&lt;p&gt;There are some &lt;em&gt;edge cases&lt;/em&gt; where you want to access Spring Beans in a static method. &lt;br&gt;
&lt;strong&gt;While you should always try to refactor your code so you do not have to do this... this post will still show you how it can be done&lt;/strong&gt;.&lt;br&gt;
Continue reading at your own risk! You have been warned! &lt;/p&gt;
&lt;h2&gt;
  
  
  Autowiring Beans
&lt;/h2&gt;

&lt;p&gt;Getting instances of beans in Spring is pretty simple. &lt;br&gt;
You add @Autowired on your constructor and assuming your class is a bean as well, an instance will be injected in your constructor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserServiceImpl&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UserServiceImpl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//JEEJ! an instance!&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Some notes about the above code example before we continue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;@Autowired can also be placed on a field or a setX(x) method. Constructor injection is generally accepted as the best way to inject dependencies;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;When a class only has a single constructor you can omit the @Autowired annotation (since Spring 4.3), I kept it here for clarity;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qjzWGMHU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tomcools.be/post/apr-2020-static-spring-bean/spilling-the-beans.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qjzWGMHU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tomcools.be/post/apr-2020-static-spring-bean/spilling-the-beans.jpg" alt="Spilling the beans"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Time to spill some beans! Statically!&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;In our use-case, we don't want to create a class. We want to be able to have static access to the beans!&lt;br&gt;
This means the standard @Autowire is not an option. There is however another way to get beans, namely directly from the Application Context.&lt;/p&gt;

&lt;p&gt;The Application Context is at the heart of the Spring Framework. It provides a couple of different features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load file resources in a generic fashion;&lt;/li&gt;
&lt;li&gt;Publish events to registered listeners;&lt;/li&gt;
&lt;li&gt;Resolve messages, supporting internationalization;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It has bean factory methods for accessing application components;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is what we are interested in. We want to use the Application Context to get another bean.&lt;br&gt;
The ApplicationContext interface provides a nice convenient method to access beans it knows about: &lt;em&gt;getBean(Class&amp;lt;&amp;gt;)&lt;/em&gt;?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Our static method&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ApplicationContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="c1"&gt;//excluded&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;So all we need now is to get an ApplicationContext and we are done!&lt;/strong&gt; How do we get one?&lt;br&gt;
Well, you could @Autowire one... but we want to use it in a static context. Here is how we can do it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StaticContextAccessor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;ApplicationContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;StaticContextAccessor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ApplicationContext&lt;/span&gt; &lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Create a class marked with @Component. This way, Spring will initialize it on startup by default.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;@Autowire the ApplicationContext.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Set the ApplicationContext to a static field.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;static method can now use the ApplicationContext.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Doing this, we can now use the &lt;strong&gt;getBean()&lt;/strong&gt; method on the StaticContextAccessor to get any bean in a static context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StaticContextAccessor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserRespository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---rA3K-Cq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tomcools.be/post/apr-2020-static-spring-bean/visual-wait.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---rA3K-Cq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tomcools.be/post/apr-2020-static-spring-bean/visual-wait.png" alt="Normal flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Timing and the looming Nullpointer
&lt;/h2&gt;

&lt;p&gt;While the solution above works, there is a major problem with it.&lt;br&gt;
It is possible to use the StaticContextAccessor.getBean(class) method &lt;strong&gt;before&lt;/strong&gt; the ApplicationContext is autowired.&lt;br&gt;
This would crash the system because you can't invoke a method on a reference pointing to null.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NII0Kh9U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tomcools.be/post/apr-2020-static-spring-bean/visual-nullpointer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NII0Kh9U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tomcools.be/post/apr-2020-static-spring-bean/visual-nullpointer.png" alt="Nullpointer Alert!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We have a timing issue here.&lt;/strong&gt;&lt;br&gt;
We know the ApplicationContext will be autowired eventually, usually within seconds if not milliseconds after the application is started.&lt;br&gt;
But we also can't really stop anyone from invoking the static method to get the bean before that happens.&lt;/p&gt;
&lt;h2&gt;
  
  
  Returning a Proxy
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;To avoid the timing issue, we need to bridge the time between those two events.&lt;/strong&gt;&lt;br&gt;
What we could do is provide a temporary object, so our static getBean() returns at least something.&lt;br&gt;
&lt;strong&gt;This can be achieved by using a Proxy object&lt;/strong&gt;, which is a part of the Java specification.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A proxy class is a class created at runtime that implements a specified list of interfaces, known as proxy interfaces. &lt;br&gt;
A proxy instance is an instance of a proxy class. &lt;br&gt;
Each proxy instance has an associated invocation handler object, which implements the interface InvocationHandler. &lt;br&gt;
&lt;br&gt;&lt;br&gt;A method invocation on a proxy instance through one of its proxy interfaces will be dispatched to the invoke method of the instance's invocation handler, passing the proxy instance, a java.lang.reflect.Method object identifying the method that was invoked, and an array of type Object containing the arguments. &lt;br&gt;
&lt;br&gt;&lt;br&gt;Source: &lt;a href="https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/reflect/Proxy.html"&gt;https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/reflect/Proxy.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;So we need a couple of things now. Let's start by seeing how we create the proxy object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getProxy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;getProxy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Our custom invocation handler, will be explained below!&lt;/span&gt;
    &lt;span class="nc"&gt;DynamicInvocationhandler&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;invocationhandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DynamicInvocationhandler&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newProxyInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClassLoader&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;invocationhandler&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The Proxy.newProxyInstance() method will return a dynamic object of the given &lt;strong&gt;interface&lt;/strong&gt;.&lt;br&gt;
It creates a new Object, at runtime, which &lt;strong&gt;extends Proxy&lt;/strong&gt; and &lt;strong&gt;implements the given interface&lt;/strong&gt;.&lt;br&gt;
Since this object implements the given interface, we can return it in our getBean() method. Thanks Polymorphism!&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: This method will only work when requesting a interface. If you want to be able to create a proxy-object for non-interfaces, you could use ByteBuddy. ByteBuddy is out of the scope of this post.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;Next up is the InvocationHandler.&lt;br&gt;
&lt;strong&gt;Whenever a method is invoked on our proxy object, the invoke method of this handler will be called.&lt;/strong&gt;&lt;br&gt;
If your handler has the actual bean set, it will invoke the correct method on our bean instance.&lt;br&gt;
If the actual bean isn't set yet, it will throw a RuntimeException().&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DynamicInvocationhandler&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;InvocationHandler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;actualBean&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setActualBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;actualBean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Method&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actualBean&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Not initialized yet! :("&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actualBean&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now all that is left is to set the actual bean on the handler as soon as it becomes available and we are done!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M8XsDG-x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tomcools.be/post/apr-2020-static-spring-bean/visual-proxy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M8XsDG-x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tomcools.be/post/apr-2020-static-spring-bean/visual-proxy.png" alt="Proxy Diagram"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Full Code Solution
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StaticContextAccessor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;DynamicInvocationhandler&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;classHandlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;ApplicationContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;StaticContextAccessor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ApplicationContext&lt;/span&gt; &lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getProxy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;getProxy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;DynamicInvocationhandler&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;invocationhandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DynamicInvocationhandler&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="n"&gt;classHandlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;invocationhandler&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newProxyInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClassLoader&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="n"&gt;clazz&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt;
                &lt;span class="n"&gt;invocationhandler&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;//Use the context to get the actual beans and feed them to the invocationhandlers&lt;/span&gt;
    &lt;span class="nd"&gt;@PostConstruct&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;classHandlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;invocationHandler&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;bean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="err"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;invocationHandler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setActualBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bean&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DynamicInvocationhandler&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;InvocationHandler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;actualBean&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setActualBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;actualBean&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;actualBean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;actualBean&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Method&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actualBean&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Not initialized yet! :("&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There we go! We can now get Spring components from a static context! &lt;br&gt;
All we need to do is call the static &lt;em&gt;getBean&lt;/em&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StaticContextAccessor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserRespository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h2&gt;
  
  
  About that RuntimeException
&lt;/h2&gt;

&lt;p&gt;Even with this proxying setup, there is still a case which will not work. &lt;br&gt;
As you can see in the handler code above, if the actualBean isn't set yet, we throw a RuntimeException.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StaticContextAccessor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserRespository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;userRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAll&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;//this will break if called before ApplicationContext is ready.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There is no way around this. If the bean isn't created and known in the ApplicationContext, we can't call a method on it.&lt;br&gt;
&lt;strong&gt;The proxy solves the issue with the time between requesting the Bean and the ApplicationContext being created.&lt;/strong&gt;&lt;br&gt;
However, if the real bean isn't loaded into the proxy and a method is invoked, the only option is to throw an exception.&lt;/p&gt;

</description>
      <category>java</category>
      <category>spring</category>
      <category>springboot</category>
    </item>
    <item>
      <title>A plushy controlled game (Part 1)</title>
      <dc:creator>Tom Cools</dc:creator>
      <pubDate>Sat, 29 Feb 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/tomcools/a-plushy-controlled-game-part-1-hf1</link>
      <guid>https://forem.com/tomcools/a-plushy-controlled-game-part-1-hf1</guid>
      <description>&lt;p&gt;I have been fascinated by video games ever since I saw the first level of Mario. They dominated a big part of my youth and are what got me into programming in the first place. Building a website for our Call of Duty clan was probably one of the first times I came into contact with HTML and CSS. &lt;/p&gt;

&lt;p&gt;Recently however, my fascination has shifted from playing games, to discovering how they are built. &lt;strong&gt;Physics are a big part of what makes a game feel natural&lt;/strong&gt;, making things fall with gravity, being blown away by wind, etc. &lt;br&gt;
I had no idea how to even start coding physics, until colleague of mine told me about this great book he had read: &lt;a href=""&gt;The Nature of Code&lt;/a&gt;.&lt;br&gt;
The book describes in incredible detail how you could program physics in a pretty clear and straightforward way.&lt;br&gt;
Best of all, you can find it online, for free! :o&lt;/p&gt;

&lt;p&gt;Next to the physics part, how your audience interacts with your game determines a lot of the experience.&lt;br&gt;
I have always loved the idea of using a camera to control your game so I decided I wanted to use my laptop camera as the main way to interact with the game.&lt;/p&gt;
&lt;h2&gt;
  
  
  What are we building?
&lt;/h2&gt;

&lt;p&gt;So what do you get when you mix physics and computer vision? A demo concept "game" controlled by a plush animal! So fluffy! &amp;lt;3&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/w36o2PjRaKc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this &lt;strong&gt;first post&lt;/strong&gt; we will focus on the basic elements of a game.&lt;br&gt;
We'll cover how to draw items on a canvas and program in some realistic looking physics. &lt;strong&gt;As this blog post contains a lot of examples with Javascript which could not be posted on dev.to, please read the blog on &lt;a href="https://tomcools.be/post/feb-2020-plushy-game-1/"&gt;my own personal website&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>p5js</category>
    </item>
    <item>
      <title>Event Stores: Saving the right kind of byte[]</title>
      <dc:creator>Tom Cools</dc:creator>
      <pubDate>Fri, 14 Feb 2020 15:32:12 +0000</pubDate>
      <link>https://forem.com/tomcools/event-stores-saving-the-right-kind-of-byte-388p</link>
      <guid>https://forem.com/tomcools/event-stores-saving-the-right-kind-of-byte-388p</guid>
      <description>&lt;p&gt;A colleague of mine recently started exploring Event Sourcing.&lt;br&gt;
While his focus is on .NET and mine is on Java, I was more than glad to help him out.&lt;br&gt;
I pointed him to &lt;a href="https://eventstore.org" rel="noopener noreferrer"&gt;Event Store&lt;/a&gt; as a great place to start.&lt;br&gt;
A couple of hours later he shared a link to his github, proclaiming he "had done it".&lt;/p&gt;

&lt;p&gt;The warm feeling you get when helping a colleague discover something new was rising up inside me... until it was taken away again when he dropped the following line on me.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's a shame I have to manually serialize my objects to byte[]...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I immediately opened the Event Store website only to discover that serializing your Objects into byte[] seems to be the default way of saving events when you use the C# library. While there are other ways to create a byte[], &lt;em&gt;there seems to be no guidance what so ever on what you should be putting in your event store&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So... what bytes are a right fit for an event store? To make a decision, lets take a step back to one of the fundamental truths in our sector.&lt;/p&gt;
&lt;h2&gt;
  
  
  Change as a constant vs Event Sourcing
&lt;/h2&gt;

&lt;p&gt;Perhaps one of the most powerful lessons I learned in school was this: &lt;strong&gt;"Change is the only constant"&lt;/strong&gt;. &lt;br&gt;
Writing code is an iterative process where we learn and discover better ways of expressing ourselves. We refactor, we get new insights and sometimes so does the business we are working for.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://martinfowler.com/eaaDev/EventSourcing.html" rel="noopener noreferrer"&gt;Event Sourcing&lt;/a&gt; on the other hand is about writing and never changing events.&lt;br&gt;
Most of the time, the way we save our events is referred to as an "immutable sequence of events". This means that if we save something, we have to keep dragging it along until the end of time. It can not change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;center&gt;Immutable Event Store &lt;em&gt;VS&lt;/em&gt; The fundamental truth of change&lt;/center&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Event Store and the concept of &lt;em&gt;Change&lt;/em&gt; may seem like complete opposites.&lt;br&gt;
What we can do is try to bring the two closer together by &lt;strong&gt;choosing an event structure which is flexible enough to allow for some change, without truly breaking the immutability of the Event Store&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Lets look at some of the options for creating our byte[] events while &lt;em&gt;keeping change in mind&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Serializing JAVA/C# Objects
&lt;/h3&gt;

&lt;p&gt;My colleague chose for serializing his C# objects. There are some obvious pitfalls to this choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Serialization is a very fragile thing&lt;/strong&gt;. Simple changes like adding or renaming fields will already break the system.&lt;br&gt;
Your events will be locked forever to a single version, requiring you to keep them forever and use &lt;a href="https://github.com/prooph/event-store/blob/master/docs/upcasting.md" rel="noopener noreferrer"&gt;upcasters&lt;/a&gt; to update them to the latest version.&lt;/p&gt;

&lt;p&gt;Depending on how much you change your events, this may lead to an explosion of versions and an overall increase in complexity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fndlxpupxmhgry8k41nnl.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fndlxpupxmhgry8k41nnl.jpeg" alt="A developer unable to retrieve a serialized object from the Event Store" width="800" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That being said, there is a bigger issue here. By serializing Objects, you are binding your events to a certain programming language.&lt;br&gt;
This might be a conscious choice but it is not one that should be taken lightly as it will haunt you forever.&lt;/p&gt;
&lt;h3&gt;
  
  
  JSON
&lt;/h3&gt;

&lt;p&gt;To remove the dependency on a specific programming language we could use &lt;a href="https://www.json.org/json-en.html" rel="noopener noreferrer"&gt;JSON&lt;/a&gt;. JSON has been a big success as a communication format in polyglot environments. We are at a point where a public API is expected to return data in a JSON format!&lt;br&gt;
But how does it fare as a format for events in our store?&lt;/p&gt;

&lt;p&gt;While we can now be polyglot when reading our events, it is far from perfect.&lt;br&gt;
For example, if we discover a more meaningful name for a field, we still can not change it.&lt;br&gt;
Have a look at the following JSON structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"event"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UserAddedEvent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"userid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123456789"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tom"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lastname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cools"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Through evolving our code, we notice that we have different kinds of users in our system, which each mean something different.&lt;br&gt;
You want to be able to make the distinction between &lt;em&gt;"Customers", "Employees"&lt;/em&gt; and maybe an &lt;em&gt;"Administrator"&lt;/em&gt; type of user.&lt;br&gt;
As adding employees is new for the system, the currently saved users are all "Customers".&lt;br&gt;
What you actually want to do, is change the event to the following:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"event"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CustomerAddedEvent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;event&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"customerid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123456789"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tom"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lastname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cools"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Using JSON however, this will not work.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can't change the events in the event store, so now you have two kinds of events.&lt;/li&gt;
&lt;li&gt;Without making two readers for the different types, the reading of the event will fail, either hard with an exception, or soft because the resulting field is empty or null.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will be forced to add a new "type" field to the data and your reader must be smart enough to set the &lt;em&gt;type = Customer&lt;/em&gt; as a default.&lt;br&gt;
This might not be a big deal for now, but remember, &lt;em&gt;every version of an event must be handled.&lt;/em&gt; This means, adding more processors or adding more upcasters to handle the differences.&lt;/p&gt;

&lt;p&gt;Another downside is that &lt;strong&gt;JSON is, at its core, a String&lt;/strong&gt;. This means you will need to escape special characters.&lt;br&gt;
Those of you who have lost some hours with escape sequences should have felt a shiver down your spines reading the last paragraphs...&lt;/p&gt;
&lt;h3&gt;
  
  
  Data Serialization Libraries
&lt;/h3&gt;

&lt;p&gt;Data Serialization Libraries are often mentioned in the context of Inter Process Communication. Think about the things you put on Kafka, RabbitMQ or some other message broker. It is commonplace to use a library to transform messages into byte[] to put them on the wire. &lt;em&gt;So why not use those libraries to serialize and save our events?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are some out there, like &lt;a href="https://avro.apache.org/" rel="noopener noreferrer"&gt;Avro&lt;/a&gt; and &lt;a href="http://thrift.apache.org/" rel="noopener noreferrer"&gt;Thrift&lt;/a&gt;, but my personal favorite is the &lt;a href="https://developers.google.com/protocol-buffers/" rel="noopener noreferrer"&gt;Google Protocol Buffers Library&lt;/a&gt;.&lt;br&gt;
Using Protocol Buffers you declare a schema which is used to generate (de)serialization code for a specific programming language.&lt;/p&gt;

&lt;p&gt;The serialized result is the same each time, so you could serialize data using the Java library and deserialize that data again with the .NET Library.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;CustomerAddedEvent&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;optional&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Important to note is that a &lt;strong&gt;Protocol Buffer schema is index based&lt;/strong&gt;. Because this is the case, there is &lt;em&gt;no impact when changing a field name&lt;/em&gt;.&lt;br&gt;
As long as the field index and type never change, you can change the field name as much as you want.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding and removing of fields can be done without problem&lt;/strong&gt; as well. The serialization will keep working.&lt;br&gt;
When you add a new field that didn't exist before, you do need to program a sensible default yourself.&lt;/p&gt;

&lt;p&gt;I have created an example project &lt;a href="https://github.com/TomCools/protocol-buffers-example" rel="noopener noreferrer"&gt;on github&lt;/a&gt; where I use the Maven plugin to generate the Java classes out of the Protobuf Schemas.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/TomCools" rel="noopener noreferrer"&gt;
        TomCools
      &lt;/a&gt; / &lt;a href="https://github.com/TomCools/protocol-buffers-example" rel="noopener noreferrer"&gt;
        protocol-buffers-example
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Example repo for protocol buffers
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Be sure to have a look. For other programming languages, check out the &lt;a href="https://developers.google.com/protocol-buffers/docs/overview" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what do you choose?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Choosing in which structure you save your events is probably the most significant decision you have to make while starting Event Sourcing.&lt;/strong&gt;&lt;br&gt;
If you worry about an ever changing world, you may want a mix between the principles of an Immutable store, while still having a little bit of flexibility.&lt;/p&gt;

&lt;p&gt;Here is a table listing the options I described above and which changes are possible when using each one without adding an extra mapping layer.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Serialized Object&lt;/th&gt;
&lt;th&gt;JSON&lt;/th&gt;
&lt;th&gt;Protocol Buffers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Polyglot&lt;/td&gt;
&lt;td&gt;✘&lt;/td&gt;
&lt;td&gt;✔&lt;/td&gt;
&lt;td&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove field from event&lt;/td&gt;
&lt;td&gt;✘&lt;/td&gt;
&lt;td&gt;✔&lt;/td&gt;
&lt;td&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add field to event&lt;/td&gt;
&lt;td&gt;✘&lt;/td&gt;
&lt;td&gt;✔&lt;/td&gt;
&lt;td&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change field name&lt;/td&gt;
&lt;td&gt;✘&lt;/td&gt;
&lt;td&gt;✘&lt;/td&gt;
&lt;td&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Human Readable&lt;/td&gt;
&lt;td&gt;✘&lt;/td&gt;
&lt;td&gt;✔&lt;/td&gt;
&lt;td&gt;✘&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I have a tendency to forgo the human readability in favor of the flexibility and speed of Protocol Buffers.&lt;br&gt;
If you are interested in performance metrics, the guys at &lt;a href="https://auth0.com/blog/beating-json-performance-with-protobuf/" rel="noopener noreferrer"&gt;auth0 have written a great blog post on this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For now, &lt;strong&gt;I will be sticking with Protocol Buffers&lt;/strong&gt; as the format for my events. Whatever you choose to use, be sure you know the consequences. &lt;br&gt;
&lt;strong&gt;&lt;span&gt;Choosing an event format is a day 1 decision&lt;/span&gt;&lt;/strong&gt;, so whatever you do, keep in mind: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A bad choice now will haunt you for a long, long time.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Don't agree or have another idea, please leave your remarks in the comments!&lt;/p&gt;

</description>
      <category>eventsourcing</category>
      <category>java</category>
      <category>csharp</category>
    </item>
    <item>
      <title>'Just Google It' is not enough - The negative impact of 3 simple words</title>
      <dc:creator>Tom Cools</dc:creator>
      <pubDate>Wed, 12 Feb 2020 15:05:07 +0000</pubDate>
      <link>https://forem.com/tomcools/just-google-it-is-not-enough-the-negative-impact-of-3-simple-words-14lh</link>
      <guid>https://forem.com/tomcools/just-google-it-is-not-enough-the-negative-impact-of-3-simple-words-14lh</guid>
      <description>&lt;p&gt;When I had just transitioned into a senior role a couple of years ago, a junior developer in my team asked me a technical question.&lt;br&gt;
I was busy tackling a pretty important issue which required my full attention so I didn't give him the time he deserved.&lt;br&gt;
Basically what I answered him was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Just Google It..."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fast forward a couple of months. &lt;br&gt;
I am scrolling through Twitter and see an interesting discussion.&lt;br&gt;
The subject is not relevant here but the discussion was between 2 people who seemed to be experts on the topic.&lt;br&gt;
Me being me, I asked for more resources, eager to learn more.&lt;br&gt;
I got a simple and straight answer: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Just Google It&lt;/strong&gt;, we do not have to do the work for you."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;... thanks?&lt;/p&gt;

&lt;h2&gt;
  
  
  Giving vs Receiving
&lt;/h2&gt;

&lt;p&gt;Looking back at those two moments, it started to realize two things.&lt;/p&gt;

&lt;p&gt;Telling my junior colleague to &lt;em&gt;Just Google It&lt;/em&gt; was easy, too easy.&lt;br&gt;
Being new to the senior role, I hadn't yet realized the full scope of my new assignment.&lt;br&gt;
And with 3 words, I was able to go back to my tasks like I never became a senior.&lt;/p&gt;

&lt;p&gt;Being on the receiving side however, being the one with the questions, this doesn't feel good at all.&lt;br&gt;
The motivation and eagerness to learn were somewhat replaced by other emotions, like anger, sadness... feelings which lead to the &lt;strong&gt;Dark Side&lt;/strong&gt;.&lt;br&gt;
I decided not to look into the subject at all and moved on to other things.&lt;/p&gt;

&lt;p&gt;Considering this, I reflected on my own behaviour. How did those 3 simple words impact my colleague?&lt;br&gt;
Did he feel the same way I felt after being &lt;em&gt;"Just Google It"&lt;/em&gt;'d? Perhaps he did.&lt;/p&gt;

&lt;h2&gt;
  
  
  Impact of "Just Google It"
&lt;/h2&gt;

&lt;p&gt;So... what happens when you tell someone to &lt;em&gt;"Just Google It"&lt;/em&gt;? &lt;/p&gt;

&lt;p&gt;We live in an age where software engineers know where to get information.&lt;br&gt;
People know how to Google and most of the time &lt;strong&gt;they already tried Googling for an answer before they asked you a question&lt;/strong&gt;.&lt;br&gt;
At that point, telling them to just look it up online is almost an insult.&lt;br&gt;
In a way, you are telling them they are incompetent, unable to do the simple thing of looking up some information online.&lt;/p&gt;

&lt;p&gt;We all struggle to get something working on almost a daily basis.&lt;br&gt;
Either it's because CSS is being annoying or because you are trying to run 3 different Java versions at the same time.&lt;br&gt;
Not getting any help when struggling might &lt;strong&gt;leave you desperate and ready to quit&lt;/strong&gt;. Is it an good working environment when your motivation is perpetually drained by your senior developer not taking the time to help you? Not very likely.&lt;/p&gt;

&lt;p&gt;There is one thing I see a lot of junior developers struggle with: &lt;strong&gt;Being able to speak up when they get stuck.&lt;/strong&gt;&lt;br&gt;
A few years ago there was one junior colleague who was visibly struggling with this. He would just sit at his desk, head in in his hands, trying to figure out a problem. During a 1-on-1 talk I had with him, he explained the reason for his behaviour.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Bothering you with questions just makes me feel like a junior developer &lt;br&gt;- a junior developer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If someone asks you a question, in a very real sense, they are looking up to you.&lt;br&gt;
They turn to you for expertise. They want to learn from you. &lt;br&gt;
If all you do is say they should look it up online, &lt;strong&gt;this will impact how they view you&lt;/strong&gt;. No matter how great your skills are, they will turn to someone else who actually helps them.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Positive Change
&lt;/h2&gt;

&lt;p&gt;While sending your colleague a &lt;a href="http://letmegooglethat.com/" rel="noopener noreferrer"&gt;"let me google that for you"&lt;/a&gt; link can be funny when done in good sport, it can be taken badly as well.&lt;br&gt;
So just how do we turn this situation into a Win/Win situation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of saying "Just Google It", ask them &lt;strong&gt;"What are the things you have tried already?"&lt;/strong&gt; or &lt;strong&gt;"What is holding you back?&lt;/strong&gt;
There is a big chance they'll show you an entire search history filled with information related to the problem.
&lt;/li&gt;
&lt;li&gt;If you already have an idea on how to solve the issue, try out your solution together by &lt;strong&gt;pair programming&lt;/strong&gt;. 
Not only are you solving the problem, you are sharing what you know at the same time. Great return-on-investment if you ask me.
&lt;/li&gt;
&lt;li&gt;If the issue is vague or you don't know the answer, try &lt;strong&gt;Googling together&lt;/strong&gt;. 
You might be using different terminology leading to better search results. This also helps your colleague to get better results in the future.
It also shows you don't know everything either (despite them thinking you do...), helping to create an environment where it is OK to not know something.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;As senior developers it isn't our job to solve the next issue. It is our job to enable our team to build amazing software.&lt;br&gt;
We can do this by helping them out, guiding them through the ocean of information available on the internet, share what we know.&lt;br&gt;
&lt;strong&gt;Foster a safe environment where it is normal to express doubts and fears, where asking questions is seen as an opportunity to learn for all parties involved.&lt;/strong&gt;&lt;br&gt;
Don't just disregard questions and uncertainties of your teammates.&lt;/p&gt;

&lt;p&gt;In short, it is pretty clear: &lt;strong&gt;"Just Google It" is Just Not Enough&lt;/strong&gt;.&lt;/p&gt;





</description>
      <category>professionalism</category>
      <category>leadership</category>
      <category>leaddev</category>
      <category>java</category>
    </item>
    <item>
      <title>Burnout: Looking the monster in the eye</title>
      <dc:creator>Tom Cools</dc:creator>
      <pubDate>Wed, 05 Feb 2020 13:27:46 +0000</pubDate>
      <link>https://forem.com/tomcools/burnout-looking-the-monster-in-the-eye-3ojf</link>
      <guid>https://forem.com/tomcools/burnout-looking-the-monster-in-the-eye-3ojf</guid>
      <description>&lt;p&gt;Early september 2019, it finally happened. &lt;br&gt;
I had been ignoring the warning signs for years. &lt;br&gt;
Instead of pacing myself for the marathon which is a career, I sprinted, running ever faster, harder, better... only to fall on my face.&lt;br&gt;
I had burned out.&lt;/p&gt;

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

&lt;p&gt;That was 4 months ago and I have started working a couple of days a week now.&lt;br&gt;
As we reach this phase of my recovery, &lt;strong&gt;I want to take the time to list some of the things which helped me get back on top&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Some ground rules
&lt;/h2&gt;

&lt;p&gt;There are a lot of blogs who talk about burnout without further context. To avoid the same trap, here are some baselines for this post.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Blog posts (including this one) are not replacements for professional help&lt;/strong&gt;. Most of the activities in this post were suggested or inspired by my psychologist.&lt;/li&gt;
&lt;li&gt;The books, videos and activities listed in this post helped &lt;strong&gt;me&lt;/strong&gt;. We are all unique individuals and discovering what works for you is your own personal journey... but maybe some of my stuff will inspire you.&lt;/li&gt;
&lt;li&gt;This post is &lt;strong&gt;not about work re-integration&lt;/strong&gt;, both because I'm just starting that phase and your work situation might be very different from mine.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Looking the monster in the eye
&lt;/h2&gt;

&lt;p&gt;During one of our first sessions, my psychologist and I went over a questionnaire. &lt;br&gt;
I got top marks! Unfortunately, the questions were derived from the &lt;a href="https://en.wikipedia.org/wiki/Maslach_Burnout_Inventory" rel="noopener noreferrer"&gt;Maslach Burnout Inventory&lt;/a&gt;, the most recognized test for Burnout.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can do a semi-official test &lt;a href="https://www.mindtools.com/pages/article/newTCS_08.htm" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;br&gt; If you take this test and are troubled by the result, consult a professional.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After a week or 2 of growing some acceptance for my situation, my psychologist and I found that the best next step would be to learn more about burnout.&lt;br&gt;
She gave me the notes she had from a recent seminar, which were a good starting point but a bit too academical for my liking (and current state of mind). After some searching I did find some other sources to learn from which I will share with you here.&lt;/p&gt;
&lt;h3&gt;
  
  
  Video: Understanding Burnout - Prof. Christina Maslach (U.C. Berkeley)
&lt;/h3&gt;

&lt;p&gt;Who better to tell you a bit more about burnout than one of the co-authors of the &lt;a href="https://en.wikipedia.org/wiki/Maslach_Burnout_Inventory" rel="noopener noreferrer"&gt;Maslach Burnout Inventory&lt;/a&gt;?&lt;br&gt;
Prof. Christina Maslach is well known as one of the pioneers in work-related burnout. &lt;br&gt;
In this video she focuses a lot on a &lt;em&gt;mismatch between person and job&lt;/em&gt;, which I didn't really relate to. It does give a nice introduction to the problem.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/4kLPyV8lBbs"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Book: Overcoming burnout in 30 days - Carien Karsten
&lt;/h3&gt;

&lt;p&gt;The title of this book should have been &lt;em&gt;"Overcoming burnout in 30 steps"&lt;/em&gt;, as even the author herself admits in the opening chapter that for most people it will take longer. (Hurray for marketing...)&lt;br&gt;
Despite this, the book offers a great balance between practical advice and (simplified) scientific information. &lt;/p&gt;

&lt;p&gt;This is not a book you read in a single day. Every chapter is chore, in a good way.&lt;br&gt;
&lt;strong&gt;Getting out of a burnout requires serious effort and thought&lt;/strong&gt;. In that sense, this book could be considered to be more of a workout plan than a magazine to leisurely browse through.&lt;/p&gt;
&lt;h3&gt;
  
  
  Video: The Burnout Gamble - Hamza Khan
&lt;/h3&gt;

&lt;p&gt;There are a lot of talks about Burnout on Youtube.&lt;br&gt;
I watched nearly all of them, at least the ones the algorithms allowed me to find.&lt;br&gt;
A lot of them are &lt;em&gt;quick fix&lt;/em&gt;-style talks, talking about this one thing you can change to make it all better.&lt;br&gt;
Others were incredibly personal experiences where it seems to be more important for the speaker to have an audience, someone to listen to &lt;em&gt;what happend to them&lt;/em&gt; than it is to say something of value.&lt;/p&gt;

&lt;p&gt;Amids all of this, there is one talk that stood out. While it did seem to start off as &lt;em&gt;just another personal story&lt;/em&gt;, Hamza's story is meant to reinforce his message, it is not the core of the talk.&lt;br&gt;
He explains the different phases of burnout and gives some practical advice on how to move forward.&lt;br&gt;
All while pulling in references to greek mythology, basketball legends and casino-style gambling.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/iEjukHJybm8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Hamza's talk resonated with me a lot because I consider myself to be a recovering overachiever. &lt;br&gt;
I too kept going while everyone around me told me I was doing more than enough already.&lt;br&gt;
Wether you fall into this same group or not, I believe this is a must-see.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's not the fire that's the problem, &lt;br&gt; it is the absence of the fire that's the issue. - Hamza Khan&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have not yet read Hamza's book (The Burnout Gamble) but if it is as entertaining and revealing as his talks, it should be a great read.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Round-Up
&lt;/h2&gt;

&lt;p&gt;These are the top 3 resources which gave me more insight into burnout. &lt;br&gt;
If you want to learn more, I think some of Prof. Christina Maslach's books or even some of her papers are a safe bet.&lt;/p&gt;

&lt;p&gt;In the next post, I will write about some activities which helped me recharge my batteries again. &lt;br&gt;
If you have anything else burnout-related you would like me to talk about, leave a note in the comments.&lt;/p&gt;

&lt;p&gt;Take care out there and love yourself! &amp;lt;3&lt;/p&gt;

</description>
      <category>burnout</category>
      <category>psychological</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
