David Tanzerhttp://www.davidtanzer.net
enThe Single Responsibility Principlehttp://www.davidtanzer.net/the_single_responsibility_principle
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>Do you know the <a href="https://en.wikipedia.org/wiki/Single_responsibility_principle">Single Responsibility Principle</a> (<strong>SRP</strong>)?</p>
<blockquote class="quotation"><p>The single responsibility principle is a computer programming principle that states that every module or class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class.</p></blockquote>
<p>It seems to generate a lot of confusion. Just a few days ago, Jon Reid had to clarify a misconception about that very principle:</p>
<blockquote class="twitter-tweet" data-lang="de"><p lang="en" dir="ltr" xml:lang="en">SRP is misunderstood. Despite the name, it's not about some Platonic "single responsibility". No, it's "one reason to change." <a href="https://t.co/2iuCZH7oLd">https://t.co/2iuCZH7oLd</a></p>
<p>— Jon Reid (@qcoding) <a href="https://twitter.com/qcoding/status/880512082365390852">29. Juni 2017</a></p></blockquote>
<script async="" src="//platform.twitter.com/widgets.js" charset="utf-8"></script><p>
There, he refers to the definition of Robert C. Martin, who expresses the principle as, "A class should have only one reason to change." In this post, I want to write down my own thoughts about the "Single Repsonsibilty Principle". I hope I can clarify a few things, and do not add too much new confusion ;)</p>
<h3>A Definition that "Works for Me"</h3>
<p>So, some of the confusion comes from "single responsibility" vs. "single reason to change". The definition that talks about "responsibilities" is hard to follow in practice: What exactly is a responsibility? What if I can divide the responsibility in multiple sub-responsibilities? How can I make sure that all the code is part of the same responsibility?</p>
<p>On the other hand, "one reason to change" sounds more like a heuristic to me than a real definition. Yes, when a class has many different responsibilities, it also has many reasons to change. But if that was the definition, we should rename the principle to "SRTCP" (Single Reason To Change Principle).</p>
<p>So, I was searching for a definition that works for me <strong>and</strong> that gives me some guidance in my day-to-day work. After discussing with several very good developers, I nowadays really like the following definition:</p>
<blockquote class="quotation"><p>You can describe everything a design element (method, class, module, ...) does - at a reasonable level of abstraction - as a single, coherent thing.</p></blockquote>
<p>In other words, if you use <a href="https://en.wikipedia.org/wiki/Class-responsibility-collaboration_card">"CRC cards"</a> to desing your classes, the "Responsibilities" column should contain a single bullet point.</p>
<p><a data-flickr-embed="true" href="https://www.flickr.com/photos/davidtanzer/35695853015/in/dateposted-public/" title="SRP_Hangman_1"><img src="https://farm5.staticflickr.com/4286/35695853015_36fde29df2_z.jpg" width="600" height="329" alt="SRP_Hangman_1" /></a></p>
<script async="" src="//embedr.flickr.com/assets/client-code.js" charset="utf-8"></script><p>
If the level of abstraction is too high, you can describe everything as a single thing ("Is a part of the XYZ system"). If the level of abstraction is too low, everything has many responsibilities ("Execute assembler instruction x. Execute assembler instruction y. ..."). So what is a "reasonable" level of abstraction?</p>
<p>We'll come to that soon, after an example...</p>
<h3>Hangman</h3>
<p>When I teach TDD workshops, I ask the attendees to implement <a href="https://en.wikipedia.org/wiki/Hangman_(game)">Hangman</a> (the word guessing game) - even multiple times. I now want to discuss with you a few possible designs for implementing this game (none of them is the best possible design, of course).</p>
<p>Let's start simple. The whole problem is so easy, you can implement everything in a single class:</p>
<p><a data-flickr-embed="true" href="https://www.flickr.com/photos/davidtanzer/35527023992/in/dateposted-public/" title="SRP_Hangman_2"><img src="https://farm5.staticflickr.com/4266/35527023992_0551a20898_z.jpg" width="600" height="308" alt="SRP_Hangman_2" /></a></p>
<p>This design has a few disadvantages. Most glaringly, in a TDD class: It is really hard to test. Especially if you do not make any compromises like making methods public that should actually be private.</p>
<p>We can try to simply split the class along the four responsibilities that we have already identified:</p>
<p><a data-flickr-embed="true" href="https://www.flickr.com/photos/davidtanzer/35695852825/in/dateposted-public/" title="SRP_Hangman_3"><img src="https://farm5.staticflickr.com/4263/35695852825_b6118424c7_z.jpg" width="640" height="348" alt="SRP_Hangman_3" /></a></p>
<p>Now you can easily test three of the four classes, and with some work, you can probably even test the UI. And you can test every class in complete isolation from the other classes, which is great for achieving stable tests...</p>
<p>Is 4 classes for such a simple problem over-engineering? Quit possibly. But I am trying to make a point here...</p>
<h3>(Single) Level of Abstraction</h3>
<p>So, how do you decide which level of abstraction is right?</p>
<p>There are already several levels in your application, e.g.:</p>
<pre>
program / library
&gt; package / module
&gt; public classes
&gt; public methods
&gt; private methods
&gt; package protected classes
&gt; public methods
&gt; private methods
</pre><p>
To add clarity to your design, make sure that all design elements in a level are roughly on the same level of abstraction (yes, there is gut-feeling involved in deciding that).</p>
<p>So, all the public methods in a class should be roughly on the same level of abstraction, and the class itself would be on a <strong>higher level</strong>. They delegate to private methods of that class to do the real work, which are on a <strong>lower level</strong>.</p>
<p>Sometimes you can find interesting responsibilities by looking at the tests of a class or method. And when you split it, you might need new design elements (a new package or a new class) to keep everything at roughly the same level of abstraction.</p>
<h3>Tests and Responsibilities</h3>
<p>So, I wrote some tests for the "Rules" class - This time using a <strong>different design</strong>, where I do not split out the game state to its own class. Here is the output of Jest, a JavaScript Test Runner:</p>
<pre>
Hangman - Implements the flow of a single Hangman game, given a secret word.
<span style="color: greenyellow">√</span> returns a hint that contains only underscores at the start of the game
<span style="color: greenyellow">√</span> shows a hint with the correct length for the secret word "test" at the start of the game
<span style="color: greenyellow">√</span> shows a hint with the correct length for the secret word "a" at the start of the game
<span style="color: greenyellow">√</span> shows a hint with the correct length for the secret word "few" at the start of the game
<span style="color: greenyellow">√</span> shows a hint with the correct length for the secret word "cases" at the start of the game
<span style="color: greenyellow">√</span> updates hint to "c____" after guessing "c" when word is "cases"
<span style="color: greenyellow">√</span> updates hint to "c_s_s" after guessing "c,s" when word is "cases"
<span style="color: greenyellow">√</span> updates hint to "c_ses" after guessing "c,s,e" when word is "cases"
<span style="color: greenyellow">√</span> does not update the hint when making a wrong guess
<span style="color: greenyellow">√</span> decrements the number of remaining tries after a wrong guess
<span style="color: greenyellow">√</span> does not decrement the number of wrong guesses after a right guess
<span style="color: greenyellow">√</span> indicates game is over ("Lost") when there was only one guess remaining and the user guessed wrong
<span style="color: greenyellow">√</span> indicates game is over ("Won") when the user guessed all letters of the secret word
<span style="color: greenyellow">√</span> does not accept any input after the game is over
</pre><p>
<a href="https://gist.github.com/dtanzer/63d619c1797edfcde54bd2dc5573a1c8">Here is the code that produced this output...</a></p>
<p>Oh, some of these tests seem to belong together. Let's group them, and look at the test output again:</p>
<pre>
Hangman - Implements the flow of a single Hangman game, given a secret word.
Generates Hints from the secret word and the input
<span style="color: greenyellow">√</span> returns a hint that contains only underscores at the start of the game
<span style="color: greenyellow">√</span> shows a hint with the correct length for the secret word "test" at the start of the game
<span style="color: greenyellow">√</span> shows a hint with the correct length for the secret word "a" at the start of the game
<span style="color: greenyellow">√</span> shows a hint with the correct length for the secret word "few" at the start of the game
<span style="color: greenyellow">√</span> shows a hint with the correct length for the secret word "cases" at the start of the game
<span style="color: greenyellow">√</span> updates hint to "c____" after guessing "c" when word is "cases"
<span style="color: greenyellow">√</span> updates hint to "c_s_s" after guessing "c,s" when word is "cases"
<span style="color: greenyellow">√</span> updates hint to "c_ses" after guessing "c,s,e" when word is "cases"
<span style="color: greenyellow">√</span> does not update the hint when making a wrong guess
Keeps track of remaining guesses, so UI can draw the gallows pole
<span style="color: greenyellow">√</span> decrements the number of remaining tries after a wrong guess
<span style="color: greenyellow">√</span> does not decrement the number of wrong guesses after a right guess
Keeps track of whether the game is running or over (Won / Lost)
<span style="color: greenyellow">√</span> indicates game is over ("Lost") when there was only one guess remaining and the user guessed wrong
<span style="color: greenyellow">√</span> indicates game is over ("Won") when the user guessed all letters of the secret word
<span style="color: greenyellow">√</span> does not accept any input after the game is over
</pre><p>
<a href="https://gist.github.com/dtanzer/d8e746f19e0541e355aa59fc301b5683">Here is the code that produced this output...</a></p>
<p>It seems like this class has three different responsibilities (at least at some level of abstraction). So, if I wanted, I could split this "Rules" class even further, into one class for each of the groups, and one to coordinate them. Then I would probably need a package to group these two "Rules" classes, and the responsibility of that package could now be "Implements the state changes of a single game, based on the rules".</p>
<p>Does it always make sense to split a class like that? That depends on a lot of things, but from the perspective of the Single Responsibility Principle, we <strong>could</strong> do it...</p>
<h3>Conclusion</h3>
<p>The Single Responsibility Principle gives you an indicator when to change your design. Split your methods / classes / modules when they have more than one responsibility. Restructure code when your classes / methods / modules do not fully encapsulate that responsibility.</p>
<p>When your design elements have many different responsibilities, they have many reasons to change. And they are also hard to test. When your design elements do not reasonably encapsulate their responsibility, changes will cascade through your code. And again, it will be harder to test.</p>
<p>But do not start to split all your classes alon their reponsibilities right away! The SRP should not be the only driving force of your designs - There are other forces, and sometimes they give you conflicting advice. Take, for example, the <a href="https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)">SOLID principles</a> - 5 design principles, where the SRP is only one of them.</p>
<p><em>By the way:</em> <a href="https://twitter.com/qcoding">Jon Reid</a> has now also written an article about the SRP: <a href="https://qualitycoding.org/single-responsibility-principle/">Single Responsibility Principle: Is It a Fundamental Mistake?</a> Go read it, it's excellent!</p>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-above"><div class="field-label">Posting Type:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/professional">David&#039;s Blog</a></div></div></div>Wed, 26 Jul 2017 10:03:33 +0000david248 at http://www.davidtanzer.nethttp://www.davidtanzer.net/the_single_responsibility_principle#commentsI am Not the Best Developer on the Teamhttp://www.davidtanzer.net/i_am_not_the_best_developer_on_the_team
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>Being a freelance consultant / coach, I have worked with many different teams in the last 10+ years. As far as I am concerned, I never was the best developer on the team.</p>
<p>No, I do not have any proof for that, of course not. It is more of a mind set than something that can be objectively proven to be true or false. Let me explain...</p>
<h2>Learning Every Day</h2>
<blockquote><p>
Learn from everyone, follow noone.
</p></blockquote>
<p>If you hire me, I come to your company to learn something. Yes, I also come to provide more value for you than you pay for me - To teach you something, to coach your team, to help you solve a problem, to write some code. That's why you hired me.</p>
<p>But for me, it is also a learning experience. I am trying to get better at what I do every day. I read many books, blogs, and I try to learn from everyone. And I really think that you <strong>can</strong> learn something from <strong>everyone</strong>: Even the most senior developer might learn a thing or two from the most junior, if she is open to learning something.</p>
<p>Now, if I would be in a team and have an attitude like "I am the best X here", learning from everyone else just becomes a lot harder, at least in the field of X. Also, I think others on the team might notice that attitude, and this would also hinder mutual learning / teaching.</p>
<h2>But What if I am the Best?</h2>
<p>Let's assume, hypothetically, that I come to a team, where after some time, all my evidence suggests that I am really the best developer (I do not think this has ever happened to me). I would still try hard to think that I am not the best.</p>
<p>A little humility can help in many aspects. Mutual learning / teaching, like above, is one of them. A better team culture is another. When you ask for help, you encourage people to talk to you on the same level.</p>
<h2>Too Many Dimensions</h2>
<p>Also, there are too many dimensions where you can be good in software development. And a team working on any non-trivial task needs many of those dimensions.</p>
<p>So who is the best developer - The person who is good at keeping the overall architecture in mind, the person who knows all the details of your programming language, the person who is getting the details right, or anyone else on the team? You need all of them!</p>
<p>I think that I, personally, are quite competent in several programming languages, in software architecture / design, in techniques for better software quality, in facilitating better team practices. I think that, over time, I have become quite good at dealing with legacy code. I am also quite competent as a trainer and as a technical coach.</p>
<p>But I am probably not the best developer or tester or architect or coach or trainer you have ever seen.</p>
<h2>Good in Multiple Disciplines</h2>
<p>I think <a href="https://en.wikipedia.org/wiki/Scott_Adams">Scott Adams</a> (I cannot find the quote anymore) once wrote that it is really hard to become world class in a single field, but when you become merely quite good in multiple fields, you might already be world class for <strong>this combination</strong> of fields. And this can be very valuable.</p>
<p>I always liked this idea, and I try to work like that. This is why I think I am competent in so many different fields, but surely not the best in any of them. And so far, this has worked quite well for me.</p>
<p>But even this is not what I am trying to say.</p>
<h2>Keep Learning</h2>
<p>My goal is to keep learning, to keep becoming better. And a little humility can help a lot here.</p>
<p>When my state of mind is "I am not the best X in here", the questions become "What can I learn from you?" or "How can you help me today?" and, of course, "How can we help each other today?".</p>
<p>But, of course, this is also something I have to constantly work on. I always have to remind myself to ask these questions. So this post is also a little reminder to myself ;)</p>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-above"><div class="field-label">Posting Type:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/professional">David&#039;s Blog</a></div></div></div>Fri, 31 Mar 2017 05:14:54 +0000david247 at http://www.davidtanzer.nethttp://www.davidtanzer.net/i_am_not_the_best_developer_on_the_team#commentsReact / Redux Training Coursehttp://www.davidtanzer.net/react_redux_training_course
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>Last week, I hosted an online training course for people from all over Europe. There they learned how to build web applications with React and Redux. We recorded Videos during the talk, and I prepared some more Videos and Training Materials for you. Get them here:</p>
<p><a href="http://quickglance.at/react">React / Redux Training Course</a></p>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-above"><div class="field-label">Posting Type:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/professional">David&#039;s Blog</a></div></div></div>Thu, 16 Mar 2017 06:10:53 +0000david246 at http://www.davidtanzer.nethttp://www.davidtanzer.net/react_redux_training_course#commentsFree React / Redux Workshophttp://www.davidtanzer.net/free_react_redux_workshop
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>I will be teaching a <strong>free</strong>, online React / Redux Workshop for up to 8 students.</p>
<p><strong>Date:</strong> Thu March 9th - Fri March 10th, 2017, 9:00 - 17:00<br /><strong>Location:</strong> online (probably Hangouts)</p>
<p>This workshop is for beginners. We will start with the basics of React / Redux, so you don't need any experience with either library. But some JavaScript experience probably helps.</p>
<p>Here's how it will work:</p>
<ul><li>Register with the form below.</li>
<li>8 people who registered will be in the live workshop, everyone else will be on the waiting list.</li>
<li>I will record the workshop. By registering, you agree that I can record the workshop and publish the recordings online, either for free or for profit.</li>
<li>If everything works (quality of the recording, ...), the 8 participants and everyone on the waiting list will get the videos <strong>for free</strong>.</li>
<li>If you don't have time for the live sessions, you can still register. Answer the "Video"-question with "No", you will still get the free videos afterwards.</li>
</ul><p>Hope to see you there! Register here (Mobile users: Swipe up/down to navigate the questions):</p>
<p><i><strong>Registration is closed now.</strong> Follow <a href="https://twitter.com/dtanzer">@dtanzer</a> to get updates.</i></p>
<p>Any questions? <a href="mailto:Business@DavidTanzer.net?Subject=Questions%3A%20Free%20React%20/%20Redux%20Workshop">Business@DavidTanzer.net</a></p>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-above"><div class="field-label">Posting Type:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/professional">David&#039;s Blog</a></div></div></div>Mon, 06 Feb 2017 05:16:51 +0000david245 at http://www.davidtanzer.nethttp://www.davidtanzer.net/free_react_redux_workshop#commentsYou don't Find Bugs in Legacy Codehttp://www.davidtanzer.net/you_dont_find_bugs_in_legacy_code
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>Of course there are defects in legacy code. But when you are a developer working on changing, refactoring or enhancing legacy code, many of the "defects" you'll find are probably desired behaviour (or have been, at some point in time). And even when they are not, you often still cannot be sure if you can fix the undesired behaviour without negatively affecting users. Let me explain...</p>
<h2>...Changes Colour Unexpectedly</h2>
<p>I once wrote some piece of really bad code that I use when I facilitate refactoring exercises at conferences, at user group meetups and during my trainings: The <a href="https://github.com/dtanzer/babystepstimer">BabySteps Timer</a>. A few days ago, I invited people on Twitter to refactor this code, as a challenge.</p>
<p>One of the developers who accepted the challenge, <a href="https://twitter.com/singsalad">Franziska</a>, submitted a defect report:</p>
<blockquote class="quotation"><p>
<strong>Clock resets to white colour when time is over</strong></p>
<p> Not sure if bug or feature, if the time has expired, the clock turns red, starts counting down from 2:00 again and then it turns white after a couple of seconds (see screenshots).</p>
<p> <a href="https://github.com/dtanzer/babystepstimer/issues/1">Issue #1</a> by <a href="https://github.com/franziskas">Franziska Sauerwein</a>
</p></blockquote>
<p>I am fully aware that Franziska only reported some unexpected behaviour she saw, and did not have any intent of changing that behaviour during a refactoring exercise.</p>
<p>But this reminded me of a situation I experienced at a past client, where we actually changed some unexpected behaviour, and it didn't turn out well...</p>
<h2>But... The Numbers are Wrong!</h2>
<p>Some years ago, I was working with 2 Scrum teams as an agile coach. When I joined, they were already one year into a project where they were changing some legacy code: They refactored the server, and they completely re-wrote the client.</p>
<p>In addition to its main purpose, the software calculated some statistics. When we started to work on that feature, we found out that the numbers it calculated were wrong. Under some conditions, it just gave inaccurate answeres, that were at least in the right ballpark, but sometimes the numbers were not only inaccurate - just plain wrong.</p>
<p>None of the business analysts could remember what this statistics feature was used for, so we tried to find out who uses it. We looked at the logs of the last 6 months and found out: It was never used! Not a single time!</p>
<p>Our Product Owner asked some key stakeholders, but noone could explain to us why this feature would be required. So we removed it.</p>
<p>A few months later, the "Blocker" defects were rolling in: "The statistics feature is missing! We cannot do our work!" they said.</p>
<p>We found out that this feature was only used during 4-6 weeks of the year and only by some users, and we did not look at this time frame when searching the logs.</p>
<p>We tried to convince the users to allow us to change the statistics so they'll get the correct numbers. But we did not get a budget for that. They just wanted the old feature back, because "We only use them as ballpark estimates anyway". "And when the software gives you <strong>wrong</strong> numbers?" we asked - "Oh, we can spot that", they said.</p>
<p>So we put the faulty feature back in. But even after we put the feature back in, nobody wanted us to fix the defects...</p>
<h2>Unexpected != Defect</h2>
<p>In a real legacy code situation, don't expect that you have found a defect when you have found some really strange behaviour. Ask business analysts. Ask stakeholders. Ask real users. Gather data from usage statistics and logs.</p>
<p>And even after you did all this, you cannot be 100% sure...</p>
<p>Yes, there are defects in legacy code. And yes, you will find some of them. But, as a developer, beware of just fixing the defect (especially if you are new to the project): The strange behaviour might not be a defect at all. And even if it is one, your fix might cause more problems than the defect.</p>
<p><strong>Update:</strong> This post was on the front page of hacker news. <a href="https://news.ycombinator.com/item?id=13460401">Read the discussion here</a>.</p>
<p><em>Side Note: I also changed the README of the babysteps timer to make it more clear that it is mainly an exercise/kata, not a program you should use. Even though you can use it, if you want.</em></p>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-above"><div class="field-label">Posting Type:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/professional">David&#039;s Blog</a></div></div></div>Fri, 20 Jan 2017 14:53:10 +0000david244 at http://www.davidtanzer.nethttp://www.davidtanzer.net/you_dont_find_bugs_in_legacy_code#commentsLegacy Code Refactoring at Softwerkskammer Munichhttp://www.davidtanzer.net/legacy_code_refactoring_at_softwerkskammer_munich
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>Yesterday I facilitated a "legacy code refactoring" session at the <a href="https://www.meetup.com/Software-Craftsmanship-Meetup-Softwerkskammer-Munchen/events/236096130/">Softwerkskammer München Meetup</a>. There were ~50 craftswoman and craftsmen, and all of them were coding, trying to improve some particularily bad code I wrote.</p>
<p>We did three different exercises, each of them for 30 minutes, and in all of them, we tried to bring a piece of bad code under test.</p>
<h2>The Code</h2>
<p>First I gave them a very short (actually too short - but that was on purpose) introduction to the code: The "Babysteps Timer". This is a very simple GUI program I wrote some time ago, because I needed a short example of really bad code that I could use for refactoring exercises.</p>
<p><em>Clone it on GitHub if you want to try the exercise yourself: <a href="https://github.com/dtanzer/babystepstimer">https://github.com/dtanzer/babystepstimer</a>.</em></p>
<p>The application is just a timer that counts down from 02:00 to zero. Ten seconds before reaching zero, it plays a sound. When it actually reaches zero, it plays a sound and changes the background color to red for a few seconds. When you reset it before it reaches zero, it changes the background color to green for a few seconds. That's it.</p>
<p>The code is reasonably short (a single class with ~150 lines without the Java boilerplate) and most variables are reasonably well named (for some definition of "reasonably" ;) ). Still it is very hard to change: The class has more than 10 different responsibilities, there are two threads, lots of inner classes, and every small part of the code is coupled to almost everything else.</p>
<p>The code makes testing particularily hard because it makes several calls to <code>System.currentTimeMillis()</code> and state changes take a long time: After starting the timer, you need to wait <strong>a full second</strong> (that's 1 000 000 microseconds!) until you see the timer changing. So when your tests can control how fast time progresses for the application, you can test the application more easily and the tests will run faster.</p>
<h2>Exercise 1: Refactor, then test</h2>
<p>Sometimes, it is so hard to find seams for testing in a bit of code that it makes sense to first refactor a bit to make the code more testable, and then add some tests. This was our first exercise:</p>
<p><em>Perform some refactoring to make the code testable, then write a test.</em></p>
<p>Participants could do any refactorings they wanted - Get rid of all the static stuff, extract inner classes to their own files, extract some methods, rename stuff - Whatever. But their goal should be to write a first test (any kind of test - unit test or integrated test or behavior test) after ~25 minutes of refactoring.</p>
<p>I told them to rely on their IDEs as much as possible to minimize the amount of manual testing, which slows you down considerably because a full timer cycle lasts 2 minutes.</p>
<p>As far as I know, nobody got to the point where they could write a first green test. And that was exactly the point of this exercise: I wanted to show them how hard it is to first refactor, then test. Even when it's often tempting. Especially in a code base like this, with so much coupling and so little cohesion.</p>
<h2>Exercise 2: Test, then refactor</h2>
<p>OK, so if we cannot easily make this code testable, maybe we can find a way to test it without changing it. At first, this code looks like there are no seams for testing, but there actually is one: The <code>JTextPane</code> that contains the whole user interface. You can get the whole HTML from this text pane, and you can invoke it's <code>HyperlinkListener</code> to simulate button clicks. So, our second exercise was:</p>
<p><em>Write some high-level functional tests using the timerPane's HTML and hyperlink listener. Then start to refactor</em></p>
<p>I also told them that, once they have a few tests, a good first refactoring would be to try to control the progress of time, because this would speed up their existing tests.</p>
<p>Writing those tests will not make the hard refactorings from Exercise 1 any easier, but at least you'll have a safety net of tests before you do it. When you do it right, you can write automated test for the whole user-visible functionality without making any <strong>big</strong> changes, and then speed them up by controlling time. Then you can start the refactoring with fast, automated tests as your safety net.</p>
<p>I don't think any pair actually did a bigger refactoring. Bot several people told me afterwards that it was an eye-opener for them how easy it was to write the tests before the refactoring, compared to refactoring first.</p>
<h2>Exercise 3: Golden Master</h2>
<p>I also showed them the <a href="http://blog.codeclimate.com/blog/2014/02/20/gold-master-testing/">Golden Master</a> techniqe and told them that it is sometimes very well suited for testing legacy code. So this was our third exercise:</p>
<p><em>Add log statements to the code, save the log output as your golden master, and compare future runs to this golden master.</em></p>
<p>I added Samir Talwar's <a href="https://github.com/SamirTalwar/Smoke">Smoke</a> test framework and told them they could use it if they want. Or they could also just save the logs to files and compare them with whatever tool they had. Not everyone could use Smoke because some didn't have Ruby installed...</p>
<p>Even though the "Baby Steps Timer" is not very well suited for "Golden Master" testing, people were very interested in this exercise. Most didn't know "Golden Master" before, and some said they wanted to try it on some "real" code.</p>
<h2>Fun and Learning</h2>
<p>I had a lot of fun yesterday, and I learned a lot. I hope most or all attendees feel the same :) So thanks to everyone at Softwerkskammer München and LV 1871 who made this event possible.</p>
<p>If you want to run a legacy code refactoring session at your meetup or in your company, feel free to use the <a href="https://github.com/dtanzer/babystepstimer">Baby Steps Timer</a>. If you want some tips for facilitating the session, or if you have some ideas/improvements for me, just <a href="mailto:Business@DavidTanzer.net?Subject=Legacy%20Code%20Refactoring%3A%20The%20BabySteps%20Timer">contact me</a> - I'll be happy to help and/or listen. And if you want me to facilitate that session or run a longer training for you, I can do that too: <a href="mailto:Business@DavidTanzer.net?Subject=Legacy%20Code%20Refactoring%3A%20The%20BabySteps%20Timer">Let's talk</a> ;)</p>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-above"><div class="field-label">Posting Type:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/professional">David&#039;s Blog</a></div></div></div>Fri, 13 Jan 2017 07:17:17 +0000david243 at http://www.davidtanzer.nethttp://www.davidtanzer.net/legacy_code_refactoring_at_softwerkskammer_munich#commentsreact-native-ubunut on Fedora Linuxhttp://www.davidtanzer.net/react_native_ubuntu_on_fedora_linux
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>Last week, I first heared about <a href="https://github.com/CanonicalLtd/react-native/blob/ubuntu/README-ubuntu.md">React Native Ubuntu</a>. I thought: That's awesome - Now I can develop desktop applications for all major operating systems (since there is also a <a href="https://github.com/ReactWindows/react-native-windows">React Native Windows</a> and <a href="https://github.com/ptmt/react-native-macos">React Native MacOS</a>). So I had to give it a try.</p>
<p>The only problem: My main laptop is running Fedora, and I do not want to switch to Ubuntu just for toying with a new technology. Well, I tried anyway, and I was pleasantly surprised that it was not very hard to set up. (Wouldn't it be really cool if Canonical and RedHat would work together on react native and renamed it to "React Native Linux"? <a href="https://twitter.com/home?status=Heya%20%40RedHatNews%20-%20Please%20join%20forces%20with%20%40Canonical%20on%20react-native-ubuntu%20(and%20rename%20the%20project)%20-%20http%3A//buff.ly/2fAvYiy">Tell them!</a>).</p>
<p>So, here's what I did to install and run the react native starter app on my Fedora system:</p>
<h3>Clone the GitHub Repo</h3>
<p>I will clone the react-native-ubuntu repository to a directory where I have my development libraries ("<code>devel-libs</code>" in this case):</p>
<pre class="hljs bash">
[devel-libs]$ git clone https://github.com/CanonicalLtd/react-native -b ubuntu
</pre><p>
And then you need to install sinopia (a local npm registry), uninstall the react-native command line interface, reinstall it from the ubuntu branch, change the registry for the globally installed npm to sinopia, ...</p>
<p><strong>Wait, what?</strong></p>
<h3>Installing Stuff Globally?</h3>
<p>So, the developers really want me to modify the global environment on my laptop? I won't do that. Especially not for playing around with a technology that I might not even need.</p>
<p>The thing is: If your library requires me to install anything globally on my development machine, you have a <strong>coupling problem</strong>. Which is an architectural problem. Go, fix it.</p>
<p>But: I wanted to try react-native-ubuntu anyway. I thought about using a Vagrant VM, but I first wanted to try to install everything locally - within my example project. And it worked! So throw away the <code>react-native-cli/README.md</code> and bear with me...</p>
<h3>Install Qt Dependencies</h3>
<p>I actually <strong>did</strong> install some dependencies globally - The Qt 5 libraries that are needed to compile and run the react-native app:</p>
<pre class="hljs bash">
$ sudo dnf install Qt5Core
$ sudo dnf install qt5-default
$ sudo dnf install qt5-qtbase-devel
</pre><p>
I think those were all. You might need different libraries, depending on your system setup...</p>
<h3>Local Installation</h3>
<p>Well, let's just try to install react-native locally, in a directory where I want to create my example application ("<code>example</code>"). "<code>path/to/react-native</code>" is the directory where I've checked out the ubuntu branch of react-native before.</p>
<pre class="hljs bash">
[example]$ npm install ~/path/to/react-native
[example]$ npm install ~/path/to/react-native/react-native-cli/
</pre><p>
Now I can run the react-native-cli from the local installation in "<code>node_modules</code>":</p>
<pre class="hljs bash">
[example]$ node node_modules/react-native-cli/index.js init TestApp
Looks like React Native project already exists in the current
folder. Run this command from a different folder or remove node_modules/react-native
</pre><p>
OK, react-native-cli wants to download react-native. That's why the official guide wants me to install sinopia (which I still want to avoid). Maybe there's a workaround? Let's delete the react-native module, let the cli do whatever it wants to do, and then install react-native from the ubuntu branch again...</p>
<pre class="hljs bash">
[example]$ rm -rf node_modules/react-native
[example]$ node node_modules/react-native-cli/index.js init TestApp
[example]$ cd TestApp/
[TestApp]$ rm -rf node_modules/react-native/
[TestApp]$ npm install ~/Documents/Development/react-native
[TestApp]$ node ../node_modules/react-native-cli/index.js run-ubuntu
</pre><p>
And now our react-native app is running! Isn't it awesome?</p>
<p><figure class="embed hide-smooth dark image_half_width"><a href="https://www.flickr.com/photos/davidtanzer/30769040941/in/dateposted-public/"><img src="https://farm6.staticflickr.com/5336/30769040941_c2632f0c9a_z_d.jpg" alt="react-native-ubuntu app running on Fedora Linux" /><figcaption>react-native-ubuntu app running on Fedora Linux</figcaption></a></figure></p>
<p>Now I can start playing with developing desktop apps using react-native. Maybe I'll try react-native-windows next...</p>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-above"><div class="field-label">Posting Type:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/professional">David&#039;s Blog</a></div></div></div>Tue, 08 Nov 2016 11:06:44 +0000david242 at http://www.davidtanzer.nethttp://www.davidtanzer.net/react_native_ubuntu_on_fedora_linux#commentsSpring Boot and React: Flow and Mochahttp://www.davidtanzer.net/spring_boot_and_react_flow_and_mocha
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>In my last blog post, I created a basic setup for getting started with <a href="http://www.davidtanzer.net/getting_started_with_react_and_spring_boot">Spring Boot and React</a>. But some things were still missing, like type-checking JavaScript with <a href="https://flowtype.org/">flow</a> or running the mocha tests with gradle.</p>
<p>Once again, you can get the current status of the whole project on GitHub: <a href="https://github.com/dtanzer/example-react-spring-boot">dtanzer/example-react-spring-boot</a>. Feel free to clone this project as a blueprint for your own projects...</p>
<h3>Type-Check with Flow</h3>
<p>We need some more dependencies to get started, so we'll add them to <strong><code>web-frontend/build.gradle</code></strong>:</p>
<pre>
task clientDependenciesDev(type: Exec) {
commandLine 'npm', 'install', '--save', 'mocha', <strong>'mocha-cli'</strong>, 'jsdom', 'react-addons-test-utils', 'chai', 'sinon', 'enzyme', <strong>'flow-bin'</strong>
}
task clientDependencies(type: Exec, dependsOn: 'clientDependenciesDev') {
commandLine 'npm', 'install', '--save', 'react', 'react-dom', 'babelify', 'babel-core', 'babel-preset-react', 'babel-preset-es2015', <strong>'babel-plugin-transform-flow-strip-types'</strong>
}
</pre><p>
And for whatever reason, flow need a <strong><code>web-frontend/package.json</code></strong>:</p>
<pre>
{
"name": "react_spring_boot",
"scripts": {
"flow": "flow; test $? -eq 0 -o $? -eq 2"
}
}
</pre><p>
And also a <strong><code>web-frontend/.flowconfig</code></strong>:</p>
<pre>
[ignore]
&lt;PROJECT_ROOT&gt;/build/.*
&lt;PROJECT_ROOT&gt;/node_modules/.*
</pre><p>
Now we want to see if flow is working. By default, flow does not check your JavaScript files, so you have to add "//@flow" to them.</p>
<pre>
<strong>//@flow</strong>
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import {HeaderArea} from './headerarea';
//...
</pre><p>
Type "npm run-script flow" on your command line, and you should see some output. Probably errors. We'll get to that later.</p>
<pre>
$ npm run-script flow
</pre><h3>IntelliJ IDEA and FlowType</h3>
<p>In IntelliJ IDEA, set the language version for JavaScript files to "Flow". You can do this in the "Settings" under "Languages and Frameworks" / "JavaScript".</p>
<p><figure class="embed hide-smooth dark image_half_width"><a href="https://www.flickr.com/photos/davidtanzer/28526490914/in/dateposted-public/"><img src="https://farm9.staticflickr.com/8103/28526490914_48392064bd_z_d.jpg" alt="IDEA set JS language version to Flow" /><figcaption>IDEA set JS language version to Flow</figcaption></a></figure></p>
<p>But this only sets the language level. Right now, IntelliJ IDEA does not actually highlight flow type errors by itself. So to actually see the flow errors, you need to install a thrid party plugin: <a href="https://github.com/dsilva/webstorm-plugin-flow-typecheck/releases">dsilva/webstorm-plugin-flow-typecheck/releases</a> - Just download the latest release and install the plugin from disk.</p>
<p><figure class="embed hide-smooth dark image_half_width"><a href="https://www.flickr.com/photos/davidtanzer/29070472691/in/dateposted-public/"><img src="https://farm9.staticflickr.com/8647/29070472691_2526b88bc7_z_d.jpg" alt="IDEA add flow plugin" /><figcaption>IDEA add flow plugin</figcaption></a></figure></p>
<p>Install flow globally so you can easily run it from the command line. The Flow plugin we just installed needs this.</p>
<pre>
$ sudo npm install -g flow-bin
</pre><p>
And configure the flow plugin.</p>
<p><figure class="embed hide-smooth dark image_half_width"><a href="https://www.flickr.com/photos/davidtanzer/29148142975/in/dateposted-public/"><img src="https://farm9.staticflickr.com/8534/29148142975_1c6e0973ee_z_d.jpg" alt="IDEA configure flow plugin" /><figcaption>IDEA configure flow plugin</figcaption></a></figure></p>
<p>Congrats: Flow is now working in IntelliJ IDEA - Enjoy seeing JavaScript type errors right in the IDE!</p>
<p><figure class="embed hide-smooth dark image_half_width"><a href="https://www.flickr.com/photos/davidtanzer/28526490334/in/dateposted-public/"><img src="https://farm9.staticflickr.com/8231/28526490334_a3c07b53a2_z_d.jpg" alt="IDEA Flow plugin is working now!" /><figcaption>IDEA Flow plugin is working now!</figcaption></a></figure></p>
<h3>Mocha, FlowType and Gradle</h3>
<p>We also want to be able to run the flow type checks and our mocha tests from our Gradle build. There is a gradle plugin for running <a href="https://github.com/craigburke/karma-gradle">running tests with karma</a>, but again I did not use it because I could not configure it to make it work with my project setup. So I just added two tasks that run flow and mocha for me:</p>
<pre>
task checkFlowTypes(type: Exec) {
commandLine 'node', 'node_modules/flow-bin/cli'
}
task runClientTests(type: Exec, dependsOn: 'checkFlowTypes') {
commandLine 'node', 'node_modules/mocha-cli/bin/mocha', '--require', 'babel-core/register', 'src/test/javascript/setup.js', 'src/test/javascript/**/*.spec.js'
}
</pre><p>
Now you can run the checks and tests with Gradle - On your build server, for example.</p>
<h3>Fix all FlowType Errors</h3>
<p>When you run flow now, you'll see a lot of errors:</p>
<pre>
src/test/javascript/environment.spec.js:2
2: import { expect } from 'chai';
^^^^^^ chai. Required module not found
src/test/javascript/environment.spec.js:4
4: describe('the environment', () =&gt; {
^^^^^^^^ identifier `describe`. Could not resolve name
src/test/javascript/environment.spec.js:5
5: it('should at least run this test, and it should be green', () =&gt; {
^^ identifier `it`. Could not resolve name
</pre><p>
To fix them, we first have to update <strong><code>web-frontend/.flowconfig</code></strong> so it actually includes all node_modules. But then it would produce some errors because of the "fbjs" module. I don't think they are critical right now, so I set this module to ignore. We also want to ignore everything in the "build" folder, because that's auto-generated code.</p>
<pre>
[ignore]
&lt;PROJECT_ROOT&gt;/build/.*
&lt;PROJECT_ROOT&gt;/node_modules/fbjs/.*
[libs]
src/test/interfaces
</pre><p>
We have to add an interface for mocha, so that flow can type check the tests we wrote. Just add <strong><code>web-frontend/src/test/interfaces/mocha.js</code></strong>:</p>
<pre>
declare class describe {
static (description: string, spec: () =&lt; void): void;
}
declare class it {
static (description: string, spec: () =&lt; void): void;
}
</pre><p>
And now flow should be running with no errors.</p>
<pre>
$ npm run-script flow
&gt; react_spring_boot@ flow /home/david/Documents/Projects/examples/react-spring-boot/web-frontend
&gt; flow; test $? -eq 0 -o $? -eq 2
No errors!
</pre><h3>Configure babel for FlowType</h3>
<p>We also want to configure babel so it strips the flow types from our JavaScript files when running browserify - We don't need them in production mode. So I added a plugin to <strong><code>web-frontend/.babelrc</code></strong>:</p>
<pre>
{
"presets": ["es2015", "react"],
"plugins": ["transform-flow-strip-types"]
}
</pre><p>
I did not change anything in the way development mode works (loading the files with system.js), because this works out of the box (at least with Chrome).</p>
<h3>What Next?</h3>
<p>Now the basic setup works for me - I can run the tests from the build, and I see type errors in my IDE. But there are still some things missing. </p>
<p>Running the tests from the IDE is probably a very simple task. We could do more interesting things, like making our web application isomorphic - I.e. rendering all the react components on the server when loading the application. Or we could actually start to implement something - Like the client/server communication. Maybe in the next blog post ;)</p>
<p>Do you have any feedback/questions? Just <a href="mailto:Business@DavidTanzer.net?Subject=FlowType%20Mocha%20IDEA%20-%20Feedback%20/%20Questions">contact me</a>!</p>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-above"><div class="field-label">Posting Type:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/professional">David&#039;s Blog</a></div></div></div>Mon, 22 Aug 2016 05:30:41 +0000david238 at http://www.davidtanzer.nethttp://www.davidtanzer.net/spring_boot_and_react_flow_and_mocha#commentsGetting Started with React and Spring Boothttp://www.davidtanzer.net/getting_started_with_react_and_spring_boot
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>Right now, I am trying to deepen my react knowledge and skills. So I started to set up a little project where I can play around: A spring boot backend and a client application written with react and redux. You can get the whole source code on GitHub: <a href="https://github.com/dtanzer/example-react-spring-boot">dtanzer/example-react-spring-boot</a>. Here is a <strong>really detailed</strong> guide that describes what I did to make it work (and often why I did it)...</p>
<p>Note: If you just want to play around with what I did, don't repeat all my steps, <a href="https://github.com/dtanzer/example-react-spring-boot">clone my github project</a>. This guide is just here to explain why the code is how it is right now, and how all the parts play together.</p>
<h3>Basic Project Structure</h3>
<p>Nowadays I tend to split even the simplest project in multiple modules (I am using the IntelliJ IDEA jargon here) to make it easier to manage dependencies later when they grow. So my basic module structure for this project is:</p>
<pre>
react-spring-boot
+---common
+---spring-boot-webapp
\---web-frontend
</pre><p>
<strong><code>spring-boot-webapp</code></strong> is the actual application. It contains the <code>@SpringBootApplication</code> class (<code>"WebApplication"</code> in this case) and the <code>application.properties</code>. It also has a dependency on all other modules to be able to run the whole application. This allows me to keep dependencies between other modules low, and to even apply the dependency inversion principle for modules.</p>
<p><strong><code>common</code></strong> is basically a dumping ground for code that all (or most) modules need, and where I didn't find a better module name yet. I'll try to keep the code in this module to a minimum.</p>
<p><strong><code>web-frontend</code></strong> contains the Spring WebMVC <code>@Controller</code> classes, static files and javascript code.</p>
<p>Later, I will need more modules for REST APIs, backend functionality, and so on. But right now, I just want to get the react app to work, so this is enough (or maybe even over-engineered, as some would say).</p>
<p>A more complete picture of the basic structure is:</p>
<pre>
react-spring-boot
+---common
+---spring-boot-webapp
| \---src
| \---main
| +---java
| | \---net.davidtanzer.reactspringboot
| | \---WebApplication.java
| \---resources
| \---application.properties
\---web-frontend
\---src
+---main
| +---java
| +---javascript
| \---resources
| +---static
| | +---css
| | \---js
| \---templates
\---test
\---javascript
</pre><h3>Build With Gradle</h3>
<p>I want to build the application with gradle and use the gradle wrapper. This is pretty straight forward. Every module has a <code>build.gradle</code> file, and there is a global build- and settings-file.</p>
<pre>
react-spring-boot
+---common
| \---build.gradle
+---spring-boot-webapp
| \---build.gradle
\---web-frontend
| \---build.gradle
+---gradlew
+---gradle
| \---wrapper
+---build.gradle
\---settings.gradle
</pre><p>
<strong><code>settings.gradle</code></strong> only lists all the modules for now:</p>
<pre class="hljs groovy">
include 'common', 'spring-boot-webapp', 'web-frontend'
rootProject.name = 'react-spring-boot'
</pre><p>
<strong><code>build.gradle</code></strong> configures global dependencies (dependencies for all projects and for all build scripts). It is pretty simple but a little long. You can view the whole file <a href="https://github.com/dtanzer/example-react-spring-boot/blob/master/build.gradle">on github</a>.</p>
<p><strong><code>spring-boot-webapp/build.gradle</code> configures the build for the whole application.</strong></p>
<pre class="hljs groovy">
buildscript {
ext {
springBootVersion = '1.3.0.RELEASE'
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'spring-boot'
jar {
baseName = 'react-spring-boot'
}
dependencies {
compile project(':common')
compile project(':web-frontend')
compile 'org.springframework.boot:spring-boot-starter-actuator'
testCompile 'org.springframework.boot:spring-boot-starter-test'
}
</pre><p>
<strong><code>web-frontend/build.gradle</code></strong> adds the web dependencies of spring boot:</p>
<pre class="hljs groovy">
buildscript {
ext {
springBootVersion = '1.3.0.RELEASE'
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'spring-boot'
dependencies {
compile project(':common')
compile 'org.springframework.boot:spring-boot-starter'
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.springframework.boot:spring-boot-starter-thymeleaf'
}
</pre><p>
But I also want to manage my javascript dependencies with gradle. I have tried several plugins that promise to do this, but none did work for me. <a href="https://github.com/craigburke/client-dependencies-gradle">client-dependencies-gradle</a> has a <a href="https://github.com/craigburke/client-dependencies-gradle/issues/52">bug</a>, for example, where it cannot resolve dependencies that have a circular dependency. So I juss call "npm" from the command line. I have also created a task for executing "browserify" (which packs all javascript resources into a single file):</p>
<pre class="hljs groovy">
task clientDependenciesDev(type: Exec) {
commandLine 'npm', 'install', '--save', 'mocha', 'jsdom', 'react-addons-test-utils', 'chai', 'sinon', 'enzyme'
}
task clientDependencies(type: Exec, dependsOn: 'clientDependenciesDev') {
commandLine 'npm', 'install', '--save', 'react', 'react-dom', 'babelify', 'babel-core', 'babel-preset-react', 'babel-preset-es2015'
}
task browserify(type: Exec) {
commandLine 'browserify', '-t', '[', 'babelify', ']', 'src/main/javascript/main.js', '-o', 'src/main/resources/static/js/bundle.js'
}
</pre><p>
You can execute one of these tasks from the root project like this:</p>
<pre>
[david@localhost react-spring-boot]$ ./gradlew web-frontend:browserify
:web-frontend:browserify
BUILD SUCCESSFUL
Total time: 4.373 secs
</pre><h3>Frontend / React</h3>
<p>We need an index.html as a placeholder to load the react app, and the application itself (written in JavaScript):</p>
<pre>
web-frontend
\---src
+---main
| +---java
| +---javascript
| | +---headerarea.js
| | \---main.js
| \---resources
| \---static
| \---index.html
\---test
\---javascript
</pre><p>
The static <strong><code>index.html</code></strong> really just loads the react app:</p>
<pre class="hljs html">
&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div id="example"&gt;Example...&lt;/div&gt;
&lt;script src="js/bundle.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre><p>
<strong><code>main.js</code></strong> initializes the react application:</p>
<pre class="hljs js">
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import {HeaderArea} from './headerarea';
ReactDOM.render(
&lt;HeaderArea/&gt;,
document.getElementById('example')
);
</pre><p>
And <strong><code>headerarea.js</code></strong> defines our first real component, <code>&lt;HeaderArea&gt;</code>:</p>
<pre class="hljs js">
import React, { Component } from 'react';
export class HeaderArea extends Component {
render() {
return &lt;header&gt;Header...&lt;/header&gt;
}
}
</pre><h3>Run the application</h3>
<pre>
web-frontend
+---src
\---.babelrc
</pre><p>
For production, we need to bundle all javascript in the single <code>js/bundle.js</code> file, which is loaded from our <code>index.html</code>. So, before running the application, we always have to call:</p>
<pre>
[david@localhost react-spring-boot]$ ./gradlew web-frontend:browserify
</pre><p>
This command will also run babel to translate our ES2016 jsx files to something all browsers understand, so we need a <strong><code>.babelrc</code></strong>:</p>
<pre class="hljs json">
{
"presets": ["es2015", "react"]
}
</pre><p>
In intelliJ IDEA, we can automate this:</p>
<p><figure class="embed hide-smooth dark image_half_width"><a href="https://www.flickr.com/photos/davidtanzer/28625669320/in/dateposted-public/"><img src="https://farm9.staticflickr.com/8057/28625669320_3fd041f744_z_d.jpg" alt="Automatic browserify before build" /><figcaption>Automatic browserify before build / run</figcaption></a></figure></p>
<p>Now we can start the application in IntelliJ, load it in the browser, and we should see a very simple page that just contains the text "Header...".</p>
<h3>Test With Mocha</h3>
<p>Now we can add a first unit test for the web frontend. This test does not actually test some of our code yet, it just verifies that we have set up the test system correctly. The tests also need some common setup. I'll also add a shell script to run mocha (the test runner to run our frontend tests):</p>
<pre>
web-frontend
+---src
| +---main
| \---test
| \---javascript
| +---environment.spec.js
| \---setup.js
\---mocha.sh
</pre><p>
<strong><code>mocha.sh</code></strong> just runs all the mocha tests continuously. This file is only here so I don't have to remember the mocha command line...</p>
<pre class="hljs sh">
#!/bin/sh
mocha --watch --require babel-core/register src/test/javascript/setup.js src/test/javascript/*.spec.js
</pre><p>
<strong><code>setup.js</code></strong> is just <a href="https://semaphoreci.com/community/tutorials/getting-started-with-tdd-in-react">some boiler plate</a> we need to set up everything for testing react components:</p>
<pre class="hljs js">
var jsdom = require('jsdom').jsdom;
var exposedProperties = ['window', 'navigator', 'document'];
global.document = jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) =&gt; {
if (typeof global[property] === 'undefined') {
exposedProperties.push(property);
global[property] = document.defaultView[property];
}
});
global.navigator = {
userAgent: 'node.js'
};
</pre><p>
And <strong><code>environment.spec.js</code></strong> is the file that contains our first spec (or test):</p>
<pre class="hljs js">
import { expect } from 'chai';
describe('the environment', () =&gt; {
it('should at least run this test, and it should be green', () =&gt; {
expect(true).to.be.true;
});
});
</pre><p>
Running the tests now should result in exactly one green test.</p>
<h3>Development Mode / Reload from Filesystem</h3>
<p>So we already have a running application, but every time we change a javascript file, we have to re-run the browserify task and then re-start the application. This takes too much time. We want to be able to reload changed javascript files on the fly, without restarting the application.</p>
<p>Luckily, <a href="https://github.com/systemjs/systemjs">system.js</a> is a great tool <a href="http://developer.telerik.com/featured/taming-react-setup/#s3">that does everything we need</a>. But we only want to use it in development mode. In production, we still want to use our <code>js/bundle.js</code> that we create with browserify.</p>
<p>We only have to create different configurations for development and production and then create index.html dynamically so it either loads bundle.js or uses system.js.</p>
<pre>
web-frontend
\---src
+---main
| +---java
| | \---net.davidtanzer.reactspringboot.web
| | \---MainPageController.java
| +---javascript
| \---resources
| +---static
| \---templates
| \---index.html
\---test
\---javascript
</pre><p>
<strong><code>index.html</code></strong> is now a thymeleaf template that dynamically (generated on the server) selects how to load the javascript.</p>
<pre class="hljs html">
&lt;html xmlns:th="http://www.thymeleaf.org"&gt;
&lt;head&gt;
&lt;script th:if="${not bundleJavaScript}" src="https://jspm.io/system@0.19.js"&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div id="example"&gt;Example...&lt;/div&gt;
&lt;!-- ******* Load bundled javascript (for production mode) ******* --&gt;
&lt;!-- ******* or javascript modules via system.js (in development mode) ******* --&gt;
&lt;script th:if="${bundleJavaScript}" src="js/bundle.js"&gt;&lt;/script&gt;
&lt;script th:if="${not bundleJavaScript}"&gt;
System.config({
transpiler: 'babel',
babelOptions: {},
});
System.import('./main.js');
&lt;/script&gt;
&lt;!-- ************************************************************************* --&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre><p>
We need a controller class, <strong><code>MainPageController.java</code></strong> to actually set the value for the variable <code>bundleJavaScript</code></p>
<pre class="hljs java">
package net.davidtanzer.reactspringboot.web;
import net.davidtanzer.jdefensive.Returns;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.HashMap;
import java.util.Map;
@Controller
public class MainPageController {
@Value("${net.davidtanzer.webfrontend.bundledjs}")
private boolean bundleJavaScript;
@RequestMapping("/")
public ModelAndView index() {
Map&lt;String, Object&gt; model = new HashMap&lt;&gt;();
model.put("bundleJavaScript", bundleJavaScript);
return Returns.notNull(new ModelAndView("index", model));
}
}
</pre><p>
Now we have to add the configuration for development and production mode to the web application:</p>
<pre>
spring-boot-webapp
\---src
\---main
\---resources
+---application.properties
\---application-development.properties
</pre><p>
<strong><code>application.properties</code></strong> contains the default values for production:</p>
<pre>
spring.profiles.active=production.properties
net.davidtanzer.webfrontend.bundledjs=true
</pre><p>
And <strong><code>application-development.properties</code></strong> contains the overrides for development. It configures spring to load javascript files from the file system and to send a cache-control header with value "0" to the browser. Otherwise the browser would cache javascript files loaded by system.js and on-the-fly re-loading would not even work with a server restart.</p>
<pre>
spring.resources.staticLocations=file:web-frontend/src/main/javascript/,classpath:/static/
spring.resources.cache-period=0
net.davidtanzer.webfrontend.bundledjs=false
</pre><p>
To activate the development profile, you have to add <code>-Dspring.profiles.active=development</code> to the Java command line:</p>
<p><figure class="embed hide-smooth dark image_half_width"><a href="https://www.flickr.com/photos/davidtanzer/28293114234/in/dateposted-public/"><img src="https://farm9.staticflickr.com/8843/28293114234_2cdc2186a3_z_d.jpg" alt="Selecting development profile" /><figcaption>Selecting development profile</figcaption></a></figure></p>
<p>Now everything works - You can start the server, load the application, change headerarea.js, reload in the browser, and you'll see the changed texts immediately.</p>
<h3>What Next?</h3>
<p>This basic setup works well for me right now, but there are still things left to do, for example:</p>
<ul><li>Integrate redux</li>
<li>Integrate a REST backend</li>
<li>Run mocha test in the gradle build, and break the build when they fail.</li>
</ul><p>Remember: If you just want to play around with what I did, don't repeat all my steps, <a href="https://github.com/dtanzer/example-react-spring-boot">clone my github project</a>. This guide is just here to explain why the code is how it is right now, and how all the parts play together.</p>
<p>Do you have any questions? What else could I do? Is there anything I could do better? Please <a href="mailto:Business@DavidTanzer.net?Subject=React%20with%20Spring%20Boot">tell me</a>!</p>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-above"><div class="field-label">Posting Type:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/professional">David&#039;s Blog</a></div></div></div>Thu, 11 Aug 2016 12:34:58 +0000david237 at http://www.davidtanzer.nethttp://www.davidtanzer.net/getting_started_with_react_and_spring_boot#commentsWhy We'll Have Vegan Food at SoCraTes Day Linzhttp://www.davidtanzer.net/why_well_have_vegan_food_at_socrates_day_linz
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>We will have vegan food at <a href="http://socrates-conference.at/">SoCraTes Day Linz 2016</a>. OK, we will probably have a non-vegan option at some of the meals, but the default is vegan. This was one of the first things I said to our caterer and to a sponsor who might bring breakfast.</p>
<p>People who know me know that I eat - and even love - meat. So why was vegan catering so important to me?</p>
<h3>...Inclusive to the Largest Number of Contributors</h3>
<p>Our code of conduct says:</p>
<blockquote><p>A primary goal of SoCraTes Day Linz is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible.</p>
<p><a href="http://socrates-conference.at/en/code-of-conduct/">SoCraTes Day Linz Code of Conduct</a>
</p></blockquote>
<p>I always wanted to create a conference where everybody can come and where everybody feels welcome. We tried this with <a href="http://www.advanceit.io/2016/index.html">Advance IT</a> (which we had to cancel) and we are trying it here. This means we have to be very careful about not giving people a reason not to come.</p>
<p>People come to a conference because of what they can learn, because of what they can share, and because of the connections to other people they can make. I think we have that covered: The other <a href="https://www.socrates-conference.de/">SoCraTes</a> conferences around the world are great - even awesome - in all three respects, and we hope (and give our best) to bring this spirit to Linz.</p>
<p>So, I think that we can attract a lot of developers, but I also think that some things could prevent certain people - especially people from groups underrepresented in technology - from coming. And I want to avoid those things...</p>
<h3>Safety</h3>
<p>SoCraTes is a great learning experience. We want people to share what they know and learn from others. People will only share and be open to conversations when they feel safe.</p>
<p>This is why we have our <a href="http://socrates-conference.at/en/code-of-conduct/">code of conduct</a> and why we communicate it regularily through multiple channels.</p>
<p>We were already criticised because we do not define unwanted behaviour clearly enough, but I really want to keep the positive tone in our CoC. But this does not mean that we will tolerate harassment or sexualized content. If anyone thinks that there is room for interpretation in "Be welcoming, friendly, and patient." or that they can test the boundaries, we will happily expel them from the conference.</p>
<h3>Food</h3>
<p>Almost everyone in our tartet group would probably be happy with a typical Austrian "Wiener Schnitzel" or "Schweinsbraten" - and even accept fast food. But there are people who cannot or do not want to eat meat for several reasons. Others want to eat healthy food or high quality food. And we do not want to exclude them from the conference.</p>
<p>Luckily for us, there is a great restaurant at our venue, and they will cook really good vegan food for us. We will have a self-service buffet for lunch and dinner at the restaurant. We will also have a vegan breakfast.</p>
<h3>Language</h3>
<p>Almost everyone in our tartet group would probably be OK if we had the conference in German. But there are some people in Linz for whom German is not their first Language. And maybe some people from other countries want to come. And we do not want to exclude them from the conference.</p>
<p>So the main language (the greeting, facilitation and online communication) of the conference will be English. If you host a session, you can have the session in German if there are only native speakers in the audience. But we kindly ask you to switch to English if any visitor of your session would prefer English.</p>
<h3>Location</h3>
<p>Almost everyone in our tartet group would probably be OK with any venue in Linz (because I guess most of our participants will be from Linz). But it would also be great if we had some visitors from farther away. And we want to make it easy for them to come.</p>
<p>So we chose a venue near Linz Hauptbahnhof. The bus from Linz Airport and buses from Graz and Prag stop right next to the venue. There are fast train connections from Vienna, Salzburg, Munich and Nuremberg. Hotels are in walking distance or can be easily reached by tram or bus. If you come by train from Vienna or Salzburg, you might even not need a hotel at all (but then it will be a long day).</p>
<h3>Accessibility</h3>
<p>Our venue, Wissensturm, has great accessibility features. It was planned with accessibility in mind and with the help of handicapped people. You can find out more here (in German): <a href="http://www.linz.at/wissensturm/120.asp">Wissensturm Linz - Barrierefreiheit</a>.</p>
<h3>What Else Can We Do?</h3>
<p>So, what else can we do to make sure we are "inclusive to the largest number of contributors"? Please <a href="mailto:Business@DavidTanzer.net?Subject=SoCraTes%20Day%20Linz%20%22inclusive%20to%20the%20largest%20number%20of%20contributors%22">send me your suggestions</a>.</p>
<p><strong>P.S.:</strong> The <strong>ticket sale</strong> for SoCraTes Day Linz 2016 starts on August 24th, 2016, 09:00 am. Grab your ticket at <a href="http://socrates-conference.at/">socrates-conference.at</a>. To stay in touch <a href="https://twitter.com/SoCraTesAT">follow us on Twitter</a> or <a href="https://www.facebook.com/Socrates_at-1766306073645285/">like us on Facebook</a> - there we will remind you about the start of the ticket sale, so you don't miss it.</p>
</div></div></div><div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-above"><div class="field-label">Posting Type:&nbsp;</div><div class="field-items"><div class="field-item even"><a href="/professional">David&#039;s Blog</a></div></div></div>Mon, 08 Aug 2016 04:52:16 +0000david236 at http://www.davidtanzer.nethttp://www.davidtanzer.net/why_well_have_vegan_food_at_socrates_day_linz#comments