tag:blogger.com,1999:blog-34120762073930355932024-03-10T14:36:10.846-04:00Treetown Agile AdventureMy adventures in Agile Software Development and Coaching from Ann Arbor, MI.Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.comBlogger76125tag:blogger.com,1999:blog-3412076207393035593.post-28371871702223698272024-02-15T23:36:00.001-05:002024-02-15T23:36:32.862-05:00Don't know where to start on TDD?<p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjn7rj-aZnLh1960Uz7ygT_ULXhwOYjCCRU00F8ZC8NCdU37ruGxBoTLdC1IM7N_XvR0LiqHY1qpR6QFN-s-2wfRpHWB0_Li7CUhIGlhelEGrvUAXCGLUvzch80iGG5sdqtJ5Vwu5fIpX7NMJBeUW7QIMJGuDw8E7NYLzZAVwXFtGGLVPe2Hh1Tjq-c1Dg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="342" data-original-width="1134" height="97" src="https://blogger.googleusercontent.com/img/a/AVvXsEjn7rj-aZnLh1960Uz7ygT_ULXhwOYjCCRU00F8ZC8NCdU37ruGxBoTLdC1IM7N_XvR0LiqHY1qpR6QFN-s-2wfRpHWB0_Li7CUhIGlhelEGrvUAXCGLUvzch80iGG5sdqtJ5Vwu5fIpX7NMJBeUW7QIMJGuDw8E7NYLzZAVwXFtGGLVPe2Hh1Tjq-c1Dg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><a href=" https://www.linkedin.com/posts/ayalavirtual_test-driven-development-has-been-extremely-activity-7162182903563546625-XWt0" target="_blank">This post</a> got me thinking about how difficult it can be for people new to Test Driven Development to know where to start. I started writing this post as a reply to the post, but I ended up 29 characters beyond the limit, so here it is:<p></p><div><br /><div>You might start by coming up with an example of what you want your code to do, what its behavior should be. Here's an example:</div><div><br /></div></div><div><div>"When I give [specific complex input] I will get [specific output]"</div><div><br /></div><div>Then imagine this example sequence of test-writing:</div><div><br /></div><div>1. a test that asserts that I can call newCode</div><div>2. a test that asserts that calling newCode returns nothing</div><div>3. a test that asserts that calling newCode with any argument returns nothing</div><div>4. a test that asserts that calling newCode with any argument returns six (or some other dummy result)</div><div>5. a test that asserts that calling newCode with simplest argument returns the correct result</div><div>6. a test that asserts that calling newCode with more complex argument returns correct result</div><div><br /></div><div>Each test should fail when you first write it. Then you add implementation to newCode to make only that test pass. Don't add code to make future tests pass - remember, small steps. As you write implementations for subsequent tests, 1-4 will fail (maybe even to the point of not compiling). That's expected. Delete any test that is superseded by one that moves you closer to your goal.</div><div><br /></div><div>You might not get to 6 with the same steps as me, or you might gain enough TDD experience to start at 2 or 3 or 4 instead of 1. But hopefully this example shows a means of tests "driving" behavior.</div></div><div><br /></div><div><br /></div>Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-8318768922017838212023-09-01T13:05:00.001-04:002023-09-01T13:05:39.412-04:00"Don't Make Me Think" about your code.<p><span style="font-family: Arial, sans-serif;"><span style="font-size: 11pt; white-space-collapse: preserve;">Sometime after 2008 or so, I started telling software crafters that I was coaching that I have a guideline for </span><span style="font-size: 14.6667px; white-space-collapse: preserve;">code</span><span style="font-size: 11pt; white-space-collapse: preserve;"> quality: “<i>Don’t make me think.</i>” Often I used the phrase to reference one of the many well-known </span></span><a href="https://refactoring.guru/refactoring/smells" style="font-family: Arial, sans-serif; font-size: 11pt; white-space-collapse: preserve;" target="_blank">code smells</a><span style="font-family: Arial, sans-serif;"><span style="font-size: 11pt; white-space-collapse: preserve;">. Recently, I wondered where I </span><span style="font-size: 14.6667px; white-space-collapse: preserve;">first learned that</span> <span style="font-size: 14.6667px; white-space-collapse: preserve;">expression. Unfortunately, online searches are dominated by Steve Krug's 2000 UI/UX book (with editions in 2005 and 2013) by the same name.The earliest use that I could find of “Don’t make me think” as applied to code quality is a <a href="https://vinod.blog/2011/02/04/dont-make-me-think/" target="_blank">blog post from 2011</a>, If you know of an earlier use, please get in touch.</span></span></p><p><span style="font-family: Arial, sans-serif;"><span style="font-size: 14.6667px; white-space-collapse: preserve;">As I thought more about "Don't make me think", I've come up with many examples. Here's my list so far. What's your favorite?</span></span></p><p style="text-align: left;"></p><ol style="text-align: left;"><li><span style="font-family: Arial, sans-serif;"><span style="font-size: 14.6667px; white-space-collapse: preserve;">Have a readme that tells me how to run tests and install and run your application</span></span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Use a test naming convention that gives the action, initial state, and expected state.</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Name things well</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">When possible, use the names that are the same as in the business domain</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">No commented-out code</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">No comments, except to explain something that you have to do in an unexpected way (Debunk “good” comments)</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Unless you squash, have meaningful commit messages. If you squash, have meaningful merge messages.</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Write short methods</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Write with idiomatic use of your language</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Don’t write “clever” code</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Don’t over architect or over generalize</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Have sufficient types and amounts of automated tests</span></li><li><span style="font-family: Arial, sans-serif;"><span style="font-size: 14.6667px; white-space-collapse: preserve;">Maintain your tests as you maintain the rest of your code</span></span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Methods should have few arguments, and probably no boolean arguments.</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">The interface of a class should “hang together” without methods that “don’t belong”</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Avoid “primitive obsession”</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Find solutions besides switch statements</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Don’t go crazy with inheritance. Prefer composition.</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Use a rich domain model, not an anemic one.</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Avoid conditional nesting</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Avoid subclassing unless you need all (or most) of the parent class (avoid Refused Bequest)</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Declare things where they are used.</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Arrange Act Assert</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">One assert/concept per test</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Avoid double negation</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Use a Formatting Convention</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Short feedback cycles</span></li><li><span style="font-family: Arial, sans-serif; font-size: 14.6667px; white-space-collapse: preserve;">Don’t mix levels of abstraction</span></li></ol><p></p><p></p><div><br /></div><p><span style="font-family: Arial, sans-serif;"><span style="font-size: 14.6667px; white-space-collapse: preserve;"><br /></span></span></p><p><br /></p>Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-47467893210936034132020-09-29T17:17:00.000-04:002020-09-29T17:17:43.213-04:00Rough Post - Styles of Pair Programming<p>This post is probably a little rough, but I wanted to get it out, so here it is:</p><p><br /></p><p><a href="https://martinfowler.com/articles/on-pair-programming.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Fowler’s article</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> on pair programming lists four "styles" of pair programming:</span></p><span id="docs-internal-guid-390e504f-7fff-21d1-d9a0-4ce5d5e06deb"><ul style="margin-bottom: 0; margin-top: 0;"><li dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Driver and Navigator</span></p></li><li dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Ping Pong</span></p></li><li dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Strong-Style Pairing</span></p></li><li dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Pair Development</span></p></li></ul><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">and then goes on to throw out Pair Development as not being a style. Ping-Pong to me is totally a different style from anything else. There are also "Evil Pair Partner" and “Silent Ping Pong”, which are variants of PingPong, so I'd say there are three styles related to Ping Pong.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Fowler doesn't list "Just Pairing” as a style. Likewise, I can’t see the difference between “Just Pairing” and D/N - I consider them different names for the same one style.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The rule of Strong Style from </span><a href="https://llewellynfalco.blogspot.com/2014/06/llewellyns-strong-style-pairing.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Llewellyn Falco</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and Clare Macrae is: "For an idea to go from your head into the computer it </span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">must</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> go through someone else's hands". I'll restate this as "Driver </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">may not type their own ideas</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">; driver must only type the navigator's ideas." That sounds like D/N with a restriction, so maybe a separate style.</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">All that said, I’m seeing five distinct styles:</span></p><br /><ul style="margin-bottom: 0; margin-top: 0;"><li dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Driver and Navigator aka “Just Pairing”</span></p></li><ul style="margin-bottom: 0; margin-top: 0;"><li dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: circle; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Strong Style </span></p></li></ul><li dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Ping Pong</span></p></li><ul style="margin-bottom: 0; margin-top: 0;"><li dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: circle; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Evil Pair Partner (more for practice, not writing prod code)</span></p></li><li dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: circle; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Silent Ping Pong (more for practice, not writing prod code)</span></p></li></ul></ul><br /><br /></span>Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-91078068483494656472019-06-22T11:52:00.001-04:002019-06-22T11:52:15.547-04:00Bangle - Next StepsI haven’t solved the bridging issue yet, so I’ve started printing the first of two cut-down halves to see if I can glue them together seamlessly. (CA/Superglue is said to be good for this).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi52x07MoWrSMp_MgkhWxpD03-XNNTeZEfH02g4J9XsNYONbAixLbg5us4r-gyUGDlGSD8s8TPBxscSVJBTrncBkLDo-YC5ikgfVDOFNRljRqqysouE-KimpyeXrtXufuwO6W8OYfz1gTQ/s1600/Screen+Shot+2019-06-22+at+11.42.55+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="629" data-original-width="1600" height="125" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi52x07MoWrSMp_MgkhWxpD03-XNNTeZEfH02g4J9XsNYONbAixLbg5us4r-gyUGDlGSD8s8TPBxscSVJBTrncBkLDo-YC5ikgfVDOFNRljRqqysouE-KimpyeXrtXufuwO6W8OYfz1gTQ/s320/Screen+Shot+2019-06-22+at+11.42.55+AM.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://www.amazon.com/gp/product/B0761PMW3X/ref=ppx_yo_dt_b_asin_title_o00_s00">Here's the filament I chose</a>. It's non-metalic PLA but looks a lot like copper:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWsRUHS8ZOJgR68kGFl4YPiHS2HCz_HIcUxTFWMmLTXA8cLKd8X5z7G6Xjhy8tOGYxZoHhXUVOQqT7Y3te1p2im2Do54Jm_e5v9nkhL6OHqFoYXop-vq6IFzFC_jQAiwwQhrVc1kbzqk0/s1600/IMG_3561.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWsRUHS8ZOJgR68kGFl4YPiHS2HCz_HIcUxTFWMmLTXA8cLKd8X5z7G6Xjhy8tOGYxZoHhXUVOQqT7Y3te1p2im2Do54Jm_e5v9nkhL6OHqFoYXop-vq6IFzFC_jQAiwwQhrVc1kbzqk0/s320/IMG_3561.JPG" width="240" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
If the result of gluing the two cut-down halves is good, I'll sand the inner diameter to make it a comfortable thing bangle, then print two full halves in copper and try gluing them. If gluing doesn't end up being a good solution, I'll have to solve the bridging issue, perhaps with supports, or with tweaking print/extrusion/fan speeds.<br />
<br />
<br />Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-64116283995280196042019-06-15T11:06:00.002-04:002019-06-15T11:24:52.418-04:00Designing and 3D Printing a Chunky Bangle<h3>
Initial Concept</h3>
My wife likes big, chunky jewelry, so I thought I would try and 3D print something for her. I started with this as a basic idea:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyoPHd_gYt8JPmn4gLO7MKR0AdHuKRLEVN7o8jbYCRu78Av8p-zDf647Ip27FRN20xNUO9wz8oe7IV_cHCEDbPWLi9czNf9E-Z0s8Ex3crDLnREEP0VXBVX2sSoUPVogkkqsMnrYc-UDU/s1600/Screen+Shot+2019-06-11+at+8.22.52+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="739" data-original-width="1600" height="147" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyoPHd_gYt8JPmn4gLO7MKR0AdHuKRLEVN7o8jbYCRu78Av8p-zDf647Ip27FRN20xNUO9wz8oe7IV_cHCEDbPWLi9czNf9E-Z0s8Ex3crDLnREEP0VXBVX2sSoUPVogkkqsMnrYc-UDU/s320/Screen+Shot+2019-06-11+at+8.22.52+PM.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
This bangle looks to be in 3 pieces. My wife has similar multiple-part bangles. The pieces are held together with elastic. It allows for a smaller inner diameter, but the elastic is a potential point of failure. My wife also has one-piece bangles that she can slide her hand into, so I figure I can make a one-piece for her.<br />
<br />
<h3>
Tools</h3>
<b>Printer</b>: I have access to a Prusa i3 MK3, the predecessor to the <a href="https://shop.prusa3d.com/en/51-original-prusa-i3-mk3s">MK3S</a>.<br />
<br />
<b>Modeling</b>: <a href="http://www.openscad.org/">OpenSCAD</a> - open source, "The Programmers Solid 3D CAD Modeller". Unlike traditional CAD apps that rely on drawing and/or moving around shapes, in OpenSCAD, you build designs by writing lines of OpenSCAD language code (<a href="https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Commented_Example_Projects">some examples</a>) Once you have a design in OpenScad, you have the software render it and export it in STL format.<br />
<br />
<b>Slicing / exporting gcode</b>: Prusa has <a href="https://www.prusa3d.com/prusaslicer/">their own version</a> of the popular open source app, Slic3r. Slicing is the process of taking a 3D model (usually an STL file) and converting it to a stack of slices that a printer can print, one on top of the other, to create the object. <a href="https://www.reprap.org/wiki/G-code">Gcode</a> is the low-level instruction language used by printers to control the motions of the bed, the extruder, the arms and so on. Exporting gcode is the process of taking slices and converting them into those low-level instructions<br />
<br />
<br />
<h3>
Iteration 1:</h3>
Design a basic ring-ish shape. The easiest way I found was to design a disk and subtract from it a disk of same thickness but smaller diameter, centering the disks on each other. It looked like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMzeRxx_R6zEHwedCfzM3palU2vjeQpsGINMqf0gmMMhu0dWNJF4hpvnQcV_DpiEYCNUxuFkjtPs7ZLg4yB08yRR2cV8_oWiFAqlgfALq4uvp9O88kh_HQihGV5BF93iiS3O-oxIPx5Sg/s1600/b2d2a44224782ebaf52b1ea095fb9367_preview_featured.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="472" data-original-width="628" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMzeRxx_R6zEHwedCfzM3palU2vjeQpsGINMqf0gmMMhu0dWNJF4hpvnQcV_DpiEYCNUxuFkjtPs7ZLg4yB08yRR2cV8_oWiFAqlgfALq4uvp9O88kh_HQihGV5BF93iiS3O-oxIPx5Sg/s320/b2d2a44224782ebaf52b1ea095fb9367_preview_featured.jpg" width="320" /></a></div>
<br />
<br />
<h3>
Iteration 2:</h3>
I wanted to improve the ring design from a harsh geometric shape into the first inkling of a bracelet design. This involved learning to rotate a 2-D circle in 3-space around an axis, using the <a href="https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Using_the_2D_Subsystem#Rotate_Extrude">rotate_extrude()</a> function. The result looked like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv_iKXJSZAwhr0Lkvuk7uoeKlmw9FBwctLECMkzNxgOpB8EXT38bDwprjCHniUqxdqTCIj_dybSvtBwhPPp380BirzKCIm_Q7AxIPW2fECsHxxYSkP5vimUpTRLNKh0h3X9aKOIqDJ7g8/s1600/658042f43f36372959296894424afab1_preview_featured.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="472" data-original-width="628" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv_iKXJSZAwhr0Lkvuk7uoeKlmw9FBwctLECMkzNxgOpB8EXT38bDwprjCHniUqxdqTCIj_dybSvtBwhPPp380BirzKCIm_Q7AxIPW2fECsHxxYSkP5vimUpTRLNKh0h3X9aKOIqDJ7g8/s320/658042f43f36372959296894424afab1_preview_featured.jpg" width="320" /></a></div>
<br />
<h3>
Iteration 3:</h3>
To create the first printed prototype, I reduced the thickness of the bracelet design, keeping the diameter. Thinness causes a quicker print and uses less plastic. Took about 40 minutes to print. (No pic)<br />
<br />
<h3>
Iteration 4:</h3>
Discover that diameter of first physical prototype is about 1/3 of useful bracelet diameter. Scale design to 300% and print again. When my wife put it on, it was a little too big, I decided to measure a favorite bracelet of hers and use its inner diameter (ID), 65 mm, for my design. Going back to the Iteration 1 design, I quick-printed something with the 65 mm ID. Holding it up against the favorite bangle, the ID matched. My wife put it on and called the fit perfect. So, I had confirmed the final ID. (No pics)<br />
<br />
<h3>
Iteration 5:</h3>
Learn to go from circular cross-section to something more complex.<br />
First, I set out to relearn parabolas:<br />
<br /><a href="https://www.symbolab.com/solver/parabola-equation-calculator">https://www.symbolab.com/solver/parabola-equation-calculator</a><br /><a href="https://www.mathwarehouse.com/geometry/parabola/">https://www.mathwarehouse.com/geometry/parabola/</a><br /><a href="https://www.mathwarehouse.com/quadratic/parabola/interactive-parabola.php">https://www.mathwarehouse.com/quadratic/parabola/interactive-parabola.php</a><br /><a href="https://www.mathwarehouse.com/geometry/parabola/standard-and-vertex-form.php">https://www.mathwarehouse.com/geometry/parabola/standard-and-vertex-form.php</a><br /><a href="https://www.desmos.com/calculator/dz0kvw0qjg">https://www.desmos.com/calculator/dz0kvw0qjg</a><br /><a href="https://www.omnicalculator.com/math/parabola#how-to-use-the-parabola-equation-calculator-an-example">https://www.omnicalculator.com/math/parabola#how-to-use-the-parabola-equation-calculator-an-example</a><br /><a href="https://www.desmos.com/calculator/mey71rif1d">https://www.desmos.com/calculator/mey71rif1d</a><br /><pre class="a-b-r-La" style="overflow-wrap: break-word;"></pre>
<br />I created a curve that I liked. It turned out to be Y = 0.3*(x-6.1)^2 + c.<br />
<br />
<div>
<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="272" data-original-width="394" height="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfaYkYnsMjCYvjGiTTyGbUbohrXyVpIrKQlV2GnxSOCRo-1yZB9PfUhe7xskjN7axR5bKcjlH95ijunSOaW0lUA7inMgukiz2T8FCws4Kk30Xvjhd3bTlO8ej2dET1KR9Ng2uafMBcoh4/s320/Screen+Shot+2019-06-11+at+9.05.10+PM.png" width="320" /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Then I enclosed the curve into a shape with a perimeter and area:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD2wl1pbUkKoAzSQ5D3Qlz-wjyZ2lKvl4dXQi52EC13oTTvHn8hB3ZB2PNa8HOabjIpNtwS2tC64tJE8pE_IeCm64U-f9HXpGH_BGBiZfL5yA3bIo_ZtnmWAdkAVIaMiAWc7UtaWNfsfk/s1600/Screen+Shot+2019-06-11+at+9.05.10+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="272" data-original-width="394" height="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD2wl1pbUkKoAzSQ5D3Qlz-wjyZ2lKvl4dXQi52EC13oTTvHn8hB3ZB2PNa8HOabjIpNtwS2tC64tJE8pE_IeCm64U-f9HXpGH_BGBiZfL5yA3bIo_ZtnmWAdkAVIaMiAWc7UtaWNfsfk/s320/Screen+Shot+2019-06-11+at+9.05.10+PM.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Then I plugged some points into the equation and added 3 corners. It was simple to turn those points into a polygon call in OpenSCAD (in a future iteration, I would calculate and add more points in between these points, to smooth out what was a faceted curve:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both;">
polygon(points=[[6.0, 0.000],</div>
<div class="separator" style="clear: both;">
[5.5, 0.108],</div>
<div class="separator" style="clear: both;">
[5.0, 0.363],</div>
<div class="separator" style="clear: both;">
[4.5, 0.768],</div>
<div class="separator" style="clear: both;">
[4.0, 1.323],</div>
<div class="separator" style="clear: both;">
[3.5, 2.028],</div>
<div class="separator" style="clear: both;">
[3.25, 2.773],</div>
<div class="separator" style="clear: both;">
[3.0, 3.518],</div>
<div class="separator" style="clear: both;">
[3.0, 0.000]</div>
<div class="separator" style="clear: both;">
]);</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div>
The rotate_extrude() call stands up a shape and rotates it around the z axis. Applying this to my polygon resulted in a shape like a volcano:</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimkMd5iyMMNRSlJ203NTY9FBW-71AYHV8bWFY7HHmDDXPjPwY68SbcDWdOeW5AGEbj3YBifDIUKmstf3PpBEb1mxCthTTqmehlyQO2cbKqBUm64n1Vl9Fz7Wvove9wE2gYEr4A8epS2M0/s1600/zScreen+Shot+2019-06-05+at+9.53.34+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="430" data-original-width="1348" height="102" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimkMd5iyMMNRSlJ203NTY9FBW-71AYHV8bWFY7HHmDDXPjPwY68SbcDWdOeW5AGEbj3YBifDIUKmstf3PpBEb1mxCthTTqmehlyQO2cbKqBUm64n1Vl9Fz7Wvove9wE2gYEr4A8epS2M0/s320/zScreen+Shot+2019-06-05+at+9.53.34+PM.png" width="320" /></a></div>
<br />In OpenSCAD, I duplicated the "volcano", fliped it 180 degrees, and lined the duplicate up with the base of the original:<br /><br /><div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="754" data-original-width="1600" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggr9bsdQVt603gYXtIjq6kayxQepUhS7Nrs_WPGUkO64M5ZlVybHycVInCat5pPNxZTRLVx57xmtV4x9U_feyd9wpNvrx6CVx7ycRSatQvaz5bjabmrq309fnUtkp224Hk0yLunwJ1rK8/s320/Screen+Shot+2019-06-11+at+9.33.54+PM.png" width="320" /></div>
<pre class="a-b-r-La" style="background-color: white; overflow-wrap: break-word; user-select: text;"><span style="font-family: "times";"><span style="white-space: normal;">
</span></span><span style="font-family: "times"; white-space: normal;"><div class="separator" style="clear: both; text-align: center;">
</div>
</span></pre>
<div class="separator" style="clear: both;">
<br />I showed the double-volcano model to my wife for her blessing, which I received. A first real physical prototype is in sight.</div>
<h3>
Iteration 6:</h3>
<br />
<div class="separator" style="clear: both;">
I decided to test-print only one volcano, just to have something to handle before committing to the whole print (which the slicing software projected would take 13 hours at 7% infill). It turned out that because of the nature of the curve I chose, the edges taper to a very thin edge are are not comfortable to wear:<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7QPH-NFGt_Vjmgul2nkmVJcg28mTPs5ZxdCIpmsdAuuLiP1EsTKAEPuYDCrUrLVGlIgF2LRskFQIo2hJ6mLjS3t-nG1nYCqhi633dZUp4pOiH7eq6xgfepsMeiF5vvhdZTGPMsU2WJh4/s1600/SqUqxcTH.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1072" data-original-width="1529" height="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7QPH-NFGt_Vjmgul2nkmVJcg28mTPs5ZxdCIpmsdAuuLiP1EsTKAEPuYDCrUrLVGlIgF2LRskFQIo2hJ6mLjS3t-nG1nYCqhi633dZUp4pOiH7eq6xgfepsMeiF5vvhdZTGPMsU2WJh4/s320/SqUqxcTH.jpg" width="320" /></a></div>
<pre class="a-b-r-La" style="background-color: white; overflow-wrap: break-word; user-select: text;"></pre>
<h3 style="overflow-wrap: break-word;">
<br />Iteration 7:<br /><br /><span style="font-weight: normal;"><span style="font-size: small;"><span style="font-family: "times";">I decided I needed to find some way to smooth the sharp edges and reduce/eliminate the faceting artifacts shown above. I had already figured out how to reduce the faceting down the face of the "volcano" by using more points to express the curve that became the polygon that was rotated through space. The faceting around the perimeter turned out to be easy - I had to add an extra argument, </span><a href="https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features#.24fa.2C_.24fs_and_.24fn" style="background-color: transparent;">$fn=360</a><span style="background-color: transparent;">, (number of fragments) to the rotate_exclude() call. Of course, the extra computation changed the rendering and slicing time from seconds to several minutes. I smoothed the lips edges of the volcano by smoothing the polygon itself using the </span><a href="https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#offset" style="background-color: transparent;">offset()</a><span style="background-color: transparent;"> function before the rotate_extrude() call. The resulting model looked like this:</span></span></span><br />
<span style="font-weight: normal;"><span style="font-size: small;"><span style="background-color: transparent;"><br /></span></span></span></h3>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgURqziq3pmauK8rugLKTB8j3-Y5F4NoxyUxXnVESmHpWEVhbsyRRtkRhjqNm3SZZ5urxtXLfZKdQRJ2F1YJHam5q3x4s71FL92-Tlzshy0czZOe5iZ821e0__bSGzV4qI-BnYqEoBXtfQ/s1600/Screen+Shot+2019-06-02+at+11.58.51+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1263" data-original-width="1600" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgURqziq3pmauK8rugLKTB8j3-Y5F4NoxyUxXnVESmHpWEVhbsyRRtkRhjqNm3SZZ5urxtXLfZKdQRJ2F1YJHam5q3x4s71FL92-Tlzshy0czZOe5iZ821e0__bSGzV4qI-BnYqEoBXtfQ/s320/Screen+Shot+2019-06-02+at+11.58.51+PM.png" width="320" /></a></div>
<div>
<br /></div>
I started to print, but not long after it started, the print separated from the bed. I suspected that there was not enough surface area on the bed, so I stopped the print and restarted it with a 15mm brim (seen below) After 13.5 hours, the first "real" prototype print looked like this:</div>
<div>
<br /><pre class="a-b-r-La" style="background-color: white; overflow-wrap: break-word; user-select: text;"><span style="font-family: "times";"><span style="white-space: normal;">
</span></span></pre>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwRO4QfWrrySz-bvvb0u5YRlDx9ex0wi2WWKOoxAhqcitc44NLrfzzzIIKXgjTGq28MBS5qmxLkz3DNS1HeHrWzCVlI8-pGkG4lfxOL-SWROlX7cJ4Ik6IyEkUdFnDFSHRq3QAyKCy6Yw/s1600/done.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1024" data-original-width="768" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwRO4QfWrrySz-bvvb0u5YRlDx9ex0wi2WWKOoxAhqcitc44NLrfzzzIIKXgjTGq28MBS5qmxLkz3DNS1HeHrWzCVlI8-pGkG4lfxOL-SWROlX7cJ4Ik6IyEkUdFnDFSHRq3QAyKCy6Yw/s320/done.jpg" width="240" /></a></div>
<div class="separator" style="clear: both;">
<br /></div>
<div>
<br /><br />But the print had some issues:<br /><br /><br /><div style="text-align: center;">
<img border="0" data-original-height="1024" data-original-width="768" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheYkzSxsLpXJtH8OgB_bfrwJAlomMQOLLfq6d2pHF5-k9YSvM7LTZT4ATdT_VSZB6lvKY4dqt62ldBCTvR8svJusuY2RasCxlAXXKmgD9zlvQppvSUSD8R6mobfldgjHDOkEoRDIapJzU/s320/img_3522_1024.jpg" width="240" /></div>
</div>
<div style="text-align: center;">
<br /></div>
<br />
<div style="text-align: center;">
<br />
<div style="text-align: left;">
It might be because the sharp angle of the base of the upside-down volcano extends out too far for support good bridging. There are lots of ways to address <a href="https://all3dp.com/2/bridging-3d-printing-tips-tricks-for-perfect-bridges/">bridging issues</a>. But before I tried any of those, I noticed that the model had a weird asymmetry. Displaying each volcano in a different color: </div>
<br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheco0bk5Z0Eru24sqGWJTlBljDvZHN6wFo8JSgbe-ZUKLF_k6xgZJsfBUPUXV8kGTmuHMLA7dqUt1FE3wiA7FGANShPuClV9JFPNUpyendDCo_eWsH2Lx39APOZEDrQffoYgatKpuPwy8/s1600/wScreen+Shot+2019-06-05+at+9.43.39+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="776" data-original-width="1402" height="177" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheco0bk5Z0Eru24sqGWJTlBljDvZHN6wFo8JSgbe-ZUKLF_k6xgZJsfBUPUXV8kGTmuHMLA7dqUt1FE3wiA7FGANShPuClV9JFPNUpyendDCo_eWsH2Lx39APOZEDrQffoYgatKpuPwy8/s320/wScreen+Shot+2019-06-05+at+9.43.39+PM.png" width="320" /></a></div>
<div style="text-align: left;">
<br />
and shifting one of the volcanos along the x-axis make the asymmetry more obvious:<br />
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpI-Omgp32ZxzBBNvx2SnGhGyP-aALt9mQEyrFfKd87K45Y2jHR8m-dhCzRJpL1CmF_zHARjYzFDViMsbi7VwzXbBKsWcWhO0HfLl_D4jK4TznvS6SdY_WfWKFdKN3GkQ1rlOC6F2pLPI/s1600/wScreen+Shot+2019-06-05+at+9.26.46+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="721" data-original-width="1600" height="144" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpI-Omgp32ZxzBBNvx2SnGhGyP-aALt9mQEyrFfKd87K45Y2jHR8m-dhCzRJpL1CmF_zHARjYzFDViMsbi7VwzXbBKsWcWhO0HfLl_D4jK4TznvS6SdY_WfWKFdKN3GkQ1rlOC6F2pLPI/s320/wScreen+Shot+2019-06-05+at+9.26.46+PM.png" width="320" /></a></div>
<div style="text-align: center;">
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
It turns out that before I used the offset(), the two halves would remain on the z plane when one was turned upside-down. But adding the call resulted in one of the volcanos impinging across the z-plane. Could the impingement be responsible for the defect?</div>
<br />
<br /><h3>
Iteration 8:</h3>
</div>
<div>
I moved the offset()'ed volcanos so their bases both sit on the the z-plane, but that resulted in a "bumpy" circumference, so I didn't print it - it needed more adjustment:<br /><pre class="a-b-r-La" style="background-color: white; overflow-wrap: break-word; user-select: text;"><span style="font-family: "times";"><span style="white-space: normal;">
</span></span></pre>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCqNJGBiOMRJsNxspmLHOp2HzRgS-sbbZZyf7Ivo9iU7pFwQSjGTliz_KeAgM9O1NQ0VvZAaJwXxVENPmkh4r9jdDQEtHcfobgCS5UpEw3vdp9QoYH3pFQG8c4OXhTxMYqvyJP480epec/s1600/iScreen+Shot+2019-06-05+at+10.02.15+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="614" data-original-width="1600" height="122" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCqNJGBiOMRJsNxspmLHOp2HzRgS-sbbZZyf7Ivo9iU7pFwQSjGTliz_KeAgM9O1NQ0VvZAaJwXxVENPmkh4r9jdDQEtHcfobgCS5UpEw3vdp9QoYH3pFQG8c4OXhTxMYqvyJP480epec/s320/iScreen+Shot+2019-06-05+at+10.02.15+PM.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<h3 style="clear: both; text-align: left;">
Iteration 9:</h3>
<div>
By making each volcano cross the z-axis an equal amount, I got to this:<br />
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgui4TNDCEmpKIaT2mLH8kBMPuCLTE2LSqL2P9UCI4z3NIoEMYy9Dir8O1wr-SYLdueDekkvzThSYPnkp96CjaDXHW7bDOOcWAt3HJrt7YvJhbJqayfHJTKdU1ACMrEdfbkjkWHtk1rL-Q/s1600/pScreen+Shot+2019-06-05+at+10.10.57+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="612" data-original-width="1600" height="122" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgui4TNDCEmpKIaT2mLH8kBMPuCLTE2LSqL2P9UCI4z3NIoEMYy9Dir8O1wr-SYLdueDekkvzThSYPnkp96CjaDXHW7bDOOcWAt3HJrt7YvJhbJqayfHJTKdU1ACMrEdfbkjkWHtk1rL-Q/s320/pScreen+Shot+2019-06-05+at+10.10.57+PM.png" width="320" /></a></div>
<div>
To determine whether there is a bridging issue, but not have to print the entire 13.5 hours, I "chopped off" some of the top and bottom of the model (by intersecting it with a box)</div>
<div>
<br /></div>
<div>
I printed iteration 9 and the bridging issue remains:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOY-GVtMj_LGWhyphenhyphenKW8LtJs837abFduOBgDP4atSv7GZ7rt_UvvnvcGTQ4WrjcxcLi5ZMs7W4PdWFpMPFBSGF2NAaKTtXD5T7d4j3DNZ4tYvGasNfLGSpF1IT95kCPilD2wYZTnM5K4INI/s1600/IMG_3547.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOY-GVtMj_LGWhyphenhyphenKW8LtJs837abFduOBgDP4atSv7GZ7rt_UvvnvcGTQ4WrjcxcLi5ZMs7W4PdWFpMPFBSGF2NAaKTtXD5T7d4j3DNZ4tYvGasNfLGSpF1IT95kCPilD2wYZTnM5K4INI/s320/IMG_3547.JPG" width="240" /></a></div>
<br />
So, next is figuring out how to fix it.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<pre class="a-b-r-La" style="background-color: white; overflow-wrap: break-word; user-select: text;"></pre>
<pre class="a-b-r-La" style="background-color: white; overflow-wrap: break-word; user-select: text;"></pre>
<br /></div>
Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-55862817883826306712018-03-05T12:49:00.001-05:002018-03-05T12:49:13.550-05:00Etiquette for Pair ProgrammingIn August, my article on <a href="http://aspetraining.com/resources/blog/etiquette-for-pair-programming">Etiquette for Pair Programming</a> was published on the <a href="http://aspetraining.com/resources/blog/etiquette-for-pair-programming">ASPE Training blog</a>!<br />
<br />Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-50298594539912416322017-02-13T13:14:00.001-05:002017-02-13T13:14:36.195-05:00TDD Amazon Alexa / Echo Skills ?While TDD and unit testing <a href="http://softwareengineering.stackexchange.com/a/59938/49877">are different things</a>, TDD often relies on a unit testing framework. I have found no articles about TDDing Amazon Alexa a skill, but here are 3 about unit testing a skill:<br />
<br />
<br />
<ul>
<li><a href="https://medium.com/@jjbskir/unit-testing-an-amazon-alexa-skill-with-node-js-and-jasmine-98982544471f">Unit Testing an Amazon Alexa-Skill with Node JS and Jasmine</a></li>
<li><a href="https://bespoken.tools/blog/2016/10/10/unit-testing-alexa-skills">Unit Testing Alexa Skills</a></li>
<li><a href="https://www.bignerdranch.com/blog/developing-alexa-skills-locally-with-nodejs-setting-up-your-local-environment/">Developing Alexa Skills Locally with Node JS - Setting up your Local Environment</a></li>
</ul>
Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-4538782556926572342016-12-13T13:48:00.003-05:002016-12-13T13:48:34.610-05:00Things an "Expert" C Developer Knows: Undefined BehaviorThis is the first post in my series: <i>Things an "Expert" C Developer Knows</i><br />
<i><br /></i>
<br />
The 2016 <a href="http://www.cert.org/secure-coding/products-services/secure-coding-download.cfm">SEI CERT C Coding Standard [free download]</a> gives this definition of <b>Undefined Behavior</b>:<br />
<blockquote class="tr_bq">
<i>Behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which the C Standard imposes no requirements.</i></blockquote>
An example of an action that causes undefined behavior is signed integer overflow. Professor John Regehr at U of Utah has a <a href="http://blog.regehr.org/archives/213">blog post</a> that gives several possible examples of what C compilers *could* do with this C statement in a program:<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">printf ("%d\n", (INT_MAX+1) < 0);</span></blockquote>
The possibilities Regehr lists include printing 0, 1, 42 or formatting your hard drive. While the latter won't actually happen, undefined behavior can cause data corruption and/or security vulnerabilities.<br />
<br />
The CERT C Coding Standard lists. in Appendix C, all undefined behaviors in the current C standard: <a href="http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=57853">C11</a> (more formally known as: ISO/IEC 9899:2011) There are 203.<br />
<br />
Since I've mentioned the C11 standard here, I should probably have a <i>Things an "Expert" C Developer Knows</i> post about C standards.<br />
<br />Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-15163915959338961242016-12-13T12:49:00.002-05:002016-12-13T12:49:52.728-05:00Things an "Expert" C Developer Knows...In January, my engagement with my current client will be taking a real change in direction. Rather than being a software craftsmanship coach, I will be joining a large team as an embedded C developer.<br />
<br />
In that vein, I submitted a talk to my employer's internal conference in February about things that developers need to know if they are going to say they *really* know C.<br />
<br />
In preparation for that, watch for a series of posts from me on: "Things an "Expert" C Developer Knows"Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-68844153229159492512016-11-15T22:25:00.001-05:002016-11-15T22:25:57.637-05:00Always TDD? But Certainly Not for Startups, Right?<br />
I just read "<a href="https://www.linkedin.com/pulse/uncle-bob-smoking-his-socks-joe-rounceville">Uncle Bob is Smoking His Socks</a>", in which the author, Joe Rounceville, starts by taking issue with Uncle Bob's statement that you are not a professional software developer if you don't TDD. I understand how that statement makes people bristle. Rounceville goes on to suggest that there are contexts (in particular lean startup) that don't merit TDD. He goes as far as to suggest that TDD in that context might be "gold plating."<br />
<br />
Of course, startups need to be ultra-agile and able to get fast feedback on experiments by getting work out in front of customers rapidly. There's an element of racing against time when a company has to achieve success with only a certain amount of capital to burn through. Startups need to be able to pivot quickly in response to what they learn in their experiments.<br />
<br />
But people who argue against "always TDD" seem to think that they save time up front by not using TDD. Among experienced TDD developers, I have not found that to be the case. And well test-driven code allows for rapid pivots because it's easy to understand and different concerns in the code are not tangled-up among each other.<br />
<br />
Another risk for startups that decide not to TDD is that prototypes tend to be pushed into production as-is. Many young companies have met serious pains when their initial rushed-to-market release could not handle the load that came with the product's rapid success. And there's the old saw that if you don't have the time to write it correctly the first time, you are not going to have the time to re-write it later.<br />
<br />
The relationship between TDD and startups is tricky. Learning TDD takes time. It's not a simple matter to start using TDD if you aren't good at it. Developing software with TDD when you are new to it is slower than developing without TDD. There is a non-trivial learning curve. As a developer, I would not want to try to get good at TDD while working for a startup. And I personally would not want to join a startup if I wasn't already strong in TDD. And because of the ever-changing nature of the market, if I have a startup idea and I want to get good at TDD before starting on it, I'm likely to miss my window of opportunity. And if I develop my startup without TDD, I'm likely to end up with a hard to change and hard to maintain project that's prone to defects. So while Uncle Bob's statement about "always TDD" may sound dogmatic, I find the statement that "startups don't need / can't afford TDD" to be false.<br />
<br />
<br />Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-54673765877635324052016-10-19T17:31:00.002-04:002016-10-19T17:31:46.567-04:00The Importance of Saying "I don't know and..."As a technical coach, especially when I am embedded in a team, it is hard to overemphasize the importance of using the phrase "I don't know," plus "let me go find out." or "I'll ask someone who I think can help us."<br />
<br />
Being able to say "I don't know" is an important skill for developers if they want to be on a high-performing team. Without it, the team risks creating an environment of fear and delayed learning. So when I say "I don't know ..." as a coach, I am modeling behavior that will help devs succeed. And adding the second phrase models taking initiative. While many, perhaps most, devs are good at finding answers to things they don't know, there can still be cultural and other reasons why a developer might not step out of their usual domain.<br />
<br />
If you have coaching responsibilities, either formal or informal, and you don't say "I don't know..." maybe ask yourself if you are missing an opportunity to model important behavior.Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-63592086671042477622016-10-11T11:39:00.000-04:002016-10-11T11:39:16.983-04:00Guest Post: Thoughts on Re-evaluating Spring as a Framework for Building Well Maintainable ApplicationsI'm hosting this post for Brandon Zeeb, another software craftsman at Pillar<br />
<br />
<h2>
Thoughts on Re-evaluating Spring as a Framework for Building Well Maintainable Applications</h2>
<br />
Spring Boot is good for the general populous. Not sure I’d recommend it for any greenfield development.<br />
<br />
Spring Boot wraps up a lot of auto configuration that most developers, in my experience, do not understand. Spring Boot enables 3-6 annotations, 2-3 of which you cannot enable outside of Spring Boot. Those 3-4 common annotations explode out into at least 10 more annotations. In total, all those annotations create a large number of beans very few developers know exist. Only if you had been using Spring since version 2.0 and had followed it's growth through MVC (and its ViewResolvers) into the RESTy side (with its MessageConverters) will you know what it's actually doing. In short, very few developers I've found can actually be effective within Spring. If they try to find the right place for a thing, they spend more time reading documentation to find the right extension point (what base class does my @Configuration need to extend so that I can put this bean in the ContentNegotiationManager!?!?) and if they work around the framework they pay later when Spring works against them<br />
<br />
If you're writing small micro services and you finish them and forget them I don't see a problem.<br />
<br />
Though these days there are many more frameworks which are slimmer and offer a more obvious and easily testable environment which makes, in my view, Spring less relevant. (edited)<br />
<br />
In short, I'm looking at more ala cart solutions. An example might be using Guice (for IoC) with Vert.x 3. There is pretty minimal frameworking, whatever your app does, you see very clearly. The examples online don't show what I believe to be the best use of Vert.x (and Guice), they put all the codes in one file and say "hey look how easy this is!". The Java APIs of Vert.x are incredibly clean, all interfaces, easy as hell to mock, which ties in well to properly abstracting and dividing the application into components<br />
<br />
The built-in Hazelcast solves a lot of problems in architecture N-tier apps have.<br />
<br />
<br />
Brandon Zeeb:<br />
Twitter: @phasebash<br />
Github.com/phasebashJeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-28824717483220400442016-09-26T13:51:00.004-04:002016-09-26T13:51:48.048-04:00SonarLint for Eclipse Does Not Analyze Test Files by Default<div class="separator" style="clear: both; text-align: left;">
I say unit tests are code like any other code. As such, they deserve to be refactored and kept clean.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I learned today that, by default, SonarLint for Eclipse disagrees. If you select <span style="font-family: Courier New, Courier, monospace;">Window->Preferences->Sonar Lint</span><span style="font-family: inherit;">, you will see that "</span><span style="font-family: Courier New, Courier, monospace;">Test file regular expressions</span><span style="font-family: inherit;">" contains "</span><span style="font-family: Courier New, Courier, monospace;">**/*Test.*,**/test/**/*</span><span style="font-family: inherit;">":</span></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYPZpsCAs-bUdullbzVwMpr9CIIA98UsdR5b9ZfMwjT8jD_r0yGkCDQRQAAgyeW72BEnfGcBv-1zFDZBv_ahJhV3nXsHukn4cRs9ZQwVpis8QkSyTfL-zlydQkPyahF3Kk7FIPUK_mo88/s1600/Capture.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYPZpsCAs-bUdullbzVwMpr9CIIA98UsdR5b9ZfMwjT8jD_r0yGkCDQRQAAgyeW72BEnfGcBv-1zFDZBv_ahJhV3nXsHukn4cRs9ZQwVpis8QkSyTfL-zlydQkPyahF3Kk7FIPUK_mo88/s320/Capture.JPG" width="320" /></a></div>
<br />
For SonarLint to behave the way I want, which is to treat any file whose name ends in ".java" as code, I have to clear the regex.Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-11854585513403565092016-09-21T20:38:00.003-04:002016-09-21T20:38:48.997-04:00Legacy Code: Characterize or Test Protect?In the context of working with legacy code, I often hear the terms "Characterization Tests" and "Test Protecting". Here is how I think about each term:<br />
<br />
<br />
<b>Characterization Tests</b>: a suite of <i>tests</i> that I build against legacy code that uses sufficient representative inputs to convince myself that I have <i>characterized</i> the behavior of the object I am testing. This suite also documents the behavior.<br />
<br />
<b>Test Protecting</b>: building a suite of <i>tests</i> against legacy code that covers the object under test sufficiently that I am confident that the suite <i>protects </i>me from inadvertently changing the object's behavior during refactoring or when I add features.<br />
<br />
<br />
One thing that is interesting to me is that the <i>exact same suite</i> of tests can both characterize and protect an object's behavior.<br />
<br />
I was running a workshop today and introducing the concept of test protecting. Here are the steps I introduced today. If you are new to test protecting, they should be a good starting point. If you've done some test protecting, I hope you'll find some new nuance to your understanding. If you're already awesome at test protecting, maybe you'll want to teach from my steps, or comment with your insights about test protecting.<br />
<h2>
<b>Steps I Teach to Test Protect Legacy Code:</b></h2>
<h4>
Select a class to protect. </h4>
Usually this is the class that I need to fix a bug in or add a feature to. Or maybe I have a few spare cycles and I want to add coverage to a frequently edited class. I do not select a rarely-modified class to test protect - that would be a waste of time (and thereby money, mine or my employer or client's)<br />
<h4>
Create a test class.</h4>
Legacy code, by <a href="https://theholyjava.wordpress.com/2011/04/18/what-do-i-mean-by-a-legacy-code/" target="_blank">one definition</a> is code that doesn't have tests, so it follows that a legacy class won't have a test corresponding class. Create a test file with a name and location that follows your unit testing framework's conventions.<br />
<div>
(Commit to your version control.)</div>
<h4>
Choose a public method to start with.</h4>
Often legacy classes are large and complex enough that it is difficult to test protect them well through only the public methods. I see several options (of varying risk) in that case:<br />
<br />
<ol>
<li>Change private methods to public</li>
<li>Change private methods to package protected</li>
<li>Don't protect private methods that are difficult to test through public methods.</li>
<li>Refactor the class so that it is easier to test.</li>
<li>Use a testing tool that allows you to test non-public methods.</li>
<li>Protect as much as you can in a reasonable amount of time, assess risks posed by unprotected code, then decide on your next action.</li>
</ol>
<div>
The only answer that I am comfortable with is number 6.</div>
<h4>
Write a test that exercises the method you selected.</h4>
<div>
If you are at least somewhat familiar with the behavior of the method you selected, think about edge case inputs and happy and sad path inputs. Choose one to start with. Some devs like to start with edge cases, some like to start happy or sad path. I'm not sure it matters.</div>
<h4>
Give your test an absurd assertion against the result.</h4>
<div>
This step is as much like characterization as it is like test protecting. I want to be sure my test fails before it passes, so I choose a value that is unlikely to be correct. For instance, if the method I am exercising is:</div>
<div>
<span style="font-family: Courier New, Courier, monospace;">int lookupDogAverageWeightLbs(string breed);</span></div>
<div>
<span style="font-family: Times, Times New Roman, serif;">then I will choose a number like 5000:</span></div>
<br />
<div>
<span style="font-family: Courier New, Courier, monospace;">assertEquals(5000, lookupDogAverageWeightLbs("Goldendoodle"));</span></div>
<h4>
<span style="font-family: Times, Times New Roman, serif;">Run the test so it fails.</span></h4>
<div>
<span style="font-family: Times, Times New Roman, serif;">In the previous example, your test should fail with a message something like:</span></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Expected [5000] got [40].</span></div>
<div>
<span style="font-family: Times, Times New Roman, serif;">If it doesn't, check your assumptions and look for mistakes in your exercising of the method or in how you wrote your assertion.</span></div>
</div>
<h4>
<span style="font-family: Times, "Times New Roman", serif;">Fix the test so it passes.</span></h4>
<div>
<span style="font-family: Times, "Times New Roman", serif;">When we test drive, we assert what the expected value <i>should be</i>, run it to see it fail, and then write the least amount of code needed to make the test pass. In test protection, the existing implementation is the standard behavior, so we fix our <i>expectation</i> to make the test pass. From absurd fail message above, </span><span style="font-family: Times, "Times New Roman", serif;">you can easily see the actual result delivered by the implementation and fix the expectation with it so that the test passes:</span></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">assertEquals(40, lookupDogAverageWeightLbs("Goldendoodle"));</span></div>
</div>
<div>
<span style="font-size: x-small;">(Commit to your version control.)</span></div>
<h4>
<span style="font-family: Times, "Times New Roman", serif;">Examine the test coverage of the method you are exercising.</span></h4>
<div>
<span style="font-family: Times, "Times New Roman", serif;">If your coverage tool doesn't automatically run when you run tests (<i>why doesn't it?</i>), then run your coverage tool. Find which lines of your exercised method are not executed by your first test. If there are none, your method is test protected.</span></div>
<h4>
<span style="font-family: Times, "Times New Roman", serif;">Write another test that hopefully increases coverage. </span></h4>
<div>
<span style="font-family: Times, "Times New Roman", serif;">Write a new test and give your exercised method new input data. Use inputs that, based on whatever understanding you have of the method so far, will exercise a non-covered line. Sometimes the name of the method will give you an idea, sometimes you will have gleaned some tentative understanding by scanning the implementation code while looking at coverage, and sometimes you still won't have a clue. Pick new inputs however you can and run your test.</span></div>
<h4>
<span style="font-family: Times, "Times New Roman", serif;">Get the new test passing.</span></h4>
<div>
<span style="font-family: Times, "Times New Roman", serif;">You might have needed to write a green test in order to increase the method's coverage. That's ok. In test driving, a test that doesn't go red before going green is worthless and time-wasting at best and possibly dangerous at worst. But in test protecting, such a test is only worthless if it does not add to the method's coverage. If your new test didn't increase the method's coverage, change your inputs until it does. This is another difference from when we test drive. When we test drive, we choose a set of inputs that fail and implement code to make it pass. We change the inputs only if the ones we chose did not make the test fail.</span></div>
<div>
<div>
<span style="font-size: x-small;">(Commit to your version control.)</span></div>
</div>
<h4>
<span style="font-family: Times, "Times New Roman", serif;">Check the coverage of your method again.</span></h4>
<span style="font-family: Times, "Times New Roman", serif;">If you have not covered all the lines in the method, jump back to "</span><span style="font-family: Times, "Times New Roman", serif;">Write another test that hopefully increases coverage." If you have covered all the lines in the method, </span><span style="font-family: Times, "Times New Roman", serif;">start over again with</span><span style="font-family: Times, "Times New Roman", serif;">"</span>Choose a public method to start with." If you've covered all the lines in the class, you have test protected the class. Congratulations!<br />
<br />
<div>
<b>Make sure new tests are run in CI.</b></div>
<div>
If there are already other test classes in your project, your continuous integration server may already be configured to run tests in all test classes. If not, adjust your CI server's configuration to be sure that it runs your new tests. Kick off a build and inspect the build output to be sure your new tests ran.</div>
<div>
<br /></div>
<div>
<br /></div>
Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-73572576595992598872016-05-09T17:48:00.002-04:002016-05-09T17:48:23.281-04:00Jokes and Fun and Safety at WorkSomething happened at a conference I recently attended:<br />
<br />
Between sessions, there was a long line at the men’s room. There was little or no line at the women’s room. Behind me in line, out of my vision, I heard a man say:<br />
<br />
<i><span class="Apple-tab-span" style="white-space: pre;"> </span>“Maybe we're all starting to feel transgender right now.”</i><br />
<br />
If you didn't cringe when you read that, I get it. In a way, it is a clever nod to all the happenings related to the recent <a href="http://wlos.com/news/local/hb2-a-history-of-the-bill-and-how-nc-got-here" target="_blank">North Carolina bathroom law</a>.<br />
<br />
But I cringed when I heard it, and I cringe each time I read it again. Unfortunately, that comment is hurtful. Would a transgender man feel welcome hearing that? I can't imagine one would.<br />
<br />
I'm sure that the comment was not <i>intended</i> to be hurtful. But if a transgender man heard it, and I can't be certain that one did not, I expect it would have a hurtful <i>impact</i>. And if we want a better workplace and a better world, I believe we have to take responsibility for the impact of our actions, not just our intentions.<br />
<br />
<div>
<div>
I believe everyone wants a fun work environment, and jokes can certainly be part of that. But I'm hoping that we can create cultures that push women and members of marginalized groups out of IT less. When someone is outnumbered in a setting, it can be hard to speak up about what feels OK and what doesn’t, especially if the rest of the group seems to (even if silently) condone something. I understand - rocking the boat about culture can be a risk to employment. As white, heterosexual men, we are probably not experienced with what can feel hurtful to people different from us. I try to honor and believe people’s life experiences. Even if I can’t see how something can be hurtful, I try to believe people when they say something is.</div>
<div>
<br /></div>
<div>
All of this means that I try to avoid humor that is sexually charged, comments on people’s bodies, or touches on race, religion, sexual orientation, gender presentation, and other characteristics of members of marginalized groups.</div>
</div>
<div>
<br /></div>
<div>
And if a joke like that slips out and I notice, I don't wait for someone else to point it out. I call myself out on it and acknowledge the possible impact, even though it wasn't my intention.</div>
<div>
<br /></div>
<div>
<br /></div>
Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-86395298659543448362016-05-07T09:36:00.000-04:002016-05-08T20:23:50.400-04:00Slides from my Diversity in IT talk at Agile and Beyond 2016 are Now AvailableAt Agile and Beyond 2016, I presented: "Why Should I Go See Another White Man Talk About Diversity in IT?" I spoke mainly about how women and members of marginalized groups are often made to feel unsafe or unwelcome at IT companies, usually without men realizing the impact of what we are doing.<br />
<br />
I've put my slides up (link below). If you are interested in the topic, please take a look. I have included many links to information and resources.<br />
<br />
<a href="http://schedule.agileandbeyond.com/event/65rg/why-should-i-go-see-another-white-man-talk-about-diversity-in-it" target="_blank">slides - scroll down below my profile to find the .pptx</a><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTbLWCy9AGjr-ueknLiaXl30Kql9cmF3IdasoWWWWt9SkzSB5XQptnT34_cCo3vn3t411w5bKhTnk3gdJKOCNP1yeWEjNgGtUoJJIjNrYSo5a68wU7L1NDoDc1kis8MqW3YdbgLM-wKZ4/s1600/image.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTbLWCy9AGjr-ueknLiaXl30Kql9cmF3IdasoWWWWt9SkzSB5XQptnT34_cCo3vn3t411w5bKhTnk3gdJKOCNP1yeWEjNgGtUoJJIjNrYSo5a68wU7L1NDoDc1kis8MqW3YdbgLM-wKZ4/s1600/image.png" /></a></div>
<br />Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-32841511241596399532016-05-04T20:51:00.002-04:002016-05-04T20:51:47.638-04:00A New Adventure - Same Employer, Same Client!For the last ten months, I have been a software developer on a high-functioning, reference team at a major enterprise client. The team is a great group of people, with solid processes, and has been delivering defect-free code and providing mission-critical business value since before I joined them. But my time as a member of that team has drawn to a close.<br />
<br />
Starting Monday, I will be moving within that same client to join the coaches in their Agile Center of Excellence. This new role will allow me to use more of my personal, social, coaching, and training skills, and will no longer involve creating production code on a cadence.<br />
<br />
I am really excited for my employer, my client, and myself. The change comes at a time when the development team is beginning a pre-planned size-down, so my employer has somewhere to place me immediately. My client can continue to benefit from my accumulated domain experience. Both will be getting their best value by paying for work that I excel at, and I'll be doing work that I have a deep passion for.<br />
<br />
<br />Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-21346694845018113192016-03-31T22:20:00.000-04:002016-03-31T22:20:15.782-04:00On PrivilegeWhat do I mean by “Privilege”?
Privilege is a set of advantages that I receive, without earning
them, merely because of my birth circumstance(s).
Privilege is different than prejudice or “ism”s. As a person of privilege, I get the advantages
even if don’t have prejudice and don’t engage in
overt oppressive activities like sexism or racism.<br />
<br />
Some examples of my privilege as a white man include:<br />
• I can go to any workplace and expect to see people who look like me<br />
• If I make a mistake, no one will say that it’s because white people are
stupid<br />
• The lead roles in movies and tv shows are usually of my color and
gender<br />
• If I have children and a career, I won’t be called selfish for not being
home with the children<br />
• I am more likely to get a job than an equally qualified applicant who is a woman and/or person of color<br />
<br />
There are many types of privilege, including (specific examples and details can be found by following the links):<br />
• <a href="http://nationalseedproject.org/white-privilege-unpacking-the-invisible-knapsack" target="_blank">White Privilege</a><br />
• <a href="http://everydayfeminism.com/2015/05/proof-male-privilege/" target="_blank">Male Privilege</a><br />
• <a href="http://queersunited.blogspot.com/2008/10/heterosexual-privilege-checklist.html" target="_blank">Heterosexual Privilege</a><br />
• <a href="http://everydayfeminism.com/2013/03/19-examples-of-ability-privilege/" target="_blank">Able-bodied Privilege</a><br />
• <a href="http://educationandclass.com/2008/05/16/middle-class-privilege/" target="_blank">Class Privilege</a><br />
• <a href="http://atheism.about.com/od/christianismnationalism/p/ChristianPriv.htm" target="_blank">Religious Privilege</a><br />
• <a href="http://itspronouncedmetrosexual.com/2011/11/list-of-cisgender-privileges/" target="_blank">Cisgender Privilege</a> (contrast with transgender)<br />
<br />
You may say: “But I have struggled!
I don’t have privilege!” Privilege isn’t about whether I am powerful,
wealthy, have a good job, have worked hard all my
life to get where I am, or struggle every day.
Privilege is simply unearned advantages I get
<u>because I belong to a group</u>.<br />
<br />
Sometimes when people learn about the concept of privilege, people feel guilt? <a href="http://everydayfeminism.com/2014/03/movingpast-privilege-guilt/" target="_blank">If this happens to you, ask yourself where the feeling is coming from.</a> Is it because:<br />
• I never noticed it before?<br />
• I act in ways that make this worse?<br />
• I don’t do things that make it better for people
without privilege?<br />
<br />
Now that you know about privilege, what can you do about it? You can:<br />
• Read about privilege<br />
• Stay on the lookout for other privileges you might discover you
have<br />
• Belive the life experiences of people with less privilege<br />
• Ask yourself if your actions or policies reinforce the advantages
of certain privileged groups<br />
• Don’t “help” less-privileged groups - it robs them of agency. Instead amplify their voices (retweet, etc)<br />
<br />Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-37787769345574250192016-03-02T22:39:00.002-05:002016-03-02T22:39:56.844-05:00Pair Programming "Out Loud"One element of Pair Programming that I find key to success is "Programming Out Loud". When I have the keyboard and mouse (driving), I want to be explaining my train of thought to my pair partner, moment-by-moment. Conversely, if I am the non-keyboard partner (navigating), I want my partner to be explaining their thoughts moment-to-moment. If my partner is practicing "silent pair programming", I try to ask ask questions like: "What's next?" or "Where are we headed?" to try to get them talking about what they are thinking or doing. Or if that doesn't help, I can ask to drive for a while and try and draw out their ideas that way. Usually things don't go this far, unless my partner is new to pairing. When I start to go off silent and solo, my partner usually invites me back into collaborative mode.<br />
<div>
<br /></div>
<div>
But what if my partner is the navigator and they are disengaged? I can ask (slightly tongue-in-cheek): "Are you with me?" It can require courage to "call out" my partner in that way, but sometimes it takes courage to be on a successful agile team. And if I'm the disengaged navigator and I catch myself being distracted, I can ask to write the next test to try and focus myself back on what we are doing.<br />
<br />
Do you have ways that you draw a distracted partner back into collaboration? Or do you have ways to get yourself back into collaboration?</div>
Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-64756063225925004872016-02-24T17:50:00.000-05:002016-03-02T10:22:41.362-05:00Hiring and Diversity<div class="graf--p" name="7769">
I’m so glad to see another man <a href="https://jaygoldman.com/hiring-awesome-developers-who-happen-to-be-women-511312e07f97" target="_blank">thinking about hiring women and members of marginalized groups</a>. I started a comment that post, but it became rather long, so I am posting it here instead. Read Jay's original post at the link above for perspective, although I hope that what I have written below stands fairly well on its own.</div>
<div class="graf--p" name="7769">
<br></div>
<div class="graf--p" name="7769">
Jay,</div>
<div class="graf--p" name="7769">
I really like your post: "Hiring Awesome Developers (who happen to be women)". I've been thinking about how to write a "disclaimer" paragraph like your “<em class="markup--em markup--p-em">Before you start</em>” paragraph. You've covered many of my thoughts. I also try and acknowledge to people that I <i>will</i> make mistakes, and that I will accept the <a href="http://everydayfeminism.com/2013/07/intentions-dont-really-matter/" target="_blank"><i>impact</i> of my words regardless of their <i>intention</i></a>. Further, I won’t expect people to teach me about those mistakes (although I am totally open to it), and I will research on my own until I think I understand them.</div>
<div class="graf--p" name="7769">
<br></div>
<div class="graf--p" name="d1da">
Another thing I find important is to amplify the voices of people in marginalized groups. I try to provide references to people who belong to the groups that I am speaking about. They are the ones whose lives are affected daily by these issues and they speak from the most authority.</div>
<div class="graf--p" name="d1da">
<br></div>
<div class="graf--p" name="8bd4">
Your paragraph “A Possible Plan” addresses the so-called “pipeline” problem that results in too few minority and women candidates. But another reason that the makeup of companies is still disproportionately is that <a href="http://rachelappel.com/stats-data-and-answers-as-to-why-there-are-so-few-women-in-technology-fields/" target="_blank">women are leaving STEM in large numbers</a>. We need to make sure that our company cultures and environments are really fair to women and minorities and free from discrimination and bias <i>before</i> we bring in women and minorities, or we risk losing them and alienating them more.</div>
<div class="graf--p" name="8bd4">
<br></div>
<div class="graf--p" name="717c">
We can also examine our websites and job descriptions for wording and imagery that may discourage women and members of marginalized groups from applying. A simple example is a posting that looks for “ninja” developers who can “smash” technical problems — this aggressive language exclude women from considering themselves as a candidate.</div>
<div class="graf--p" name="717c">
<br></div>
<div class="graf--p" name="0cd0">
Finally, <a href="https://hbr.org/2014/08/why-women-dont-apply-for-jobs-unless-theyre-100-qualified" target="_blank">women tend not to apply for tech jobs unless they meet 100% of the criteria in the posting while men apply if they match 60%</a>. I’m not sure what to do about that - maybe mention in the posting that not all criteria are required and avoid long lists of “nice-to-haves”.</div>
<div class="graf--p graf--empty" name="6456">
<br></div>
<div class="graf--p graf--empty" name="6456">
I wrote <a href="http://blog.jhoover.com/2016/02/things-i-am-learning-about-my-part-in_14.html" target="_blank">another post</a> that has a more concise bullet-list of things I'm learning about diversity and the workplace.</div>
Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-67973795781441790222016-02-24T16:36:00.000-05:002016-02-24T16:36:02.613-05:00My Crash Course Crayon Video: 4 Levels of ListeningMy employer, <a href="http://www.pillartechnology.com/" target="_blank">Pillar</a>, produces <a href="https://www.youtube.com/playlist?list=PL_PxloW2yKA7UD6TK5bIhmWfof2wFhJCE" target="_blank">a series of two-minute videos</a> related to software development and the people skills needed to do it well.<br />
<br />
A video I made was just released. The title is: "4 Levels of Listening" and you can <a href="http://youtu.be/qu547Gvg4jg" target="_blank">watch it here</a>. I'd love to hear your reactions.<br />
<br />Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-70174567863707187892016-02-14T17:39:00.003-05:002016-02-14T17:39:38.483-05:00Things I am Learning About my Part in Diversity and InclusionAs a <a href="https://en.wikipedia.org/wiki/Cisgender" target="_blank">cis-gendered</a>, heterosexual, white man, I want to:<br />
<br />
<ul>
<li>do my <a href="http://geekfeminism.wikia.com/wiki/Feminism_101" target="_blank">homework</a> to learn fundamentals about marginalized groups' experiences</li>
<li>amplify marginalized people’s voices</li>
<li>believe marginalized people's life experiences </li>
<li>understand <a href="http://everydayfeminism.com/2013/07/intentions-dont-really-matter/" target="_blank">intent vs impact</a> of what I say</li>
<li>be ready for the <a href="https://gomakemeasandwich.wordpress.com/2015/05/20/feminist-leaning-dudes-lets-have-the-talk/" target="_blank">mistakes I will mak</a>e</li>
<li>accept that the people that my mistakes hurt may be <a href="http://sophiaserpentia.livejournal.com/838741.html" target="_blank">angry</a></li>
<li>accept that they don’t owe me an explanation of why it hurts (see doing homework)</li>
<li>not “<a href="https://theangryblackwoman.wordpress.com/2008/04/29/no-cookie/" target="_blank">expect a cookie</a>” for working on diversity and inclusion (<a href="https://www.flickr.com/photos/22789525@N00/3571777191/in/album-72157616944737345/" target="_blank">pic</a>)</li>
<li>understand that <a href="http://juliepagano.com/blog/2014/05/10/so-you-want-to-be-an-ally/" target="_blank">being an ally</a> is not a yes/no condition, but requires a level of <a href="http://theangryblackwoman.com/2009/10/01/the-dos-and-donts-of-being-a-good-ally/" target="_blank">proactivity</a></li>
<li>find someone besides marginalized people to help me explore my feelings about allyship</li>
<li>learn to "<a href="http://geekfeminism.wikia.com/wiki/Privilege" target="_blank">check my privilege</a>" and understand that I have privilege <a href="http://thoughtcatalog.com/gina-crosley-corcoran/2014/01/explaining-white-privilege-to-a-broke-white-person/" target="_blank">even if I had a hard life</a> of poverty and abuse.</li>
</ul>
<br />
If these ideas interest you, please follow the links above and come see me present at <a href="http://agileandbeyond.com/2016/#/" target="_blank">Agile and Beyond 2016</a> this May.<br />
<br />
<br />Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com4tag:blogger.com,1999:blog-3412076207393035593.post-90463398767236791792016-01-17T21:00:00.000-05:002016-01-17T21:00:25.977-05:00Accountability - Do you do what you agree to do?How accountable are you for your agreements? When you say you are going to do something, do you do it?<br />
<br />
There was a time when I would say I would do things but then often not do them. For example: an acquaintance would suggest we go bowling and I would answer something like: "Yeah, I'll call you." But then I wouldn't call. Or when I first started in my career, a manager might ask me to provide a write-up on something and I might say something like: "I'll have it by the end of tomorrow." But that day and the next would pass, without any high-priority emergencies, and yet I wouldn't finish the write-up.<br />
<br />
Does that sound familiar? Do you have patterns like this? Maybe at work, or with a family member or spouse, or with friends or acquaintances?<br />
<br />
What was I doing when I said I would do something but then not do it? In both examples above, I might have had mixed feelings about doing the thing, or I might have actually meant to do it. But somehow I never quite managed to get it done. What did this behavior communicate to my friend or my manager? Perhaps it told them that I couldn't be counted on. Maybe even it said that I didn't put much value on things are that important to them. They might not have realized it consciously, but I suspect that they received a message that I didn't care very much about them.<br />
<br />
There came a time when I realized that not keeping agreements were weakening relationships with people in my life, at work and outside work. So I briefly decided that the answer was that I wouldn't commit to very much. So if that acquaintance suggested bowling, my new answer would be something like: "Yeah, maybe." Or with my manager, I would try to get away with telling him that I would complete the write-up "soon". But it quickly became apparent that this strategy wasn't strengthening relationships with people.<br />
<br />
These days, I have a strategy around agreements that strengthens relationships with people. When I'm asked something, I stop and consider the request seriously. I ask myself whether I want to agree to it, and whether I'm for sure <i>able</i> to commit to it. If both are yes, then I give the person a date or time when I will do it, and then I follow through. So, in the bowling example again, my answer would be "Yeah, that sounds fun! Can you do it this Friday?" And with my manager, I would say: "I've got a lot on my plate right now; I'm not sure when I will be able to get to the write-up. Do you want to change my priorities? If I stopped everything else right now, I could have it by noon tomorrow."<br />
<br />
Obviously, my new strategy doesn't require me to agree to everything. Maybe I don't like bowling. In that case, I could suggest a specific time for an alternate activity. Or maybe I really don't want to hang out with that person at all, I might just say: "Nah, but thanks for asking." Or I might tell my manager, if it's true, that I don't think I would do a good job on the write-up, and suggest a different person to ask. Or if it's just a preference, I could tell him something like: "If you need it to be me, I will do it. But if not, I'd rather stay on what I'm working on. Okay?"<br />
<br />
Besides the way that this method of handling agreements strengthens connections with people, I find it has personal benefits as well. I'm able think of myself as a responsible person. And I don't feel guilty for indirect communication. And I get much more clear about what I want, what I'm willing to do, and what I'm not willing to do.<br />
<br />
<br />Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0tag:blogger.com,1999:blog-3412076207393035593.post-59581355591171908882016-01-08T21:53:00.002-05:002016-01-08T21:53:24.512-05:00Even Well-Meaning Words Can Hurt - What Can We Do When It Happens?<span style="font-family: inherit;">Have you ever heard an exchange like this? </span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Person A. < some remark ><some remark=""><br />Person B. "Hey! That's not nice!"<br />Person A. "Jeez, lighten up! I was just <b>joking</b>."<br /><br />What happened here is that Person B doesn't understand the difference between <i>Intention</i> and <i>Impact</i>.<br /><br /><br /><i>Intention</i> is whatever result Person B wanted their words to have. In the case above, they probably wanted people to laugh. On the other hand, <i>impact </i>is the emotional meaning that Person A received. In the case above, Person A felt slighted in some way - probably by one of the common "isms": sexism, racism, etc.</some></span><br />
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">A tool I learned to work with Intention and Impact is called Ouch / Oops. I have only tried it in groups that are already close, but I bet it would work in somewhat mature teams as well. When a person receives a negative <i>Impact</i>, they can tell the other person: "Ouch" or: "That was an ouch for me." </span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">Here's the same example as above, but with Ouch:</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">Person A. <some remark="">< some remark ><br />Person B. "Ouch." <i>or</i> "That was an ouch for me."<br />Person A. "Oh, I'm sorry. What did I say that hurt?</some></span><br />
<some remark=""><span style="font-family: inherit;">Person B. <explains impact="" of="" remark=""></explains></span></some><br />
<some remark=""><span style="font-family: inherit;">Person A. "Wow, I had no idea that what I said could be taken that way. Thanks for explaining it.</span></some><br />
<some remark=""><span style="font-family: inherit;"><br /></span></some>
<some remark=""><span style="font-family: inherit;">Here is another version of the above example, except that when Person B points out the impact, Person A can see the problem right away.</span></some><br />
<some remark=""><span style="font-family: inherit;"><br /></span></some>
<some remark=""><span style="font-family: inherit;">Person A. <some remark="">< some remark ><br />Person B. "Ouch." <i>or</i> "That was an ouch for me."</some></span></some><br />
<some remark=""><span style="font-family: inherit;">Person A. "Oh right, I'm sorry. I see what my words implied. That wasn't what I intended. Thanks for pointing it out."</span></some><br />
<some remark=""><span style="font-family: inherit;"><br /></span></some>
<some remark=""><span style="font-family: inherit;"><br /></span></some></div>
<div>
<span style="font-family: inherit;">By contrast to Ouch, Oops works in the opposite direction. A person says something, catches a possible <i>Impact</i> of their own words, and then uses Oops. Here's our example again, this time with Oops. Notice that Person A speaks twice before Person B speaks:</span></div>
<div>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Person A. < some remark ></span></div>
<div>
<span style="font-family: inherit;">Person A. <some remark=""> "Oops. That might have a different impact than I intended. I'm sorry. Let me say it this was instead: ..."<br />Person B. "Yeah, the first way didn't feel good. Thanks for catching it."</some></span><br />
<span style="font-family: inherit;"><some remark=""><br /></some></span>
<span style="font-family: inherit;"><some remark="">It is important here that neither person belabor the point during an Oops or an Ouch. The point isn't to punish person A. Person A needs simply to recognize their impact and express a brief apology. From there, both people move on. Any additional apologizing or lecturing can lead to hurt.</some></span></div>
<div>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">Receiving "Hey! That's not nice!" is uncomfortable. Often, a"Hey! That's not nice!" response is met with defensiveness. This could be because a part of the speaker may feel shame, and sometimes a way to deal with shame is to <a href="http://blog.jhoover.com/2015/12/recognizing-projection-taking-ownership.html" target="_blank">lash out and blame the other person</a>. By contrast Ouch offers the possibility of the parties involved learning something and becoming closer. Being on the receiving end of Ouch may still be unpleasant, but is less likely to invoke shame. Calling "Ouch" focuses on the impact on the listener while presuming good faith on the part of the commenter, rather than implying that the commenter is mean, insensitive, or prejudiced. Similarly, with the focus on the impact received, there is less room for someone to be misjudged as touchy or over-sensitive.</span><br />
<span style="font-family: inherit;"><br /></span>
<br /></div>
<div>
<span style="font-family: inherit;">Oops is a way of acknowledging that the listener has valid feelings and that the speaker's words may have been received as hurtful, but that the speaker doesn't intend to hurt the listener. Like with Ouch, this offers the pair the opportunity strengthen their relationship.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><br /></span></div>
Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com2tag:blogger.com,1999:blog-3412076207393035593.post-86683551645470873052016-01-08T21:06:00.001-05:002016-01-08T21:52:07.371-05:00Increasing my BloggingI've decided to really try and be consistent and blog good content on a regular basis. I am taking a free 6-part course by <a href="http://pluralsight.com/">https://www.pluralsight.com/</a> instructor and author of "Soft Skills: The Software Developer's Life Manual", John Somnez. The course is written for software developers.<br /><br /> On John's site <a href="http://simpleprogrammer.com/">http://simpleprogrammer.com/</a> I signed up for "How To Build A Blog That Will Boost Your Career" (<a href="http://t.dripemail2.org/c/eyJhY2NvdW50X2lkIjoiOTUyNDk2NiIsImRlbGl2ZXJ5X2lkIjoiOTQyMjI4NjgiLCJ1cmwiOiJodHRwOi8vZGV2Y2FyZWVyYm9vc3QuY29tL2Jsb2ctY291cnNlLz91dG1fc291cmNlPWhvdy10by1jcmVhdGUtYS1ibG9nLXRoYXQtYm9vc3RzLXlvdXItY2FyZWVyLWNvdXJzZVx1MDAyNnV0bV9tZWRpdW09ZW1haWxcdTAwMjZ1dG1fY2FtcGFpZ249bGVzc29uLTUtZG8teW91LWtub3ctaG93LXRvLWdldC10cmFmZmljLWZvci15b3VyLWJsb2dcdTAwMjZfX3M9azhwc3RhczY0cG43eWN1dzh5bjgifQ">http://devcareerboost.com/blog-course/</a> Again, it's free, and I don't get anything if you sign up.)<br /><br /> John's course takes you through:<br /><ul>
<li>Deciding on a theme (mine is Understanding Yourself and Others to Improve your Dev Career) </li>
<li>Easily creating an actual blog site using Wordpress + Bluehost (but if you want to use something else, or already have something, no problem) </li>
<li>Creating a big backlog of blog topics </li>
<li>Choosing and committing to a posting schedule, including when you are going to write (I'm going to publish every other Monday, writing on Sunday night) </li>
<li>Generating traffic to your site without using anything scammy </li>
<li>Marketing yourself </li>
</ul>
<br />I like the course format. It comes out twice a week. Each email has a couple of homework assignments that require real work but are doable by the next email. I am really keeping up, and I tend to procrastinate some things like this.<br /><br /><br />Disclosure: Writing and publishing a post about the course is one of this week's homework assignments. It simply says to write a post about the course and include the links. I wrote the content without any input from him, he didn't see it before I published, and I don't get paid for it.<br /><br /><br /><br /><br />Jeff Hooverhttp://www.blogger.com/profile/00303074503426576256noreply@blogger.com0