tag:blogger.com,1999:blog-124676692024-11-20T02:36:28.332-05:00Jay Fields' Thoughtsexperiences in software developmentJayhttp://www.blogger.com/profile/14491442812573747680[email protected]Blogger570125tag:blogger.com,1999:blog-12467669.post-83276536833911426272017-05-17T07:00:00.000-04:002017-05-17T07:02:36.362-04:00Starting a New Engagement as a Lead ConsultantSomeone recently asked me for information on starting new consulting engagements. A few years back I published Sean Doran and Scott Conley's thoughts on <a href="http://blog.jayfields.com/2013/04/being-lead-consultant.html" target="_blank">Being a Lead Consultant</a>. Sean and Scott's list is great for any lead consultant, and the advice applies well for the lifetime of a project. I considered sending that list to the person looking for new engagement advice, but I'm not sure that list would be the best place to focus my attention at the beginning of a project.<br />
<br />
The beginning of a project is a special and dangerous time. You get a mix of (at least) optimism, concern, and freedom. There are a large number of ways the project can go, and as a lead consultant you'll play a major role determining it's outcome. The specific question I recently received was: did you have a process you followed when new engagements began. The remainder of this blog post contains my (slightly edited) response.<br />
<br />
I found being a lead at ThoughtWorks to be a nearly impossible balancing act. It's possible we didn't have a process because we weren't organized enough, but it's more likely that there's no general formula that works.<br />
<br />
What we ran into constantly was what we called the "enablement versus delivery" issue: If you're teaching client devs (enablement), you really don't have time to meet delivery deadlines; conversely if you're delivering software you rarely have time to teach. How to balance enablement versus delivery is something that varies based on the client's skillset and the ROI of the software being developed. What makes it worse is that the client often thinks they need one thing, but if the the company didn't have issues you (likely) wouldn't be there. Sometimes the issues are with the stakeholder and they'll tell you to focus on the wrong thing, and sometimes the stakeholder knows the deal but the other people you are forced to work with are the problem.<br />
<br />
Often it's a race to figure out what the client needs and get them to agree to fix it, before you've lost too much good will.<br />
<br />
Another issue is, most software is worthless within a few years, and the only way to break a perpetual cycle of mediocrity is to level up the people and processes. This can lead some people to think that delivery of a specific piece of software is secondary to improving process and people. There's a major flaw to that approach though; a non-TW consultant once said that he feels guilty about his job, because when he helps people become better the most talented always end up leaving the (suboptimal environment of the) client. You can help people improve and install good processes, but when the good people leave and the remaining don't understand the foundations of the process, you end up with not enough talent and a process that's loosely followed and for none of the right reasons.<br />
<br />
That said, you can't focus exclusively on delivery. I once led a team that beat all deadlines, created a great piece of software, and provided a great deal of content for <a href="https://martinfowler.com/books/dsl.html" target="_blank">Martin Fowler's DSL book</a>. It was a "huge success" until the client devs took over, couldn't maintain it, and wrote their own version that had 20% of the functionality we provided. The software we wrote was classified as a "proof of concept" and thrown out.<br />
<br />
I was somewhat oblivious to all of this in my first few years at ThoughtWorks; I would work with the talented clients while isolating the less talented. Eventually you find out that a stakeholder will usually fire you before their worst employee, regardless of how obvious it is.<br />
<br />
If I were going into a new engagement these days, I would split my time between training and delivery initially. After figuring out which is the bigger problem, you can spend more or less time on training or delivery.<br />
<br />
I would also keep a spreadsheet with every client employee and their talents; every one of those employees will impact your success. If you find what they're good at and get them doing that, you may have found an ally and advocate. Every employee that has no talents listed in your spreadsheet is not only slowing you down, but is also likely (consciously or unconsciously) sabotaging you in every discussion you aren't a part of. Assume you cannot get rid of them, and don't bother trying; spending political capital managing client staff is a bad investment. Keep them on your sheet and make finding their talent a top priority.<br />
<br />
Good luck, it's not an easy gig. Then again, if things don't go well you can always move on to another client. That was what always kept me sane. I always did the best job I could, but I also knew if I failed at an impossible task it wasn't the end of the world. There's an endless stream of impossible tasks available.<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-24110765947260170022016-06-28T11:24:00.000-04:002016-06-28T11:30:48.155-04:00Curious CustomerI currently work on a pretty small team, 4 devs (including myself). We have no one dedicated strictly to QA. A few years ago we ran into a few unexpected issues with our software. I hesitate to call them bugs, because they only appeared when you did things that made little sense. We write internal-only software, thus we expect a minimum level of competency from our users. In addition, it's tempting justify ignoring problematic nonsensical behavior in the name of not having to write and maintain additional software.
<br><br>
But, when I wasn't in denial, I was willing to admit that these were in fact bugs and they were costing us time.
<br><br>
The problems caused by these bugs were small, e.g. a burst of worthless emails, a blip in data flowing to the application. The emails could be quickly deleted, and the application was eventually consistent. Thus I pretended as though these issues were of low importance, and that the pain was low for both myself and our customers. I imagine that sounds foolish; in retrospect, it was foolish. The cost of developer context switching is often very high, higher if it's done as an interrupt. Introducing noise into your error reporting devalues your error reporting. Users can't as easily differentiate between good data, a blip of bad data due to something they did, and actual bad data, thus they begin to distrust all of the data.
<br><br>
The cost of these bugs created by nonsensical behavior is high, much higher than the cost of writing and maintaining the software that eliminated these bugs.
<br><br>
Once we eliminated these bugs, I spent notably more time happily focused on writing software. For me, delivering features is satisfying; conversely, tracking down issues stemming from nonsensical behavior always feels like a painfully inefficient task. I became very intent on avoiding that inefficiency in the future. The team brainstormed on how to address this behavior, and honestly we came up with very little. We already write unit tests, load tests, and integration tests. Between all of our tests, we catch the majority of our bugs before they hit production. However, this was a different type of bug, created by behavior a developer often wouldn't think of, thus a developer wasn't very likely to write a test that would catch this issue.
<br><br>
I proposed an idea I wasn't very fond of, the Curious Customer (CC): upon delivery of any feature you could ask another developer on the team to use the feature in the staging environment, acting as a user curiously toying with all aspects of the feature.
<br><br>
Over a year later, I'm not sure it's such a bad idea. In that year we've delivered several features, and (prior to release) I've found several bugs while playing the part of CC. I can't remember a single one of them that would have led to a notable problem in production; however all of them would have led to at least one support call, and possibly a bit less trust in our software.
<br><br>
My initial thought was: asking developers to context switch to QAing some software they didn't write couldn't possibly work, could it? Would they give it the necessary effort, or would they half-ass the task and get back to coding?
<br><br>
For fear of half-ass, thus wasted effort, I tried to define the CC's responsibilities very narrowly. CC was an option, not a requirement; if you delivered a feature you could request a CC, but you could also go to production without a CC. A CC was responsible for understanding the domain requirements, not the technical requirements. It's the developers responsibility to get the software to staging, the CC should be able to open staging and get straight to work. If the CC managed to crash or otherwise corrupt staging, it was the developers responsibility to get things back to a good state. The CC doesn't have an official form or process for providing feedback; The CC may chose email, chat, or any mechanism they prefer for providing feedback.
<br><br>
That's the idea, more or less. I've been surprised and pleased at the positive impact CC has had. It's not life changing, but it does reduce the number of support calls and the associated waste with tracking down largely benign bugs, at least, on our team.
<br><br>
You might ask how this differs from QA. At it's core, I'm not sure it does in any notable way. That said, I believe traditional QA differs in a few interesting ways. Traditional QA is often done by someone whose job is exclusively QA. With that in mind, I suppose we could follow the "devops" pattern and call this something like "devqa", but that doesn't exactly roll off the tongue. Traditional QA is also often a required task, every feature and/or build requires QA sign off. Finally, the better QA engineers I've worked with write automated tests that continually run to prevent regression; A CC may write a script or two for a single given task, but those scripts are not expected to be valuable to any other team member now or for anyone (including the author) at any point in the future.<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-37354977620799113492016-06-16T07:21:00.000-04:002016-06-16T07:22:16.554-04:00Maintainability and Expect LiteralsRecently, Stephen Schaub asked the following on the <a href="http://group.wewut.com">wewut group</a>:<br/>
<blockquote>
Several of the unit test examples in the book verify the construction of both HTML and plain text strings. Jay recommends using literal strings in the assertions. However, this strikes me as not a particularly maintainable approach. If the requirements regarding the formatting of these strings changes (a very likely scenario), every single test that verifies one of these strings using a literal must be updated. Combined with the advice that each test should check only one thing, this leads to a large number of extremely brittle tests.
<br><br>
Am I missing something here? I can appreciate the reasons Jay recommends using literals in the tests. However, it seems that we pay a high maintainability price in exchange for the improved readability.
</blockquote>
I responded to Stephen; however, I've seen similar questions asked a few times. Below are my extended thoughts regarding literals as expected values.
<br><br>
In general, given the option of having many similar strings (or any literal) vs a helper function, I would always prefer the literal. When a test is failing I only care about that single failing test. If I have to look at the helper function I no longer have the luxury of staying focused on the single test; now I need to consider what the helper function is giving me and what it's giving all other callers. Suddenly the scope of my work has shifted from one test to all of the tests coupled by this helper function. If this helper function wasn't written by me, this expansion in scope wasn't even my decision, it was forced upon me by the helper function creator. In the best case the helper function could return a single, constant string. The scope expansion becomes even worse when the helper function contains code branches.
<br><br>
As for alternatives, my solution would depend on the problem. If the strings were fairly consistent, I would likely simply duplicate everything knowing that any formatting changes can likely be addressed using a bulk edit via find and replace. If the strings were not consistent, I would look at breaking up the methods in a way that would allow me to verify the code branches using as little duplication as possible, e.g. if I wanted to test a string that dynamically changed based on a few variables, I would look to test those variables independently, and then only have a few tests for the formatting.
<br><br>
A concrete example will likely help here. Say I'm writing a trading system and I need to display messages such as
<br><br>
<code>"paid 10 on 15 APPL. $7 Commission. spent: $157"<br>
"paid 1 on 15 VTI. Commission free. spent: $15"<br>
"sold 15 APPL at 20. $7 Commission. collected: $293"<br>
"sold 15 VTI at 2. Commission free. collected: $30"<br>
</code>
<br>
There's quite a bit of variation in those messages. You could have 1 function that creates the entire string:<br>
<code>confirmMsg(side, size, px, ticker)</code>
<br><br>
However, I think you'd end up with quite a few verbose tests. Given this problem, I would look to break down those strings into smaller, more focused functions, for example:
<br><br>
<code>
describeOrder(side, size, px, ticker)<br>
describeCommission(ticker)<br>
describeTotal(side, size, px, ticker)<br>
</code><br>
Now that you've broken down the function, you're free to test the code paths of the more focused functions, and the test for confirmMsg becomes trivial. Something along the lines of
<br><pre>
assertEquals("paid 10 on 15 APPL",
describeOrder("buy", 10, 15, {tickerName:"APPL",commission:"standard"}))
assertEquals("sell 15 APPL at 10",
describeOrder("sell", 10, 15, {tickerName:"APPL",commission:"standard"}))
assertEquals("$7 Commission",
describeCommission({tickerName:"APPL",commission:"standard"}))
assertEquals("Commission free",
describeCommission({tickerName:"APPL",commission:"free"}))
assertEquals("spent: $157",
describeOrder("buy", 10, 15, {tickerName:"APPL",commission:"standard"}))
assertEquals("collected: $143",
describeOrder("sell", 10, 15, {tickerName:"APPL",commission:"standard"}))
assertEquals("spent: $150",
describeOrder("buy", 10, 15, {tickerName:"APPL",commission:"free"}))
assertEquals("collected: $150",
describeOrder("sell", 10, 15, {tickerName:"APPL",commission:"free"}))
assertEquals("order. commission. total",
confirmMsg("order", "commission", "total"))
</pre>
I guess I could summarize it by saying, I should be able to easily find and replace my expected literals. If I cannot, then I have an opportunity to further break down a method and write more focused tests on the newly introduced, more granular tests.<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-46941213439616907282015-06-25T09:47:00.004-04:002015-06-25T09:48:04.740-04:00Drop BooksThe vast majority of books I purchase are for my own enjoyment, but not all of them. There are a few books that I buy over and over, and drop on the desks of friends and colleagues. These books, all technical, are books that I think most programmers will benefit from reading. I call these books "Drop Books"; I drop them and never expect them to be returned.
<br/><br/>
My main motivation for dropping books is to spread what I think are great ideas. Specifically, I'm always happy to spread the ideas found in the following books:
<br/><ul>
<li><a href="https://www.goodreads.com/book/show/44936.Refactoring">Refactoring</a>
<li><a href="https://www.goodreads.com/book/show/44919.Working_Effectively_with_Legacy_Code">Working Effectively with Legacy Code</a>
<li><a href="https://www.goodreads.com/book/show/6399113-the-passionate-programmer">Passionate Programmer</a>
<li><a href="https://www.goodreads.com/book/show/70156.Patterns_of_Enterprise_Application_Architecture">Patterns of Enterprise Architecture</a>
</ul>
I know a few of my friends buy Drop Books as well. Spreading solid ideas and supporting authors seems like a win/win to me; hopefully more and more people will begin to do the same.<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-11292995725326904002015-04-06T13:20:00.000-04:002015-04-06T13:20:46.512-04:00Unit Testing Points of View, Probably<a href="https://twitter.com/mfeathers">Michael Feathers</a>, <a href="https://twitter.com/marick">Brian Marick</a>, and I are collaborating to create a new book: <a href="http://utpov.com"><i>Unit Testing Points of View</i></a> ... probably.
<br /><br />
<h3>Origin</h3>
In 2014 <a href="https://twitter.com/martinfowler">Martin Fowler</a> provided Technical Review for <a href="http://leanpub.com/wewut">Working Effectively with Unit Tests</a>. As part of his feedback he said something along the lines of: <i>I'm glad you wrote this book, and I'll likely write a <a href="http://martinfowler.com/bliki/">bliki</a> entry noting what I agree with and detailing what I would do differently</i>. I'm still looking forward to that entry, and I think the idea is worth extending beyond Martin.
<br /><br />
Unit testing is now mainstream, has tons of entry level books, and has a great <a href="http://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054">reference book</a>. The result is a widely accepted idea that you can quickly and easily adopt; unfortunately, I've found little in the way of documenting pattern trade-offs. I believe that combination leads to a lot of waste. To help avoid some of that waste, I'd like to see more written about why you may want to choose one Unit Testing style over another. That was the inspiration and my goal for <a href="http://leanpub.com/wewut">Working Effectively with Unit Tests</a>. <a href="http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/0321503627">Growing Object-Oriented Software</a> is another great example of a book that documents both the hows and whys of unit testing. After that, if you're looking for tradeoff guidance... good luck.
<br /><br />
Is this a problem? I think so. Without discussion of tradeoffs, experience reports, and concrete direction you end up with hours wasted on bad tests and proclamations of TDD's death. The report of TDD's death was an exaggeration, and the largest clue was the implication that TDD and Unit Testing were synonymous. To this day, Unit Testing is still largely misunderstood.
<br /><br />
<h3>What could be</h3>
<a href="http://leanpub.com/wewut">Working Effectively with Unit Tests</a> starts with one set of opinionated Unit Tests and evolves to the types of Unit Tests that I find more productive. There's no reason this evolution couldn't be extended by other authors. This is the vision we have for Unit Testing Points of View. Michael, Brian, and I began by selecting a common domain model. The first few chapters will detail the hows and whys of how I would test the common domain model. After I've expressed what motivates my tests, Brian or Michael will evolve the tests to a style they find superior. After whoever goes second (Brian or Michael) finishes, the other will continue the evolution. The book will note where we agree, but the majority of the discussion will occur around where our styles differ and what aspect of software development we've chosen emphasize by using an alternative approach.
<br /><br />
Today, most teams fail repeatedly with Unit Tests, leading to (at best) significant wasted time and (at worst) abandoning the idea with almost nothing gained. We aim to provide tradeoff guidance that will help teams select a Unit Testing approach that best fits their context.
<br /><br />
As I said above: <i>There's no reason this evolution couldn't be extended by other authors</i>. In fact, that's our long term hope. Ideally, Brian, Michael and I write volume one of <a href="http://utpov.com">Unit Testing Points of View</a>. Volume two could be written by <a href="https://twitter.com/kevlinhenney">Kevlin Henney</a>, <a href="https://twitter.com/sf105">Steve Freeman</a>, and <a href="https://twitter.com/royosherove">Roy Osherove</a> - or anyone else who has interest in the series. Of course, given the original inspiration, we're all hoping Martin Fowler clears some time in his schedule to take part in the series.
<br /><br />
<h3>Why "Probably"?</h3>
Writing a book is almost always a shot in the dark. Martin, Michael, Brian, and I all think this a book worth writing (and a series worth starting), but we have no idea if people actually desire such a book. In the past you took the leap expecting failure and praying for success. Michael, Brian, and I believe there's a better way: leanpub interest lists (<a href="https://leanpub.com/utpov">here's Unit Testing Points of View's</a>). We're looking for 15,000 people to express interest (by providing their email addresses). I'm writing the first 3 chapters, and they'll be made available when we cross the 15k mark. At that point, Michael and Brian will know that the interest is real, and their contributions need to be written. If we never cross the 15k mark then we know such a book isn't desired, and we shouldn't waste our time.
<br /><br />
If you'd like to see this project happen, please do sign up on the <a href="https://leanpub.com/utpov">interest list</a> and encourage others to as well (<a href="https://twitter.com/thejayfields/status/584426705198194688">here's a tweet to RT</a>, if you'd like to help). <div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-68180483318217418902015-03-15T17:48:00.000-04:002015-03-16T11:24:37.435-04:00My Answers for Microservices Awkward QuestionsEarlier this year, Ade published <i><a href="http://blog.oshineye.com/2015/01/awkward-microservices-questions.html">Awkward questions for those boarding the microservices bandwagon</a></i>. I think the list is pretty solid, and (with a small push from Ade) I decided to write concise details on my experience.
<br />
<br />
I think it's reasonable to start with a little context building. When I started working on the application I'm primarily responsible for microservices were very much fringe. Fred George was already giving (great) presentations on the topic, but the idea had gained neither momentum nor hype. I never set out to write "microsevices"; I set out to write a few small projects (codebases) that collaborated to provide a (single) solid user experience.
<br />
<br />
I pushed to move the team to small codebases after becoming frustrated with a monolith I was a part of building and a monolith I ended up inheriting. I have no idea if several small codebases are the right choice for the majority, but I find they help me write more maintainable software. Practically everything is a tradeoff in software development; when people ask me what the best aspect of a small services approach is, I always respond: I find accidental coupling to be the largest productivity drain on projects with monolithic codebases. Independent codebases reduce what can be reasonably accidentally coupled.
<br />
<br />
As I said, I never set out to create microservices; I set out to reduce accidental coupling. 3 years later, it seems I have around 3 years of experience working with Microservies (according to the <a href="http://en.wikipedia.org/wiki/Microservices">wikipedia definition</a>). I have nothing to do with microservices advocacy, and you shouldn't see this entry as confirmation or condemnation of a microservices approach. The entry is an experience report, nothing more, nothing less.
<br />
<br />
On to Ade's questions (in bold).
<br />
<br />
<b>Why isn't this a library?</b>:<br />
It is. Each of our services compile to a jar that can be run independently, but could just as easily be used as a library.<br />
<br />
<b>What heuristics do you use to decide when to build (or extract) a service versus building (or extracting) a library?</b>:<br />
Something that's strictly a library provides no business value on it's own.<br />
<br />
<b>How do you plan to deploy your microservices?</b>:<br />
Shell scripts copy jars around, and we have a web UI that provides easy deployment via a browser on your laptop, phone, or anywhere else.<br />
<br />
<b>What is your deployable unit?</b>:<br />
A jar.<br />
<br />
<b>Will you be deploying each microservice in isolation or deploying the set of microservices needed to implement some business functionality?</b>:<br />
In isolation. We have a strict rule that no feature should require deploying separate services at the same time. If a new feature requires deploying new versions of two services, one of them must support old and new behavior - that one can be deployed first. After it's run in production for a day the other service can be deployed. Once the second service has run in production for a day the backwards compatibility for the first service can be safely removed.<br />
<br />
<b>Are you capable of deploying different instances (where an instance may represent multiple processes on multiple machines) of the same microservice with different configurations?</b>:<br />
If I'm understanding your question correctly, absolutely. We currently run a different instance for each trading desk.<br />
<br />
<b>Is it acceptable for another team to take your code and spin up another instance of your microservice?</b>:<br />
Yes.<br />
<br />
<b>Can team A use team B's microservice or are they only used within rather than between teams?</b>:<br />
Anyone can request a supported instance or fork individual services. If a supported instance is requested the requestor has essentially become a
customer, a peer of the trading desks, and will be charged the appropriate costs allocated to each customer. Forking a service is free, but comes with zero guarantees. You fork it, you own it.<br />
<br />
<b>Do you have consumer contacts for your microservices or is it the consumer's responsibility to keep up with the changes to your API?</b>:<br />
It is the consumer's responsibility.
<br /><br />
<b>Is each microservice a snowflake or are there common conventions?</b>:<br />
There are common conventions, and yet, each is also a snowflake. There are common libraries that we use, and patterns that we follow, but many services require sightly different behavior. A service owner (<a href="http://blog.jayfields.com/2015/02/experience-report-weak-code-ownership.html">or primary</a>) is free to make whatever decision best fits the problem space.
<br /><br />
<b>How are these conventions enforced?</b>:<br />
Each service has a primary, who is responsible for ensuring consistency (<a href="http://blog.jayfields.com/2015/02/experience-report-weak-code-ownership.html">more here</a>). Before you become a primary you'll have spent a significant amount of time on the team; thus you'll be equipped with the knowledge required to apply conventions appropriately.<br />
<br />
<b>How are these conventions documented?</b>:<br />They are documented strictly by the code.<br />
<br />
<b>What's involved in supporting these conventions?</b>:<br />When you first join the team you pair exclusively for around 4 weeks. During those 4 weeks you drive the entire time. By pairing and being the primary driver, you're forced to become comfortable working within the various codebases, and you have complete access to someone who knows the history of the overall project. Following those 4 weeks you're free to request a pair whenever you want. You're unlikely to become a service owner until you've been on the team for at least 6 months.
<br />
<br />
<b>Are there common libraries that help with supporting these conventions?</b>:<br />A few, but not many to be honest. Logging, <a href="http://jayfields.com/expectations/">testing</a>, and <a href="https://github.com/jaycfields/jry">some common functions</a> - that's about it.<br />
<br />
<b>How do you plan to monitor your microservices?</b>:<br />We use proprietary monitoring software managed by another team. We also have front line support that is on call and knows who to contact when they encounter issues they cannot solve on their own.<br />
<br />
<b>How do you plan to trace the interactions between different microservices in a production environment?</b>:<br />
We log as much as is reasonable. User generated interactions are infrequent enough that every single one is logged. Other interactions, such as snapshots of large pieces of data, or data that is updated 10 or more times per second, are generally not logged. We have a test environment were we can bring the system up and mirror prod, so interactions we miss in prod can (likely) be reproduced in dev if necessary. A few of our systems are also experimenting with a logging system that logs every interaction shape, and a sample per shape. For example, if the message {foo: {bar:4 baz:45 cat:["dog", "elephant"]}} is sent, the message and the shape {foo {bar:Int, baz:Int, cat:[String]}} will be logged. If that shape previous existed, neither the shape nor the message will be logged. In practice, logging what you can and having an environment to reproduce what you can't log is all you need 95% of the time.<br />
<br />
<b>What constitutes a production-ready microservice in your environment?</b>:<br />Something that provides any value whatsoever, and has been hardened enough that it should create zero production issues under normal working circumstances.<br />
<br />
<b>What does the smallest possible deployable microservice look like in your environment?</b>:<br />A single webpage that displays (readonly) data it's collecting from various other services.<br />
<br />
I'm happy to share more of my experiences with a microservice architecture, if people find that helpful. If you'd like elaboration on a question above or you'd like an additional question answered, please leave a comment.<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-943589294542580412015-02-23T10:00:00.001-05:002015-02-23T10:00:49.396-05:00Experience Report: Weak Code OwnershipIn 2006 Martin Fowler wrote about <a href="http://martinfowler.com/bliki/CodeOwnership.html">Code Ownership</a>. It's a quick read, I'd recommend checking it out if you've never seen it. At the time I was working at ThoughtWorks; I remember thinking "Clearly Strong makes no sense and I have no idea what scenario would make Weak reasonable". 8 years later, I find myself advocating for Weak Code Ownership within my team.
<br><br>
Collective Code Ownership (CCO) served me well between 2005 and 2009. Given the make-up of the teams that I was a part of I found it to be the most effective way to deliver software. Around 2009 I joined a team that eventually grew to around 9 people, all very senior developers. The team practiced Collective Code Ownership. Everyone on the team was very talented, but that didn't translate to constant agreement. In fact, we disagreed far more often than I thought we should. That experience drove me to write about the importance of <a href="http://blog.jayfields.com/2011/01/compatible-opinions-on-software.html">Compatible Opinions</a>. I still believe in the importance of compatible opinions, but I now wonder if the team wouldn't have been more effective (despite incompatible opinions) if we had adopted Weak Code Ownership.
<br><br>
The 2009 project heavily shaped my approach to developing software. I suspect I'm not the only one who (at one time) believed: if we get a team full of massively talented people we can do anything. It turns out, it's not nearly that easy. Too many cooks in the kitchen is the obvious concern, and it does come up. However, the much larger problem is that talented people work in vastly different ways. Some meticulously refactor in small steps, others make wide reaching and large changes. Some prefer one language to rule them all, others are comfortable switching between 12-15 different languages in the same day. Monolithic vs separated codebases. Inherited vs duplicated config. It goes on and on. You try to optimize for everyone, to ensure everyone is maximally effective. Pretty quickly you run into this situation-
<blockquote>
If you optimize everything, you will always be unhappy.
--Donald Knuth</blockquote>
Looking back, I believe our "Collective Code Ownership" degraded to "Last in Wins". People began to cluster around shared opinions as the team grew. Inevitably the components of the project splintered and work included constant angling to ensure you only worked in areas designed to match your personal style. Perhaps that wasn't such a bad thing, but never formalizing the splinters led to constant discussion around responsibility and design. Those discussions always felt like waste to me.
<br><br>
I eventually left that team, and I left with the feeling that as a team we'd been ignoring <a href="http://en.wikipedia.org/wiki/Diffusion_of_responsibility">Diffusion of responsibility (DOR)</a>, <a href="http://en.wikipedia.org/wiki/Bystander_effect">Bystander effect (BE)</a>, and <a href="http://en.wikipedia.org/wiki/Crowd_psychology">Crowd psychology (CP)</a>. In my opinion the combination of (exclusively) talented, senior developers and collective code ownership led to suboptimal productivity. The belief that "CCO works and we're just doing it wrong" made things worse. It seemed like our solution was always: we just need to do better. You could write this team off as not as talented as I describe, but you'd be mistaken. All of the developers on the team had great success before the project, and (after that team split up) 8 out of 9 have gone on to <b>lead</b> very successful teams.
<br><br>
Several years later I found myself leading a team that was beginning to grow. We had just expanded to a 4 person team, and I could see the high level problems beginning to appear. Consistency had begun slip, and bugs had begun to appear in places where code was "correct" at the micro level, but the system didn't work as expected at the macro level. There are a few ways to manage these issues, pair programming was an obvious solution to this problem, but I believe pair programming would have introduced a different class of problems. I believe switching to pair programming (exclusively) would actually have been net negative for the team. I've written about <a href="http://blog.jayfields.com/2011/08/life-after-pair-programming.html">giving up on exclusive pair programming</a>, I'll leave it at that. The issues we were facing felt vaguely familiar, and I started to wonder if they stemmed from DOR, BE, and CP. Collective code ownership allowed developers to pop in and out of codebases, making small changes to enable features, but where was the person looking at the big picture? "It's everyone's responsibility" wasn't an answer I was comfortable with.
<br><br>
I found myself looking for another solution that would
<ul>
<li>encourage consistency
<li>give equal importance to macro and micro quality
<li>address the other issues caused by DOR, BE, and CP
</ul>
We already had our project split in a microservices style, and I proposed to the team that we move to what I called Primary Code Ownership. Primary Code Ownership can be described as-
<ul>
<li>A codebase has a "primary", the person who's responsible for that process in production. You could use the word "owner", but I don't think it conveys what I'm looking for. The team still owns the code, but when problems occur the responsibility falls on the primary first.
<li>The primary drives the architecture of the codebase. The primary gets final say on architectural decisions within a codebase.
<li>A primary may commit to master a codebase without code review.
<li>Any commit to master from a non-primary must come via a Pull Request, and only primaries can merge (or give permission for the non-primary to merge).
<li>note: in emergency circumstances, anyone can commit to any codebase.
<li>Primaries can change at any time. If a primary feels that another team member is better suited to become the primary they can propose a switch.
<li>Rotation of primary responsibility occurs naturally as people contribute to different codebases. If you seek to become a primary of a codebase, all you need to do is focus your efforts on features that require changing said codebase. If you're doing the majority of the work in that codebase, you should become the primary in a reasonable amount of time.
</ul>
The motivation for this approach is that a primary will commit keeping their vision in mind. Non-primaries can continue to commit to the same codebase, and are given the confidence that if they make a consistency or macro mistake the primary will catch it during Pull Request review.
<br><br>
We've been working with this approach for about a year now and I've been happy with the results. We've had 1 major bug in 12 months and our architecture has remained consistent despite losing 1 team member and gaining 2 more (team size is 5 now). It's probably worth mentioning that my team is entirely remote as well, making those results even more impressive (imo).
<br><br>
A nice side effect of this approach is eased on-boarding of new team-members. After an initial stretch of about a month of co-located pair programming, a new team member is free to work on whatever they want. They can work knowing that their changes will be reviewed by someone with deep understanding of the necessary changes. The rest of the team is confident that the newbie's changes shouldn't cause prod issues, and wont be merged until they're consistent with existing conventions. Another nice side effect of this process (pointed out by <a href="https://twitter.com/danielbodart">Dan Bodart</a>) is that some people are more inclined to polish their code if they know it's going to be featured in a pull request.
<br><br>
It's not (and never is) all roses. Primaries do complain at times about the context switches required to merge pull requests. I haven't found a solution to this issue, yet. In the beginning people complained about having to create branches and create pull requests. However, as the team got comfortable with this workflow, the pain seemed to disappear. Pull requests are often fairly small; the issues do not mirror the complaints against feature branches.
<br><br>
While reviewing this entry <a href="https://twitter.com/jakemcc">Jake McCrary</a> and others pointed out that while context switching is annoying, there are many benefits that also come from the pull request review process. I agree with this observation, and I'm always pleased when I see discussion (comments) occur on a pull request. Perhaps I'm over optimistic, but I always see the discussion as evidence that the team is learning from each other and we are further advancing on our shared goals.
<br><br>
12 months in, I'm happy with the results.
<br><br>
Unsurprisingly, there are other people using and/or experimenting with similar approaches. <a href="https://twitter.com/nasrat">Paul Nasrat</a> noted the similarities with this approach and the maintainer model of Linux; Scott Robinson pointed me at <a href="http://www.chromium.org/developers/owners-files">OWNERS Files</a>; <a href="https://twitter.com/romillyc">Romily Cocking</a> noted the similarities with the underlying model used in Envy/Developer (pre Java).
<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-36270534926976829832015-01-08T10:23:00.000-05:002015-01-08T10:23:23.889-05:00Preview Arbitrary HTMLI'm a big fan of <a href="https://gist.github.com/">https://gist.github.com/</a> for sharing code. It's fantastic for quickly putting something online to talk over with someone else. I've often found myself wishing for something that allowed me to share rendered HTML in the same way.
<br><br>
For example, a gist of the HTML for this blog entry can be seen here: <a href="https://gist.github.com/jaycfields/82e2cc0a588bd83a91f4">https://gist.github.com/jaycfields/82e2cc0a588bd83a91f4</a>. If I want someone to give me feedback on the rendered output, that gist isn't very helpful.
<br><br>
It turns out, it's really easy to see that HTML rendered: switch the file extension to <code>md</code>. Here's the same gist with a md extension: <a href="https://gist.github.com/jaycfields/e383b12b6ff9bd49c40a">https://gist.github.com/jaycfields/e383b12b6ff9bd49c40a</a>
This all works due to the way Github renders markdown gists, and markdown supporting inline HTML.
<br><br>
I wouldn't use this trick to create any data you'd like to have online in the long term, but it's great for sharing short lived HTML.<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-1495932450743062832015-01-07T08:45:00.000-05:002015-01-07T08:45:01.827-05:00LTR Org ChartMost traditional organizations have an Org Chart that looks similar to the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdYdVXFHXzwwAg0YImfFfRfNdcWFCSCXX08WCc0oFhf074v0rL49GkqIN6aeuHKHvkJxxR5oV0tWQxdosDEOtvV4FXqTvoIvZNTJcik2I_jTAzQZKXoh1SzoUJkNRPDIHjH-os/s1600/top-down-org.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdYdVXFHXzwwAg0YImfFfRfNdcWFCSCXX08WCc0oFhf074v0rL49GkqIN6aeuHKHvkJxxR5oV0tWQxdosDEOtvV4FXqTvoIvZNTJcik2I_jTAzQZKXoh1SzoUJkNRPDIHjH-os/s1600/top-down-org.png" /></a></div>
<br />
Org Charts displayed in this way emphasize the chain of command. A quick look at a node in this Org Chart will let you know who someone reports to and who reports to them. The chart gives a clear indication of responsibility; it also gives an impression of "who's in charge" and how far away you are from the top.<br />
<br />
Several years ago I joined <a href="http://www.thoughtworks.com/" target="_blank">ThoughtWorks</a> (TW). TW (at least, when I was there) boasted of their Flat Org Chart and it's advantages.<br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px;">A </span><b style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px;">flat organization</b><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px;"> (also known as </span><b style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px;">horizontal organization</b><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px;"> or </span><b style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px;">delayering</b><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px;">) is an organization that has an </span><a href="http://en.wikipedia.org/wiki/Organizational_structure" style="background: none rgb(255, 255, 255); color: #0b0080; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px; text-decoration: none;" title="Organizational structure">organizational structure</a><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px;"> with few or no levels of middle </span><a href="http://en.wikipedia.org/wiki/Management" style="background: none rgb(255, 255, 255); color: #0b0080; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px; text-decoration: none;" title="Management">management</a><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px;"> between </span><a class="mw-redirect" href="http://en.wikipedia.org/wiki/Employees" style="background: none rgb(255, 255, 255); color: #0b0080; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px; text-decoration: none;" title="Employees">staff</a> <span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.399999618530273px;">and executives. <a href="http://en.wikipedia.org/wiki/Flat_organization" target="_blank">wikipedia</a></span></blockquote>
A Flat Org Chart may look something like the following image.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijsNpbCnOdDEiKxjGc-nuMkdJKFTSXR1mXkWY17BcxVfao68-EximWKEsXXZClE29z7W6IZ6uVKO2kujox2e5jtXv_5GCwh0gvmxxaDnKRefZw1eUJglk9k2KEFbgnl4PyVS_p/s1600/flat.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijsNpbCnOdDEiKxjGc-nuMkdJKFTSXR1mXkWY17BcxVfao68-EximWKEsXXZClE29z7W6IZ6uVKO2kujox2e5jtXv_5GCwh0gvmxxaDnKRefZw1eUJglk9k2KEFbgnl4PyVS_p/s1600/flat.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
I've previously written on how joining TW was the <a href="http://blog.jayfields.com/2012/05/single-best-thing-for-my-career.html" target="_blank">single best thing for my career</a>. There were many things I loved about TW - the Flat Org Chart was not one of those things.<br />
<br />
The (previously linked) wikipedia article discusses the positive aspects of Flat Organizations - there are several I would agree with. What I find generally missing from the discussion is responsibility. If I make a mistake, who, other than me, could have helped me avoid that mistake? If I need help, whose responsibility is it to ensure I get the help I need? If I'm unhappy and plan to quit, who's going to understand my value and determine what an appropriate counter offer looks like?<br />
<br />
In a flat organization, this is me:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpw43SMWirTUAJXCC7kWIGawry5ioXhMF6pybHAt9Bahp-aZdhqg5avbagxbXRwuUWY_iTr2fC6ayhEnFz1HQ2jt746uLq5__mHTJZWJt4mQ9Zhv2GiKzQ_lhifj9ruVtOOhGo/s1600/flat-and-me.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpw43SMWirTUAJXCC7kWIGawry5ioXhMF6pybHAt9Bahp-aZdhqg5avbagxbXRwuUWY_iTr2fC6ayhEnFz1HQ2jt746uLq5__mHTJZWJt4mQ9Zhv2GiKzQ_lhifj9ruVtOOhGo/s1600/flat-and-me.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Reporting to, thus having access to the person who reports directly to the CEO is great. At the same time, over a hundred other people report to the same person. Would anyone honestly argue that this one individual can guide, mentor, and properly evaluate over a hundred people?</div>
<br />
Whenever I bring up responsibility people quickly point out that: those are <b>everyone's</b> issues and it's <b>everyone's</b> responsibility. I generally point these people at <a href="http://en.wikipedia.org/wiki/Diffusion_of_responsibility" target="_blank">Diffusion of responsibility</a>, <a href="http://en.wikipedia.org/wiki/Bystander_effect" target="_blank">Bystander effect</a>, and <a href="http://en.wikipedia.org/wiki/Crowd_psychology" target="_blank">Crowd psychology</a>. Personally, I'd love to see the result of, following a resignation, "everyone" determining an individual's value and producing a counter offer.<br />
<br />
I'm thankful for the experience I gained working in a Flat Organization. I'll admit that there's something nice about being one manager away from the CEO on an Org Chart. That said, it was the <b>access</b> to a high level manager and the CEO that I found to be the largest benefit of working in a Flat Organization.<br />
<br />
I eventually left TW - a move that was partially motivated by the issues I described above. When I began looking for a new job, organizational structure didn't factor into my decision making process, but I did look for something I called Awesome All the Way Up.<br />
<blockquote class="tr_bq">
Awesome All the Way Up: Given an Org Chart, do you consider the CEO and every person between you and the CEO to be awesome.</blockquote>
I believed then, and I believe now that you'll always be best off if you put yourself in Awesome All the Way Up situations. When I left TW, I only considered 2 companies - they were the only two I could find that offered Awesome All the Way Up. Everyone will likely have their own definition of "awesome". My definition of "awesome", in this context, is: above all, someone I can trust; someone whose vision I believe in; someone I will always have access to.<br />
<br />
One of the two previously referenced companies became my next (and current) employer: <a href="http://drw.com/" target="_blank">DRW Trading</a>. DRW could have a traditional Org Chart, and I would sit towards the "bottom" of it. (note: this is an approximation, not an actual DRW Org Chart.)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfa37FUsHf-SBNl03lVUPb_miOqu7qD5Vhu1W8XJrubc1XXEestGmXsqT7FZXv9Y0KhY2na7NE5tjl2030xHawsXtWBFF1T_ktQZubeTruheEJuevp9ELlKXyYZmfrAMPtwddM/s1600/top-down-and-me.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfa37FUsHf-SBNl03lVUPb_miOqu7qD5Vhu1W8XJrubc1XXEestGmXsqT7FZXv9Y0KhY2na7NE5tjl2030xHawsXtWBFF1T_ktQZubeTruheEJuevp9ELlKXyYZmfrAMPtwddM/s1600/top-down-and-me.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Personally, I wouldn't have any complaints with this Org Chart. Every person between me and DRW himself plays an important and specific role. Since I'm in an Awesome All the Way Up situation I have access to each of those people. If I have a CSO problem, I go to the CSO; if I have a CTO problem I go to the CTO; you get the idea. I strongly prefer to know whose responsibility it is when I identify what I consider to be a problem.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You may have noticed I said DRW <b>could </b>have an Org Chart similar to what's above. The phrasing was intentional - if you ask our CSO Derek we have an <a href="https://www.google.com/search?q=upside+down+org+chart" target="_blank">upside down Org Chart</a>. I'm not sure which of those articles best reflects his opinion. He once showed me a picture similar to the one below and said "part of being a leader is understanding that the shit still rolls downhill, but our hill is different".</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/AVvXsEiNHIft5F0LvekyU-KNz-icUpo15FL645gOOWTw1fdASqsaNdR8sUYOeL3_TTuy51FYbastax6pGmMwkKlKBixE0d5iyk-xyeHOEWQphFkrClixTmJMSpAGmUONT3_6Cs_xs777/s1600/top-down-and-me.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNHIft5F0LvekyU-KNz-icUpo15FL645gOOWTw1fdASqsaNdR8sUYOeL3_TTuy51FYbastax6pGmMwkKlKBixE0d5iyk-xyeHOEWQphFkrClixTmJMSpAGmUONT3_6Cs_xs777/s1600/top-down-and-me.png" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
Derek and I haven't spoken extensively on the upside down Org Chart, but I assume he's a fan of <a href="http://en.wikipedia.org/wiki/Servant_leadership" target="_blank">Servant Leadership</a>. As an employee I (obviously) appreciate the upside down Org Chart and Derek's approach to leadership. As a team lead I find the upside down Org Chart to be a great reminder that I need to put the needs of my teammates first. As someone sitting above Derek on the upside down Org Chart I find the idea of my shit (and the shit of all of my "peers") rolling down to Derek to be... unpleasant.<br />
<br />
I was once out with one of the partners from DRW and he introduced me to a friend of his (John). John asked how I knew the DRW partner, I said: he's my boss. The DRW partner interrupted and said: that's not true, we're teammates - I can't do what he does and he can't do what I do, we work together. The partner from this story isn't in my "chain of command", but I find the same team-first attitude present in each person that is.<br />
<br />
My discomfort with my shit rolling down on anyone combined with the team-first attitude I've encountered led me to the idea of the Left-to-Right Org Chart (or LTR Org Chart). Below you'll find what would be my current LTR Org Chart.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqcvr_gtLxeZNjwqi0IeuixqXAYrMOujIequNyzLAo2YvNM3P7Wjvr7MKmvFrW6vaNuRNgU2mecSkfQWEazIXB5jHieCu7nm1ws-Q3SYi4zJRzRK5ZpeeOd-OvUjfGOay0mdRW/s1600/ltr.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqcvr_gtLxeZNjwqi0IeuixqXAYrMOujIequNyzLAo2YvNM3P7Wjvr7MKmvFrW6vaNuRNgU2mecSkfQWEazIXB5jHieCu7nm1ws-Q3SYi4zJRzRK5ZpeeOd-OvUjfGOay0mdRW/s1600/ltr.png" /></a></div>
<br />
The LTR Org Chart reminds me to be a Servant Leader while also emphasizing the teammates I can count on to help me out when I encounter issues.<br />
<br />
It's probably not practical to generate an LTR Org Chart for every individual in your organization, but it certainly wouldn't be hard to create software to present an LTR Org Chart on a website. It's possible the subtle difference between upside down Org Charts and LTR Org Charts isn't worth the effort required to build the software. I wouldn't mind finding out.<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-91060785341233574362015-01-06T08:27:00.000-05:002015-01-06T08:27:00.037-05:00Making Remote Work: Tools<div>
<br /></div>
I recently wrote about <a href="http://blog.jayfields.com/2014/12/making-remote-work.html">my experiences working on a remote team</a>. Within that blog entry you can find a more verbose version of the following text:<br />
<blockquote class="tr_bq">
Communication is what I consider to be the hardest part of remote work. I haven't found an easy, general solution. A few teammates prefer video chat, others despise it. A few teammates like the wiki as a backlog, a few haven't ever edited the wiki. Some prefer strict usage of email/chat/phone for async-unimportant/async-important/sync-urgent, others tend to use one of those 3 for all communication.</blockquote>
As you can tell, we have several different communication tools. When writing, I generally prefer to include concrete examples. This blog entry will list each tool referenced above. However, I cannot emphasize enough that: <b>this list is a snapshot of what we're using, not a recommended set of tools</b>.<br />
<br />
app:<b> Github</b><br />
usage: We use many of the features of Github; however, the two features that help facilitate remote work are (a) <a href="https://help.github.com/articles/using-pull-requests/" target="_blank">pull requests</a> with inline comments and (b) <a href="https://github.com/blog/612-introducing-github-compare-view" target="_blank">compare</a>. A pull request with inline comments has (thus far) been the most productive way to asynchronously discuss specific pieces of code. Almost all non-trivial commits will eventually end up in a pull request that's reviewed by at least one other team member. We've found compare view to be the best solution for distilling changes for a teammate with limited context.<br />
<br />
app: <b>Hipchat</b><br />
usage: We have 3 hipchat rooms: work, social, support. It should be pretty obvious what we use each room for. The primary driver for splitting the 3 is for keeping noise down. Most team members look at chat history for work and support, reading anything that happened between now and the last time they were logged in. Social tends to be more verbose, often off-topic, and never required reading for keeping up with what the team is up to.<br />
<br />
app: <b>Cisco Jabber</b><br />
usage: Within the team, we primarily use Cisco Jabber for video calls; however Cisco Jabber is also a great way for people within DRW offices to reach anyone on my team without having to know their location. Cisco Jabber is significantly better than asking people to remember to call your cell, or forwarding your desk phone to your cell - it provides you 1 number that anyone can reach you at, regardless of your physical location. There's not much to say about the video capabilities, they're there, they work well. Cisco Jabber also provides desktop sharing, which we use occasionally for "remote pair-programming".<br />
<br />
app:<b> Confluence</b><br />
usage: Our backlog resides on a Confluence wiki; it's a single page with about 150 lines. The backlog is split into 3 sections: Milestones, Now, and Soon. There are generally 3-5 Milestones, which list (as sub-bullets) their dependencies. A dependency is a reference to a line item that will live in Now or Soon. Now is the list of highest priority tasks - the things we need to get down right away. Soon is the list of things that are urgent but not important, or important but not urgent. Both Now and Soon lists contain placeholders for conversations, each placeholder is around 1-2 lines. Below you'll find a contrived, sample backlog.<br />
<blockquote class="tr_bq">
Milestones
<br />
<ul>
<li>Deploy to Billy Ray Valentine</li>
<ul>
<li>(market data 1)</li>
<li>(execution 1)</li>
</ul>
<li>Automated Order Matching (stakeholder: Mortimer and Randolph Duke)</li>
<ul>
<li>(execution 2)</li>
<li>(reporting 1)</li>
</ul>
</ul>
Now
<br />
<ul>
<li>Market data</li>
<ul>
<li>(1) support pork bellies</li>
<li>support orange juice</li>
</ul>
<li>Execution</li>
<ul>
<li>(1) support pork bellies</li>
<li>(2) internally match incoming orders from customers</li>
</ul>
</ul>
Soon
<br />
<ul>
<li>Market data</li>
<ul>
<li>support coffee</li>
<li>support wheat</li>
</ul>
<li>Reporting</li>
<ul>
<li>(1) Commission summary</li>
</ul>
</ul>
</blockquote>
<blockquote class="tr_bq">
note: some things in Now need to be done immediately, but do not support an upcoming milestone. These things are incremental changes for previously met milestones.</blockquote>
Obviously we use email and other tools as well, but I can't think of any remote specific usage patterns that are worth sharing.<br />
<br />
As I previously mentioned, each member of the team uses each of these tools in their own way. None of these tools are ideal for every member of the team, and I believe a good team lead helps ensure each team member is only required to use the tools they find most helpful.<br />
<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-58211111974518106952014-12-28T14:32:00.001-05:002015-01-04T07:23:07.413-05:00Making Remote WorkOver 18 months ago I wrote <i><a href="http://blog.jayfields.com/2013/04/year-five.html" target="_blank">Year Five</a></i>, an experience report I never imagined I would write. I closed the blog entry by saying I look forward to writing about <i>Year Six</i>. A year and a half later, I'm still having a hard time deciding what (if anything) I should write. My writers block isn't the result the Remote Work experiment failing. Quite the opposite, the success of the Remote Work experiment has helped shape a team I'm very proud to be a part of, and yet I find myself unable to declare victory.<br />
<br />
"How can you work effectively with remote teammates" has become the most common question I hear when meeting up with old colleagues for coffee. Clearly people are interested in the topic. At the same time, I prefer not to write about half-baked ideas (these days), thus my apprehension in documenting my approach.<br />
<br />
This entry is an experience report, nothing more, nothing less. I'd be very skeptical of anyone providing recipes or best practices around remote work. Those working remotely today are breaking traditional workplace rules. Some are succeeding, most are failing, and I don't know of anyone with solid general advice. What follows are merely my observations.<br />
<br />
My team became remote on accident. My boss and I were a 2 person co-located team in NYC, he quit, they gave me his job, and my best option to fill my previous role lived in Chicago. <a href="https://twitter.com/dchelimsky" target="_blank">David Chelimsky</a> was willing to be in NYC 2 weeks out of the month, and I was willing to be in Chicago 1 week out of the month. It was effectively co-location, and our team ran that way for a couple months.<br />
<br />
Sometime in month three I started to feel like having David in NYC 2 weeks a month was unnecessary, and (surprisingly to me) he'd independently come to the same conclusion. From that point forward we alternated on traveling 1 week a month - thus we worked remotely for 3 weeks out of 4. We saw no drop off in our productivity or camaraderie, and traveling less definitely improved our overall happiness. I'm not sure how it would have worked out if I'd been forced to try remote work; however, arriving there organically was surprisingly painless.<br />
<br />
Eventually the team grew and <a href="http://drw.com/" target="_blank">DRW</a> hired <a href="https://twitter.com/duelinmarkers" target="_blank">John Hume</a>, who lives in Austin, Texas. I believe it's worth noting that we each lived in a different city. I've always believed that a team needs to either be completely remote or completely co-located. The team is up to 5 people at this point, and I've actively gone out of my way to ensure no two people work out of the same place on an ongoing basis.<br />
<br />
When you join the team you'll have to start on a 6 month contract. The contract period gives both you and I the opportunity to figure out if you're a good fit. There are plenty of brilliant people who I wouldn't work with: I'm looking for people with <a href="http://blog.jayfields.com/2011/01/compatible-opinions-on-software.html" target="_blank">compatible opinions on software</a> who are able to flourish in the environment we've created.<br />
<br />
Remote disagreements are hard to resolve. We can't get a beer and talk it out. I can't read your body language (or other subtle signs) and see something needs to change. Thus, it's not enough to be talented, you'll also need to be a philosophical match. The philosophical ideas are easy to agree on when everyone's looking to start a new endeavor, but best intentions don't always equal an ideal working environment. The 6 month contract ensures both parties know what we're getting into long before we discuss the idea of full time employment.<br />
<br />
My team is stretched through various timezones, sometimes from London to Los Angeles. This leaves the options of work odd hours, or finding people who can take on larger tasks and don't require constant contact. My team chose to go the latter path, and we've found no notable impact on our ability to collaborate even when our hours overlap as little as 2 hours a day. This choice is another reason the 6 month contract is critical: some people want more than 2 hours of contact a day. That's neither good, nor bad, nor is it easy to predict. If someone ends up needing more contact than they find they're getting, it's better for all parties if everyone goes their separate way after 6 months.<br />
<br />
I've found that my opinion on pair-programming and co-location is constantly evolving. In more than 2 years of working remotely, I've probably done less than 4 hours of remote pair-programming. I mention this because some people believe remote pair-programming is an essential ingredient to successful remote work. I am not one of those people.<br />
<br />
That said, I try to see my teammates as often as is reasonable, and we do often pair-program when we are co-located. At this point, I see every team member quarterly, and the entire team spends a week together every 6 months. We've found this frequency to be a solid balance between keeping relationships strong and keeping travel to a minimum.<br />
<br />
The above schedule works for ongoing collaboration; however, the beginning of a work relationship is almost the exact opposite. When a new contractor joins the team, they travel and co-locate as much as possible. A recent team member spent his first week in Austin, his second in Chicago, and his third in London. By the end of those 3 weeks he'd seen the codebase from 3 different perspectives and spent a week (mostly pairing) with every member of the (at that time, 4 person) team. That much travel is a high up-front cost, but it helps immensely with learning both the codebase and the team you'll be working with.<br />
<br />
Communication is what I consider to be the hardest part of remote work. I haven't found an easy, general solution, thus I often find myself duplicating effort to ensure teammates can consume data in their preferred format. A few teammates prefer video chat each time we're on the phone, a few teammates despise video chat. A few teammates like the wiki as a backlog, a few haven't ever edited the wiki (as far as I know). Some prefer strict usage of email/chat/phone for async-unimportant/async-important/sync-urgent, others tend to use one of those 3 for all communication. There hasn't been one tool that I would recommend; instead I think it's much more valuable to note that people prefer different approaches, and it's the job of the team lead to communicate with the team members in the way that they prefer, not the other way around. The only rule I try to apply universally: I end as many conversations as I can with "is there anything I can do to make your life better". If you constantly ask that question, it should be (often painfully) obvious what you need to change to continue to improve things for the team as a whole.<br />
<br />
The question of hardware often comes up as well, what should a company provide, what should an individual? My approach: take the cost of a 30" monitor, any laptop, a tablet, a smart phone, and anything else they'd want, then average it out over 2 years. I think you'll find the amount of money is so trivial that you'd be a fool not to buy them whatever they want. (and that you're company loses money every time you waste your time talking about such a small expenditure.)<br />
<br />
That's more or less it. I would summarize it like so: I want to create a team that people want to be a part of for at least the next 10 years. That begins by finding people who are a great fit; not everyone will be, and we'll learn valuable lessons from those people as well. We start the relationship out right, spending many hours together getting to know each other and getting to know the ins & outs of the project. From that point on we'll see if your preferred working style (hours, communication needs, etc) fit well with the team. We'll already know if you'll be happy on the team long before either of us has to commit to any long term working relationship. From there, as long as I remember that I work for the team, not the other way around, everyone should continue to be happy and effective.<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-25015050101889788172014-12-17T01:00:00.000-05:002014-12-17T01:00:05.617-05:00Working Effectively with Unit Tests Official Launch<span style="font-family: Arial, Helvetica, sans-serif;">Today marks the official release release of Working Effectively with Unit Tests. The book is available in various formats:</span><br />
<ul>
<li><span style="font-family: Arial, Helvetica, sans-serif;">DRM free pdf, epub, & mobi (Kindle) at <a href="http://leanpub.com/wewut">http://leanpub.com/wewut</a></span></li>
</ul>
<ul>
<li><span style="font-family: Arial, Helvetica, sans-serif;">Softcover at <a href="http://amzn.com/1503242706">http://amzn.com/1503242706</a></span></li>
</ul>
<ul>
<li><span style="font-family: Arial, Helvetica, sans-serif;">Kindle edition at <a href="http://amzn.com/B00QS2HXUO">http://amzn.com/B00QS2HXUO</a></span></li>
</ul>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: white; color: #222222;">I’m very happy with the final version. </span></span><span style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif;">Michael Feathers wrote a great foreword. </span><span style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif;">I incorporated feedback </span><span style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif;">from dozens of people - some that have been friends for years, and </span><span style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif;">some that I’d never previously met. </span><span style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif;">I can’t say enough great things about <a href="http://leanpub.com/">http://leanpub.com</a>, </span><span style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif;">and I highly recommend it for getting an idea out there and making it </span><span style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif;">easy to get fast feedback. </span><br />
<span style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif;">As far as the softcover edition, I had offers from a few major publishers, but in the end none of them would allow me to continue to sell on leanpub at the same time. I strongly considered caving to the demands of the major publishers, but ultimately the ability to create a high quality softcover and make it available on Amazon was too tempting to pass up.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: white; color: #222222;"><br /></span></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: white; color: #222222;">The feedback has </span><span style="background-color: white; color: #222222;">been almost universally positive - the reviews are quite solid on goodreads </span><span style="background-color: white; color: #222222;">(</span><a href="http://review.wewut.com/" style="background-color: white; color: #1155cc;" target="_blank">http://review.wewut.com</a><span style="background-color: white; color: #222222;">). I believe the book provides specific, </span><span style="background-color: white; color: #222222;">concise direction for effective Unit Testing, and I hope it helps increase the quality of the unit tests found in the wild.</span></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: white; color: #222222;"><br /></span></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: white; color: #222222;">If you'd like to try before you buy, there's a sample available in <a href="http://samples.leanpub.com/wewut-sample.pdf" target="_blank">pdf format</a> or <a href="https://leanpub.com/wewut/read" target="_blank">on the web</a>.</span></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: white; color: #222222;"><br /></span></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: white; color: #222222;"><br /></span></span>
<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-68288960746418120272014-08-25T16:50:00.002-04:002014-08-25T16:50:46.583-04:00The Case for Buying Technical Books<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.600000381469727px; margin-bottom: 16px;">
<div style="box-sizing: border-box; margin-bottom: 16px;">
<div style="box-sizing: border-box; margin-bottom: 16px;">
In the past few months I've seen more than a few articles encouraging programmers to write books. Each article provides at least a bit of good advice, and proceeds to conclude with the same idea:</div>
<blockquote style="border-left-color: rgb(221, 221, 221); border-left-style: solid; border-left-width: 4px; box-sizing: border-box; color: #777777; margin: 0px 0px 16px; padding: 0px 15px;">
<div style="box-sizing: border-box;">
<strong style="box-sizing: border-box;">You should write a book to build your brand</strong>.</div>
</blockquote>
<div style="box-sizing: border-box; margin-bottom: 16px;">
I find this conclusion accurate and extremely disappointing. If the overwhelming reason to write a book is brand building, then the pool of potential authors is restricted to people who would benefit from brand building (and people who don't value their time).</div>
<div style="box-sizing: border-box; margin-bottom: 16px;">
<strong style="box-sizing: border-box;">How Did We Get Here?</strong></div>
<div style="box-sizing: border-box; margin-bottom: 16px;">
The Internet, obviously. Practically everyone knows how to download any movie, song, or book at no cost. Opinions on "illegal downloading" range from opposition to pride. I'm not particularly interested in discussing those opinions; however, I believe it's worth observing the impact of the combination of ability and desire to acquire content without compensating the creator.</div>
<blockquote style="border-left-color: rgb(221, 221, 221); border-left-style: solid; border-left-width: 4px; box-sizing: border-box; color: #777777; margin: 0px 0px 16px; padding: 0px 15px;">
<div style="box-sizing: border-box;">
“Books aren't written - they're rewritten...” -- Michael Crichton</div>
</blockquote>
<div style="box-sizing: border-box; margin-bottom: 16px;">
If you've never written a book, you may not be aware of colossal effort it takes to write a mediocre book. When it's all said and done, it can take well over an hour of effort per page. Great books, such as <a href="http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601" rel="noreferrer" style="box-sizing: border-box; color: #4183c4; text-decoration: none;">Java Concurrency in Practice</a>, require an even greater level of attention to detail, and cost even more time to create. Brian Goetz estimates that it took them approximately 2,400 hours to create JCiP. If we also knew their royalty structure and the number of copies sold, we'd be able to calculate the hourly rate for writing a high quality book.</div>
<div style="box-sizing: border-box; margin-bottom: 16px;">
It turns out, one of the <a href="http://blog.obiefernandez.com/content/2014/04/how-to-write-and-publish-a-technical-book-and-make-lots-of-money.html" rel="noreferrer" style="box-sizing: border-box; color: #4183c4; text-decoration: none;">recent articles</a> encouraging writing gives you royalty numbers and a hint on how many copies a quality book might sell.</div>
<blockquote style="border-left-color: rgb(221, 221, 221); border-left-style: solid; border-left-width: 4px; box-sizing: border-box; color: #777777; margin: 0px 0px 16px; padding: 0px 15px;">
<div style="box-sizing: border-box; margin-bottom: 16px;">
Royalties for print should start at 18% of net revenues to the publisher. (Expect that figure to be around $10-20, so you're only making a few dollars on each sale.)</div>
<div style="box-sizing: border-box; margin-bottom: 16px;">
...</div>
<div style="box-sizing: border-box;">
Selling 10 thousand copies of a print tech book these days is a solid success and should be compensated accordingly. -- Obie Fernandez</div>
</blockquote>
<div style="box-sizing: border-box; margin-bottom: 16px;">
Let's assume JCiP was more than a solid success and sold 20K copies (doubling Obie's "solid success" benchmark). Assuming they negotiated royalties well, that would mean making $40,000 - thus the hourly rate for writing JCiP would be under $17 per hour.</div>
<div style="box-sizing: border-box; margin-bottom: 16px;">
Clearly I've made a few assumptions, but I believe all of them are based on sound logic. As long as you work 8 hours a day, 5 days a week, for 50 weeks and write a modern classic, you'll make around $34,000 per year. Anecdotal evidence among my author friends who've yet to write a modern classic is worse: the hourly rate is less than minimum wage.</div>
<div style="box-sizing: border-box; margin-bottom: 16px;">
The royalty structures combined with lessening sales create an environment where writing a book for (royalty) profit isn't a reasonable use of your time. As a result, the majority of today's authors are either consultants or unknown programmers. Established, non-consultant programmers gain little from the brand building aspect of writing a book, and likely make far more than $34,000 a year at their full-time jobs - why would they take on a poorly paying second job?</div>
<div style="box-sizing: border-box; margin-bottom: 16px;">
Around 2005 it became fairly easy to download, for free, practically any book. It might be coincidence that 10 of 13 of these <a href="https://www.wunderlist.com/lists/70326287" rel="noreferrer" style="box-sizing: border-box; color: #4183c4; text-decoration: none;">Must-Read books</a> were written prior to 2005. Despite the possibility, I don't believe it's a coincidence. Rather, I believe that at one time it paid to create a best selling technical book, and people with various backgrounds took up the challenge.</div>
<div style="box-sizing: border-box; margin-bottom: 16px;">
<strong style="box-sizing: border-box;">Nice Assumption Filled History Lesson, What's Your Point?</strong></div>
<div style="box-sizing: border-box; margin-bottom: 16px;">
My point is fairly simple. If you're, like I am, tired of having to choose between books written decades ago and books written by those with at least a slightly ulterior motive, buy some books. Does your company have a book buying policy? If you aren't spending your entire book budget, why not? It costs you nothing to buy a book and give it to a teammate, and every royalty penny reminds an author that someone cares about all of those hours writing and rewriting.</div>
<div style="box-sizing: border-box; margin-bottom: 16px;">
Even if your company doesn't have a book budget, ask yourself if you'd rather your next book about Java be written by a consultant you've never heard of or Java's language architect. The average technical book costs little compared to life's other expenses, and buying a technical book is investing in your profession twice. You stand to gain knowledge both from today's book purchase and a potential future book written by the same author - a future book that may never be written given the current financial incentives.</div>
<div style="box-sizing: border-box; margin-bottom: 16px;">
If you're a CTO, Director or Manager, why aren't you constantly buying books for the developers you work with? They could probably use your advice on which books will best guide their careers.</div>
<div style="box-sizing: border-box; margin-bottom: 16px;">
<strong style="box-sizing: border-box;">Makes Sense, What Should I Buy?</strong></div>
<div style="box-sizing: border-box; margin-bottom: 16px;">
There are several good books now available on <a href="http://leanpub.com/" rel="noreferrer" style="box-sizing: border-box; color: #4183c4; text-decoration: none;">leanpub</a> - where the authors are paid significantly higher royalties. If you want to support authors you should always start there. From there I would own at least a copy of Chad's (previously referenced) Must-Read books. I'd also buy <a href="http://pragprog.com/book/cfcar2/the-passionate-programmer" rel="noreferrer" style="box-sizing: border-box; color: #4183c4; text-decoration: none;">Chad's Passionate Programmer</a>. Finally, you can't go wrong working your way through this list: <a href="http://www.amazon.com/Clojure-Bookshelf/lm/R3LG3ZBZS4GCTH" rel="noreferrer" style="box-sizing: border-box; color: #4183c4; text-decoration: none;">Clojure Bookshelf</a>.</div>
</div>
</div>
<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-5642099987234264282014-07-16T15:55:00.003-04:002014-07-16T15:59:10.047-04:00Solitary Unit TestOriginally found in <a href="http://wewut.com/">Working Effectively with Unit Tests</a>
<br />
<br />
It’s common to unit test at the class level. The <code>Foo</code> class will have an associated <code>FooTests</code>
class. <em>Solitary Unit Tests</em> follow two additional constraints:
<br />
<ol>
<li> Never cross boundaries
</li>
<li> The Class Under Test should be the only concrete class found in a test.
</li>
</ol>
Never cross boundaries is a fairly simple, yet controversial piece of advice. In 2004, Bill Caputo wrote
about this advice, and defined a boundary as: ”...a database, a queue, another system...”. The advice
is simple: accessing a database, network, or file system significantly increases the the time it takes
to run a test. When the aggregate execution time impacts a developer’s decision to run the test suite,
the effectiveness of the entire team is at risk. A test suite that isn’t run regularly is likely to have
negative-ROI.
<br />
<br />
In the same entry, Bill also defines a boundary as: ”... or even an ordinary class if that class is ‘outside’
the area your [sic] trying to work with or are responsible for”. Bill’s recommendation is a good one,
but I find it too vague. Bill’s statement fails to give concrete advice on where to draw the line. My
second constraint is a concrete (and admittedly restrictive) version of Bill’s recommendation.
The concept of constraining a unit test such that ‘the Class Under Test should be the only concrete
class found in a test’ sounds extreme, but it’s actually not that drastic if you assume a few things.
<br />
<ol>
<li>You’re using a framework that allows you to easily stub most concrete classes
</li>
<li>This constraint does not apply to any primitive or class that has a literal (e.g. int, Integer,
String, etc)
</li>
<li>You’re using some type of automated refactoring tool.
</li>
</ol>
There are pros and cons to this approach, both of which are examined in <a href="http://wewut.com/">Working Effectively with Unit Tests</a>.
<br />
<br />
Solitary Unit Test can be defined as:
<br />
<blockquote>
Solitary Unit Testing is an activity by which methods of a class or functions of a
namespace are tested to determine if they are fit for use. The tests used to determine if
a class or namespace is functional should isolate the class or namespace under test by
stubbing all collaboration with additional classes and namespaces.
</blockquote>
<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-26218173734599434382014-06-30T20:48:00.000-04:002014-06-30T20:48:01.301-04:00Working Effectively with Unit Tests Rough Draft CompleteI finally put the finishing touches on the rough draft of <a href="http://wewut.com">Working Effectively with Unit Tests</a>. It's been an interesting journey thus far, and I'm hoping the attention to detail I've put into the rough draft will translate into an enjoyable read.
<br><br>
What I did poorly: I'd written the book's sample before I ever put it on <a href="https://leanpub.com/">leanpub</a>. Before a book is published you can collect contact and price information from those who are interested. However, once you publish and begin selling, you no longer have the ability to collect the previously mentioned information. I published and began selling my book immediately - and forfeited my chance to collect that information.
<br><br>
What I did well: I published early and often. I can't say enough nice things about leanpub. I've gotten tons of feedback on example style, writing style, typos, and content. One reader's suggestion to switch to Kevlin Henney's Java formatting style made my book enjoyable to read on a Kindle. I had twitter followers apologizing for "being pedantic and pointing out typos", and I couldn't have been happier to get the feedback. Each typo I fix makes the book more enjoyable for everyone. If you're going to write a book, get it on leanpub asap and start interacting with your audience.
<br><br>
What I learned from Refactoring: Ruby Edition (RRE): RRE <a href="http://jayfields.com/rre_errata.htm">contains errors</a>, far too many errors. I vowed to find a better way this time around, and I'm very happy with the results. Every example test in the book can be run, and uses classes also shown in the book. However, writing about tests is a bit tricky: sometimes "failure" is the outcome you're looking to document. Therefore, I couldn't simply write tests for everything. Instead I piped the output to files and used them as example output in the book, but also as verification that what failed once continued to fail in the future (and vice versa). WEwUT has a script that runs every test from the book and overwrites the output files. If the output files are unchanged, I know all the passing examples are still correctly passing, and all the failing examples are still correctly failing. In a way, git diff became my test suite output. I'm confident in all the code found in WEwUT, and happy to be able to say it's all "tested".
<br><br>
What's unclear: Using leanpub was great, but I'm not really sure how to get the word out any further at this point. I set up a <a href="https://www.goodreads.com/book/show/22605938-working-effectively-with-unit-tests">goodreads.com page</a> and many friends have been kind enough to tweet about it, but I don't really have any other ideas at this point. I've reached out to a few publishers to see about creating a paperback, and I suspect a print version will increase interest. Still, I can't help thinking there's something else I should be doing between now and paperback launch.
<br><br>
What's next: The rough draft is 100% complete, but I expect to continue to get feedback over the next month or so. As long as the feedback is coming in, I'll be doing updates and publishing new versions.
<br><br>
If you've already bought the book, thank you for the support. It takes 10 seconds to get a pdf of any book you want these days, and I can't thank you enough for monetarily supporting all the effort I've put into WEwUT. If you haven't bought the book, you're welcome to give the <a href="https://leanpub.com/wewut/read">sample a read for free</a>. I hope you'll find it enjoyable, and I would gladly accept any feedback you're willing to provide.<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-29374361449011233362014-05-21T07:29:00.000-04:002014-05-21T07:48:30.836-04:00Working Effectively with Unit TestsUnit Testing has moved from fringe to mainstream, which is a great thing. Unfortunately, as a side effect developers are creating mountains of unmaintainable tests. I've been fighting the maintenance battle pretty aggressively for years, and I've decided to write a book that captures what I believe is the most effective way to test.
<br><br>
<blockquote>
<em>From the Preface</em>
<br><br>
Over a dozen years ago I read Refactoring for the first time; it immediately became my bible. While Refactoring isn’t about testing, it explicitly states: If you want to refactor, the essential precondition is having solid tests. At that time, if Refactoring deemed it necessary, I unquestionably complied. That was the beginning of my quest to create productive unit tests.
<br><br>
Throughout the 12+ years that followed reading Refactoring I made many mistakes, learned countless lessons, and developed a set of guidelines that I believe make unit testing a productive use of programmer time. This book provides a single place to examine those mistakes, pass on the lessons learned, and provide direction for those that want to test in a way that I’ve found to be the most productive.
</blockquote>
The book does touch on some theory and definition, but the main purpose is to show you how to take tests that are causing you pain and turn them into tests that you're happy to work with.
<br><br>
<blockquote>
<em>For example, the book demonstrates how to go from...</em>
<br><br>
looping test with many (built elsewhere) collaborators
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrPu-L0eaZo_i9gusPO7GmQLhQkmlECIvU2aiJ90gRm7nUobH_GULc4GcLS45S_C-J5QFXdyegsgiCLb9gRBNPkAu1zsXrjmM3HSinRPW_YHdWfHh3gbobJaf5gkuAbVFOvrpt/s1600/Screen+Shot+2014-05-21+at+6.59.18+AM.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrPu-L0eaZo_i9gusPO7GmQLhQkmlECIvU2aiJ90gRm7nUobH_GULc4GcLS45S_C-J5QFXdyegsgiCLb9gRBNPkAu1zsXrjmM3HSinRPW_YHdWfHh3gbobJaf5gkuAbVFOvrpt/s1600/Screen+Shot+2014-05-21+at+6.59.18+AM.png" /></a>
<br>
.. to individual tests that expect literals, limit scope, explicitly define collaborators, and focus on readability
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinaTeRkg7kOWC_wcjapILV1TYqw8NWJuE2v5rZDmgT3fviSu5G11AvTt0ZutY0GBv7bLgSVZ0JQ0y_gQ8kymZ2fH6Tufnm-OCLUhCgS-V3KxTO1_R-5Fw9dK_Iw65KmGBY9FMt/s1600/Screen+Shot+2014-05-21+at+7.01.40+AM.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinaTeRkg7kOWC_wcjapILV1TYqw8NWJuE2v5rZDmgT3fviSu5G11AvTt0ZutY0GBv7bLgSVZ0JQ0y_gQ8kymZ2fH6Tufnm-OCLUhCgS-V3KxTO1_R-5Fw9dK_Iw65KmGBY9FMt/s1600/Screen+Shot+2014-05-21+at+7.01.40+AM.png" /></a>
<br>
.. to fine-grained tests that focus on testing a single responsibility, are resistant to cascading failures, and provide no
friction for those practicing ruthless Refactoring.
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOg2vIBOm7-GBJwJps0iQhBvUY_1A-1zb72CjS5rBqnqL92Xzg_dRcYPIAp3nqS24Fa05Yi_GQBmHTmJU-aB6MJtmaPqK4yiAzygIhAqFt201b140OthmyDSyTjOZ9ZkUbtZKc/s1600/Screen+Shot+2014-05-21+at+7.13.57+AM.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOg2vIBOm7-GBJwJps0iQhBvUY_1A-1zb72CjS5rBqnqL92Xzg_dRcYPIAp3nqS24Fa05Yi_GQBmHTmJU-aB6MJtmaPqK4yiAzygIhAqFt201b140OthmyDSyTjOZ9ZkUbtZKc/s1600/Screen+Shot+2014-05-21+at+7.13.57+AM.png" /></a>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEil86CKE1yl0fczlgV3PzZlP6U4KoQNgqhiVAU3lWUNPXE1zmsx0i5rg8mNiSnLY6nvymGLSj2KDORuzH94vIEzpxy10jrdtnazyjihZpDELTkXxDSfLy0UZk5fu4zM0oYN3U_E/s1600/Screen+Shot+2014-05-21+at+7.15.47+AM.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEil86CKE1yl0fczlgV3PzZlP6U4KoQNgqhiVAU3lWUNPXE1zmsx0i5rg8mNiSnLY6nvymGLSj2KDORuzH94vIEzpxy10jrdtnazyjihZpDELTkXxDSfLy0UZk5fu4zM0oYN3U_E/s1600/Screen+Shot+2014-05-21+at+7.15.47+AM.png" /></a>
</blockquote>
As of right now, you can read the first 2 chapters for free at <a href="https://leanpub.com/wewut/read">https://leanpub.com/wewut/read</a>
<br><br>
I'm currently ~25% done with the book, and it's available now for $14.99. My plan is to raise the price to $19.99 when I'm 50% done, and $24.99 when I'm 75% done. Leanpub offers my book with 100% <a href="https://leanpub.com/wewut#happiness_guarantee">Happiness Guarantee</a>: <b>Within 45 days of purchase you can get a 100% refund on any Leanpub purchase, in two clicks</b>. Therefore, if you find the above or the free sample interesting, you might want to buy it now and save a few bucks.
<br><br>
Buy Now here: <a href="https://leanpub.com/wewut">https://leanpub.com/wewut</a><div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-39438590969220263382014-05-19T12:52:00.000-04:002014-05-19T17:30:39.492-04:00Weighing in on Long Live TestingDHH recently wrote a <a href="http://david.heinemeierhansson.com/2014/tdd-is-dead-long-live-testing.html">provocative piece</a> that gave some views into how he does and doesn't test these days. While I don't think I agree with him completely, I applaud his willingness to speak out against TDD dogma. I've written publicly about not buying the pair-programming dogma, but I hadn't previously been brave enough to admit that I no longer TDD the vast majority of the time.
<br><br>
The truth is, I haven't been dogmatic about TDD in quite some time. Over 6 years ago I was on a ThoughtWorks project where I couldn't think of a single good reason to TDD the code I was working on. To be honest, there weren't really any reasons that motivated me to write tests at all. We were working on a fairly simple, internal application. They wanted software as fast as they could possibly get it, and didn't care if it crashed fairly often. We kept everything simple, manually tested new features through the UI, and kept our customer's very happy.
<br><br>
There were plenty of reasons that we could have written tests. Reasons that I expect people will want to yell at me right now. To me, that's actually the interesting, and missing part, of the latest debate on TDD. I don't see people asking: Why are we writing this test? Is TDD good or bad? That depends; TDD is just a tool, and often the individual is the determining factor when it comes to how effective a tool is. If we start asking "Why?", it's possible to see how TDD could be good for some people, and bad for DHH.
<br><br>
I've been quietly writing a book on <a href="https://leanpub.com/wewut">Working Effectively with Unit Tests</a>, and I'll have to admit that it was really, really hard not to jump into the conversation with some of the content I've recently written. Specifically, I think this paragraph from the Preface could go a long way to helping people understand an opposing argument.
<br><br>
<blockquote>
<h3>Why Test?</h3>
The answer was easy for me: Refactoring told me to. Unfortunately, doing something strictly because someone or something told you to is possibly the worst approach you could take. The more time I invested in testing, the more I found myself returning to the question: Why am I writing this test?
<br><br>
There are many motivators for creating a test or several tests:
<ul>
<li>validating the system
<ul>
<li>immediate feedback that things work as expected
<li>prevent future regressions
</ul>
<li>increase code-coverage
<li>enable refactoring of legacy codebase
<li>document the behavior of the system
<li>your manager told you to
<li>Test Driven Development
<ul>
<li>improved design
<li>breaking a problem up into smaller pieces
<li>defining the "simplest thing that could possibly work"
</ul>
<li>customer approval
<li>ping pong pair-programming
</ul>
Some of the above motivators are healthy in the right context, others are indicators of larger problems. Before writing any test, I would recommend deciding which of the above are motivating you to write a test. If you first understand why you're writing a test, you'll have a much better chance of writing a test that is maintainable and will make you more productive in the long run.
<br><br>
Once you start looking at tests while considering the motivator, you may find you have tests that aren't actually making you more productive. For example, you may have a test that increases code-coverage, but provides no other value. If your team requires 100% code-coverage, then the test provides value. However, if you team has abandoned the (in my opinion harmful) goal of 100% code-coverage, then you're in a position to perform my favorite refactoring: delete.
</blockquote>
I don't actually know what motivates DHH to test, but if we assumed he cares about validating the system, preventing future regressions, and enabling refactoring (exclusively) then there truly is no reason to TDD. That doesn't mean you shouldn't; it just means, given what he values and how he works, TDD isn't valuable to him. Of course, conversely, if you value immediate feedback, problems in small pieces, and tests as clients that shape design, TDD is probably invaluable to you.
<br><br>
I find myself doing both. Different development activities often require different tools; i.e. Depending on what I'm doing, different motivators apply, and what tests I write change (hopefully) appropriately.
<br><br>To be honest, if you look at your tests in the context of the motivators above, that's probably all you need to help you determine whether or not your tests are making you more or less effective. However, if you want more info on what I'm describing, you can pick up the earliest version of my <a href="https://leanpub.com/wewut">upcoming book</a>. (cheaply, with a full refund guarantee)
<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-15097409999973300242014-01-27T12:53:00.000-05:002014-01-27T12:54:12.520-05:00REPL Driven DevelopmentWhen I describe my current workflow I use the <a href="http://en.wikipedia.org/wiki/Three-letter_acronym">TLA</a> RDD, which is short for REPL Driven Development. I've been using REPL Driven Development for all of my production work for awhile now, and I find it to be the most effective workflow I've ever used. RDD differs greatly from any workflow I've used in the past, and (despite my belief that it's superior) I've often had trouble concisely describing what makes the workflow so productive. This entry is an attempt to describe what I consider RDD to be, and to demonstrate why I find it the most effective way to work.
<br><br>
<h3>RDD Cycle</h3>
First, I'd like to address the TLA RDD. I use the term RDD because I'm relying on the REPL to drive my development. More specifically, when I'm developing, I create an s-expression that I believe will solve my problem at hand. Once I'm satisfied with my s-expression, I send that s-expression to the REPL for immediate evaluation. The result of sending an s-expression can either be a value that I manually inspect, or it can be a change to a running application. Either way, I'll look at the result, determine if the problem is solved, and repeat the process of crafting an s-expression, sending it to the REPL, and evaluating the result.
<br><br>
If that isn't clear, hopefully the video below demonstrates what I'm talking about.
<br><br>
<iframe width="420" height="315" src="//www.youtube.com/embed/P8SWtYXXOuo" frameborder="0" allowfullscreen></iframe>
<br><br>
If you're unfamiliar with RDD, the previous video might leave you wondering: What's so impressive about RDD? To answer that question, I think it's worth making explicit what the video is: an example of a running application that needs to change, a change taking place, and verification that the application runs as desired. The video demonstrates change and verification; what makes RDD so effective to me is what's missing: (a) restarting the application, (b) running something other than the application to verify behavior, and (c) moving out of the source to execute arbitrary code. Eliminating those 3 steps allows me to focus on what's important, writing and running code that will be executed in production.
<br><br>
<h3>Feedback</h3>
I've found that, while writing software, getting feedback is the single largest time thief. Specifically, there are two types of feedback that I want to get as quickly as possible: (1) Is my application doing what I believe it is? (2) What does this arbitrary code return when executed? I believe the above video demonstrates how RDD can significantly reduce the time needed to answer both of those questions.
<br><br>
In my career I've spent significant time writing applications in C#, Ruby, & Java. While working in C# and Java, if I wanted to make and verify (in the application) any non-trivial change to an application, I would need to stop the application, rebuild/recompile, & restart the application. I found the slowness of this feedback loop to be unacceptable, and wholeheartedly embraced tools such as NUnit and JUnit.
<br><br>
I've never been as enamored with <a href="http://en.wikipedia.org/wiki/Test-driven_development">TDD</a> as some of my peers; regardless, I absolutely endorsed it. The Design aspect of TDD was never that enticing to me, but tests did allow me to get feedback at a significantly superior pace. Tests also provide another benefit while working with C# & Java: They're the poorest man's REPL. Need to execute some arbitrary code? Write a test, that you know you're going to immediately delete, and execute away. Of course, tests have other pros and cons.
At this moment I'm limiting my discussion around tests to the context of rapid feedback, but I'll address TDD & RDD later in this entry.
<br><br>
Ruby provided a more effective workflow (technically, Rails provided a more effective workflow). Rails applications I worked on were similar to my RDD experience: I was able to make changes to a running application, refresh a webpage and see the result of the new behavior. Ruby also provided a REPL, but I always ran the REPL external to my editor (I knew of no other option). This workflow was the closest, in terms of efficiency, that I've ever felt to what I have with RDD; however, there are some minor differences that do add up to an inferior experience: (a) having to switch out of a source file to execute arbitrary code is an unnecessary nuisance and (b) refreshing a webpage destroys any client side state that you've built up. I have no idea if Ruby now has editor & repl integration, if it does, then it's likely on par with the experience I have now.
<br><br>
<h3>Semantics</h3>
<blockquote><ul><li>It's important to distinguish between two meanings of "REPL" - one is a window that you type forms into for immediate evaluation; the other is the process that sits behind it and which you can interact with from not only REPL windows but also from editor windows, debugger windows, the program's user interface, etc.
<li>It's important to distinguish between REPL-<i>based</i> development and REPL-<i>driven</i> development:<ul>
<li>REPL-based development doesn't impose an order on what you do. It can be used with TDD or without TDD. It can be used with top-down, bottom-up, outside-in and inside-out approaches, and mixtures of them.
<li>REPL-driven development seems to be about "noodling in the REPL window" and later moving things across to editor buffers (and so source files) as and when you are happy with things. I think it's fair to say that this is REPL-based development using a series of mini-spikes. I think people are using this with a bottom-up approach, but I suspect it can be used with other approaches too.</ul></ul> -- Simon Katz</blockquote>
I like Simon's description, but I don't believe that we need to break things down to two different TLAs. Quite simply, (sadly) I don't think enough people are developing in this way, and the additional specification causes a bit of confusion among people who aren't familiar with RDD. However, Simon's description is so spot on I felt the need to describe why I'm choosing to ignore his classifications.
<br><br><h3>RDD & TDD</h3>
RDD and TDD are not in direct conflict with each other. As Simon notes above, you can do TDD backed by a REPL. Many popular testing frameworks have editor specific libraries that provide
immediate feedback through REPL interaction.
<br><br>
When working on a feature, the short term goal is to have it working in the application as fast as possible. Arbitrary execution, live changes, and only writing what you need are 3 things that
can help you complete that short term goal as fast as possible.
The video above is the best example I have of how you go from a feature request to software that does what you want in the smallest amount of time.
In the video, I only leave the buffer to verify that the application works as intended. If the short term goal was the only goal, RDD without writing tests would likely be the solution.
However, we all know that that are many other goals in software. Good design is obviously important. If you think tests give you better design, then you should probably mix both TDD & RDD.
Preventing regression is also important, and that can be accomplished by writing tests <i>after</i> you have a working feature that you're satisfied with.
Regression tests are great for giving confidence that a feature works as intended and will continue to in the future.
<br><br>
REPL Driven Development doesn't need to replace your current workflow, it can also be used to extend your existing TDD workflow.
<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-90278078203224982382013-06-11T13:31:00.000-04:002013-06-11T13:31:00.415-04:00Coding: Increase Your Reading and Writing SpeedA teammate of mine recently expressed a desire for a shortcut for something we type often. I started looking into our shortcut options and came to a common determination: We can do this, but the number of 2 key shortcuts available to us is finite, so we better use them wisely.
<br><br>
I wrote the following unix to give me a rough idea of what we type frequently.<blockquote>
<code>find . -name "*.clj" | xargs cat | tr -s '[:space:]:#()[]{}\"' '\n' | sort | uniq -c | sort -n</code></blockquote>note: If you're not writing clojure you'll want to look for something other than .clj files, and you might also want to tweak what you replace with a new line.
<br><br>
The above unix gave me an ordered list of the most typed 'words' across all of my codebases. At this point I had some science for setting up some shortcuts.
<br><br>
<h2>Writing</h2>
You'll want to look into whatever <a href="http://en.wikipedia.org/wiki/Text_editor">editor</a>/<a href="http://en.wikipedia.org/wiki/Integrated_development_environment">ide</a> you use and see if you can find key shortcuts and snippet expansion. My editor is emacs; I assigned some <a href="http://www.emacswiki.org/emacs/KeyChord">key-chords</a> and some <a href="http://www.emacswiki.org/emacs/Yasnippet">yasnippets</a>. If you're not using emacs you should have something similar in whatever you are using.
<br><br>
While I wanted to define some shortcuts, I also didn't want to create so many that I was constantly wasting time looking up what I'd created. Based on that desire I created:<ul>
<li>2 shortcuts (key-chords) for two of the most duplicated words. The shortcuts are concise by design, but that makes them a bit harder to remember. You can probably get started with more than 2, but I didn't see much harm in starting there.
<li>a dozen snippets for the next most used words. These snippets are descriptive enough to easily remember, thus I felt comfortable defining several of them. e.g. pps expands to (println (pr-str )).
</ul>
Having shortcuts and snippets will obviously make me more productive, and the unix helped me figure out which words were the most important to optimize for.
<br><br>
<h2>Reading</h2>
Most editors/ides also give you a summary view for common code patterns. For example, IntelliJ displays lambdas when the actual code is actually an anonymous class. Emacs gives you font-lock for turning patterns into individual characters. Armed with my list of the most common words in my codebase, I created <a href="https://github.com/jaycfields/unplugged-pack/blob/f7ba9f033cfed38f2c39da7855568c46c1a1874e/init.el#L105-L115">font-locks</a> for the 11 most duplicated.
<br><br>
Sometimes a picture is worth a thousand words. Below is a function definition without any font locks applied.
<br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2-LQAmEI9y7DJX_1hZk8vrPsJc7e5g67_3kWqyBnIW8L434tvuWtC4Z1h2JSn95h97eBxEaMsD_4G54AflJSYW_qHh5qKGA5nh63lAavvFEtz2B_oB6Ak4jhG4JZNSoBBVkWF/s1600/Screen+Shot+2013-06-09+at+2.44.45+PM.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2-LQAmEI9y7DJX_1hZk8vrPsJc7e5g67_3kWqyBnIW8L434tvuWtC4Z1h2JSn95h97eBxEaMsD_4G54AflJSYW_qHh5qKGA5nh63lAavvFEtz2B_oB6Ak4jhG4JZNSoBBVkWF/s320/Screen+Shot+2013-06-09+at+2.44.45+PM.png" /></a>
<br><br>
The following image is what the same function looks like with custom font locks applied. It might be a bit jarring at first, but in the long run it should add up to many small victories such as quickly identifying patterns in code and less line breaks.
<br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZUdjD1C65GZj5_tSlnTVy2WHJeWXe37csWCRcqK-KbsWjcldKjXtjPUEhmK5X4ewb_Od3BfNYvCjD60gZW06bKkt-Jg7YM9XXBssFl5DrI-Itf3-WFRqvnl7UK-ZOruDfTn3r/s1600/Screen+Shot+2013-06-09+at+2.55.52+PM.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZUdjD1C65GZj5_tSlnTVy2WHJeWXe37csWCRcqK-KbsWjcldKjXtjPUEhmK5X4ewb_Od3BfNYvCjD60gZW06bKkt-Jg7YM9XXBssFl5DrI-Itf3-WFRqvnl7UK-ZOruDfTn3r/s320/Screen+Shot+2013-06-09+at+2.55.52+PM.png" /></a>
<br><br>
<h2>Results</h2>
I've been working with these settings for a little over a week now. I haven't needed to look up anything I defined, and I get a little burst of satisfaction when I read or write something faster than I'd been able to in the past. I'd definitely recommend doing something similar with your codebase and ide/editor. <div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-76614854360031374812013-05-16T08:00:00.000-04:002013-05-16T08:00:16.098-04:00Clojure: Combining Calls To Doseq And LetI've you've ever looked at the <a href="http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/for">docs</a> for clojure's for macro, then you probably know about the :let, :when, and :while modifiers. What you may not know is that those same modifiers are available in <a href="http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/doseq">doseq</a>.
<br><br>
I was recently working with some code that had the following form.
<br><br>
<script src="https://gist.github.com/jaycfields/5564037.js"></script>
<br>
Upon seeing this code, <a href="http://elhumidor.blogspot.com/">John Hume</a> asked if I preferred it to a single doseq with multiple bindings. He sent over an example that looked similar to the following example.
<br><br>
<script src="https://gist.github.com/jaycfields/5564066.js"></script>
<br>
That was actually the first time that I'd seen multiple bindings in a doseq, and my immediate reaction was that I preferred the explicit simplicity of having multiple doseqs. However, I always have a preference for concise code, and I forced myself to starting using multiple bindings instead of multiple doseqs - and, unsurprisingly, I now prefer multiple bindings to multiple doseqs.
<br><br>
You might have noticed that the second version of the code slightly changes what's actually being done. In the original version the 'name' function is called once per 'id', and in the second version the 'name' function is called once per 'sub-id'. Calling name significantly more often isn't likely to have much impact on your program; however, if you were calling a more expensive function this change could have a negative impact. Luckily, (as I previously mentioned) doseq also provides support for :let.
<br><br>
The second example can be evolved to the following code - which also demonstrates that the let is only evaluated once per iteration.
<br><br>
<script src="https://gist.github.com/jaycfields/5564099.js"></script>
<br>
That's really the final version of the original code, but you can alter it slightly for experimentation purposes if you'd like. Let's assume we have another function we're calling in an additional let and it's expensive, it would be nice if that only occurred when an iteration was going to happen. It turns out, that's exactly what happens.
<br><br>
<script src="https://gist.github.com/jaycfields/5564144.js"></script>
<br>
Whether you prefer multiple bindings or multiple doseqs, it's probably a good idea to get comfortable reading both.<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-39344647257304830002013-05-15T08:00:00.000-04:002013-05-15T08:40:56.438-04:00Emacs Lisp: Font Lock for Clojure's PartialI love using partial, but I dislike the length of the function name. There's a simple solution, define another function with a shorter name that simply calls (or is) partial. This is exactly what I did in the <a href="https://github.com/jaycfields/jry">jry</a> library.
<br><br>
<script src="http://gist-it.appspot.com/github/jaycfields/jry/blob/98c2e4cef3880041060ffec5e95d86096aaa4d1b/src/clojure/jry.clj?slice=0:3"></script>
I liked the use of % due to partial feeling similar to creating a function using #(), and % having a special meaning inside #(). I thought they tied well together. Unfortunately, there's an obvious problem, things would be very broken if you tried to use the '%' function in an anonymous function defined with #(). Somewhere along the way this issue caused me to stop using jry/%.
<br><br>
Using partial is great: it's part of the standard lib, and I don't need to explain it to anyone who joins my team or any future maintainers of the code I write. Still, I want something shorter, and I've always had a background thread looking for another shorter-than-partial solution. While recently contributing to <a href="https://github.com/overtone/emacs-live">emacs-live</a> I found the solution I was looking for: clojure-mode font lock.
<br><br>
The following code can now be found in my <a href="https://github.com/jaycfields/unplugged-pack">emacs configuration</a>.
<br><br>
<script src="http://gist-it.appspot.com/github/jaycfields/unplugged-pack/blob/a88a5dc2dfd905ff9de5fbac36976688fd4536dc/init.el?slice=11:16"></script>
This solution feels like the best of both worlds. My code still uses the function from the standard library, my colleagues still see a function they already know, and 'partial' only takes up one character space in my buffer. The image below is what you'll see if you put the above emacs-lisp in your config.<br><br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgl9cdV5dquRlViVheGF3rsN7v6nA-gpdg3R4BXqlW_tSkSuUjKKJfkEhOSxo6Wv-i7T-FcJxo0g84X8z140rKYcpOu2XJTtWwU5m0eEthHkLHFWSdFGijDkeIfuLi8K4n1LMWp/s1600/Screen+Shot+2013-05-12+at+11.15.34+AM.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgl9cdV5dquRlViVheGF3rsN7v6nA-gpdg3R4BXqlW_tSkSuUjKKJfkEhOSxo6Wv-i7T-FcJxo0g84X8z140rKYcpOu2XJTtWwU5m0eEthHkLHFWSdFGijDkeIfuLi8K4n1LMWp/s320/Screen+Shot+2013-05-12+at+11.15.34+AM.png" /></a>
<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-51210298143438211692013-05-14T08:00:00.000-04:002013-05-14T08:00:03.291-04:00Clojure: Testing The Creation Of A Partial FunctionI recently refactored some code that takes longs from two different sources to compute one value. The code originally stored the longs and called a function when all of the data arrived. The refactored version partials the data while it's incomplete and executes the partial'd function when all of the data is available. Below is a contrived example of what I'm taking about.
<br><br>
Let's pretend we need a function that will allow us to check whether or not another drink would make us legally drunk in New York City.
<br><br>
The code below stores the current bac and uses the value when legally-drunk? is called.
<br><br>
<script src="http://gist-it.appspot.com/github/jaycfields/Clojure--Testing-The-Creation-Of-A-Partial-Function/blob/master/src/clojure/original.clj"></script>
The following (passing) tests demonstrate that everything works as expected.
<br><br>
<script src="http://gist-it.appspot.com/github/jaycfields/Clojure--Testing-The-Creation-Of-A-Partial-Function/blob/master/test/expectations/original_expectations.clj"></script>
This code works without issue, but can also be refactored to store a partial'd function instead of the bac value. Why you would want to do such a thing is outside of the scope of this post, so we'll just assume this is a good refactoring. The code below no longer stores the bac value, and instead stores the pure-legally-drunk? function partial'd with the bac value.
<br><br>
<script src="http://gist-it.appspot.com/github/jaycfields/Clojure--Testing-The-Creation-Of-A-Partial-Function/blob/master/src/clojure/refactored.clj"></script>
Two of the three of the tests don't change; however, the test that was verifying the state is now broken.
<br><br>
<script src="http://gist-it.appspot.com/github/jaycfields/Clojure--Testing-The-Creation-Of-A-Partial-Function/blob/master/test/expectations/refactored_expectations.clj"></script>
note: The test output has been trimmed and reformatted to avoid horizontal scrolling.
<br><br>
In the output you can see that the test is failing as you'd expect, due to the change in what we're storing. What's broken is obvious, but there's not an obvious solution. Assuming you still want this state based test, how do you verify that you've partial'd the right function with the right value?
<br><br>
The solution is simple, but a bit tricky. As long as you don't find the redef too magical, the following solution allows you to easily verify the function that's being partial'd as well as the arguments.
<br><br>
<script src="http://gist-it.appspot.com/github/jaycfields/Clojure--Testing-The-Creation-Of-A-Partial-Function/blob/master/test/expectations/refactored_passing_expectations.clj"></script>
Those tests all pass, and should provide security that the legally-drunk? and update-bac functions are sufficiently tested. The pure-legally-drunk? function still needs to be tested, but that should be easy since it's a pure function.
<br><br>
Would you want this kind of test? I think that becomes a matter of context and personal preference. Given the various paths through the code the following tests should provide complete coverage.
<br><br>
<script src="http://gist-it.appspot.com/github/jaycfields/Clojure--Testing-The-Creation-Of-A-Partial-Function/blob/master/test/expectations/high_level_expectations.clj"></script>
The above tests make no assumptions about the implementation - they actually pass whether you :use the 'original namespace or the 'refactored namespace. Conversely, the following tests verify each function in isolation and a few of them are very much tied to the implementation.
<br><br>
<script src="http://gist-it.appspot.com/github/jaycfields/Clojure--Testing-The-Creation-Of-A-Partial-Function/blob/master/test/expectations/unit_level_expectations.clj"></script>
Both sets of tests would give me confidence that the code works as expected, so choosing which tests to use would become a matter of maintenance cost. I don't think there's anything special about these examples; I think they offer the traditional trade-offs between higher and lower level tests. A specific trade-off that stands out to me is identifying defect localization versus having to update the test when you update the code.
<br><br>
As I mentioned previously, the high-level-expectations work for both the 'original and the 'refactored namespaces. Being able to change the implementation without having to change the test is obviously an advantage of the high level tests. However, when things go wrong, the lower level tests provide better feedback for targeting the issue.
<br><br>
The following code is exactly the same as the code in refactored.clj, except it has a 1 character typo. (it's not necessary to spot the typo, the test output below will show you want it is)
<br><br>
<script src="http://gist-it.appspot.com/github/jaycfields/Clojure--Testing-The-Creation-Of-A-Partial-Function/blob/master/src/clojure/refactored_with_typo.clj"></script>
The high level tests give us the following feedback.
<pre>failure in (high_level_expectations.clj:14) : expectations.high-level-expectations
(expect
true
(with-redefs
[state (atom {})]
(update-bac 0.01)
(legally-drunk? 0.07)))
expected: true
was: false</pre>
There's not much in that failure report to point us in the right direction. The unit-level-expectations provide significantly more information, and the details that should make it immediately obvious where the typo is.
<pre>failure in (unit_level_expectations.clj:8) : expectations.unit-level-expectations
(expect
{:legally-drunk?* [pure-legally-drunk? 0.04]}
(with-redefs [state (atom {}) partial vector] (update-bac 0.04)))
expected: {:legally-drunk?* [#<refactored_with_typo$pure_legally_drunk_QMARK_@621bedb0> 0.04]}
was: {:legally-drunk?** [#<refactored_with_typo$pure_legally_drunk_QMARK_@621bedb0> 0.04]}
:legally-drunk?** with val [#<refactored_with_typo$pure_legally_drunk_QMARK_@621bedb0> 0.04]
is in actual, but not in expected
:legally-drunk?* with val [#<refactored_with_typo$pure_legally_drunk_QMARK_@621bedb0> 0.04]
is in expected, but not in actual</pre>
The above output points us directly to the extra asterisk in update-bac that caused the failure.
<br><br>
Still, I couldn't honestly tell you which of the above tests that I prefer. This specific example provides a situation where I think you could convincingly argue for either set of tests. However, as the code evolved I would likely choose one path or the other based on:<ul>
<li>how much 'setup' is required for always using high-level tests?
<li>how hard is it to guarantee integration using primarily unit-level tests?
</ul>
In our examples the high level tests require redef'ing one bit of state. If that grew to a few pieces of state and/or a large increase in the complexity of the state, then I may be forced to move towards more unit-level tests. A rule of thumb I use: If a significant amount of the code within a test is setting up the test context, there's probably a smaller function and a set of associated tests waiting to be extracted.
<br><br>
By definition, the unit-level tests don't test the integration of the various functions. When I'm using unit-level tests, I'll often test the various code paths at the unit level and then have a happy-path high-level test that verifies integration of the various functions. My desire to have more high-level tests increases as the integration complexity increases, and at some point it makes sense to simply convert all of the tests to high-level tests.
<br><br>
If you constantly re-evaluate which tests will be more appropriate and switch when necessary, you'll definitely come out ahead in the long run. <div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-15402670984786322142013-05-07T08:00:00.000-04:002013-05-07T08:00:08.291-04:00Recovering Lost Post DataI recently typed out a long, thoughtful response in a textarea. I clicked submit, like I've done millions of times, and I got the dreaded "session expired" error message. This happens very, very rarely, but it's devastating when it does. Creating long & thoughtful responses isn't something that comes naturally for me. I crossed my fingers and clicked back. No luck, web 2.0 dynamically created text boxes ensured Chrome had no chance to preserve my editing state.
<br />
<br />
My first reaction was: I guess I'm not responding after all. Then it occurred to me, DevTools must have my data somewhere, right? Lucky for me, the answer was yes.
<br />
<br />
There might be easier ways, this is what worked for me:<br />
<ul>
<li>open <a href="https://developers.google.com/chrome-developer-tools/">DevTools</a>
</li>
<li>go to the "Network" tab.<br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdb8lTj7MqeVUWB0XPMpme_kB6sSQNcbGya-elLtwhXN9saKRBxYmobGK3NIP1htqfWylbYsZpnkbxHH1dis8vpURZ3sEC52Jv0F_Pnfom83lT5alTzIAb7h6GQqM3cMCmrkmk/s1600/Screen+Shot+2013-05-05+at+10.26.37+AM.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdb8lTj7MqeVUWB0XPMpme_kB6sSQNcbGya-elLtwhXN9saKRBxYmobGK3NIP1htqfWylbYsZpnkbxHH1dis8vpURZ3sEC52Jv0F_Pnfom83lT5alTzIAb7h6GQqM3cMCmrkmk/s320/Screen+Shot+2013-05-05+at+10.26.37+AM.png" /></a>
</li>
<li>look for the row with the method POST.<br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCmcqKL-yzQ8VgI-We-uF50iUyrn6nkZ46UAxX_mQKAddF64KeFTu5x_C9oNk3zfempU0uvsQHZP7gZY7YGan7fIbEMxtxCGo0MVXJTDLgdYptfbl0HUI3rNnmMT3H6L8bvbmt/s1600/Screen+Shot+2013-05-05+at+10.28.39+AM.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCmcqKL-yzQ8VgI-We-uF50iUyrn6nkZ46UAxX_mQKAddF64KeFTu5x_C9oNk3zfempU0uvsQHZP7gZY7YGan7fIbEMxtxCGo0MVXJTDLgdYptfbl0HUI3rNnmMT3H6L8bvbmt/s320/Screen+Shot+2013-05-05+at+10.28.39+AM.png" /></a><ul>
<li>If you don't see a POST row, try refreshing the page. With any luck you'll get a repost confirmation dialog, giving you some hope that your data is still around. (You'll want to allow the data repost)</li>
</ul>
</li>
<li>click on the POST row, and scroll down till you see "Form Data". If you've gotten this far, hopefully you'll find your data in clear text and able to be copied.<br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijTxLpVK1dP51UVHmxaqCm0LlH6baNRPSFrc6fPMyr7Albq56Pw3VcguLozjy9vvVD4ZwRn4so1JK9ycz5o-n71ITny70LMtm2xcD5cJazO16dDVhQRXJry0rhjabvMglZtt31/s1600/Screen+Shot+2013-05-05+at+10.35.33+AM.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijTxLpVK1dP51UVHmxaqCm0LlH6baNRPSFrc6fPMyr7Albq56Pw3VcguLozjy9vvVD4ZwRn4so1JK9ycz5o-n71ITny70LMtm2xcD5cJazO16dDVhQRXJry0rhjabvMglZtt31/s320/Screen+Shot+2013-05-05+at+10.35.33+AM.png" /></a>
</li>
</ul>
The examples from this post are from following the instructions above and logging in to <a href="http://twitter.com/">twitter.com</a>. If you've ever lost post data in the past, you may want to give these directions a dry-run now.<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-76021343282192883332013-05-02T10:41:00.000-04:002013-05-02T10:41:25.065-04:00Emacs Lisp: Toggle Between a Clojure String and KeywordWhen I was doing a fair bit of Ruby I often used the <a href="http://macromates.com/">TextMate</a>'s shortcut (Ctrl+:) to convert a Ruby String to a Symbol or a Ruby Symbol to a String. It's something I've periodically missed while doing Clojure, and yesterday I found myself in the middle of a refactoring that was going to force the conversion of 5+ Clojure Keywords to Strings.
<br><br>
The following emacs lisp is my solution for toggling between Clojure Strings and Keywords. The standard disclaimers apply - it works on my machine, and I've never claimed to know emacs lisp well.
<br><br>
<script src="https://gist.github.com/jaycfields/5502257.js"></script>
A quick video of the behavior:
<br><br>
<iframe width="560" height="315" src="http://www.youtube.com/embed/UQU7xasn3eA" frameborder="0" allowfullscreen></iframe><div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0tag:blogger.com,1999:blog-12467669.post-43977182589996898932013-04-30T08:00:00.000-04:002013-04-30T11:43:56.406-04:00Year FiveThe average lifespan for a software engineering job is 4 years. Okay, I've never actually seen proof (or contradiction), but that's the general feeling in the groups I associate with. Perhaps that's selection bias - my employer has generally changed on year 3 or 4. Perhaps this is the exception and not the rule, in that case feel free to simply read this as an experience report. However, I do think it's somewhat common for developers to leave around year 3 or 4. This entry contains speculation on why they leave, and offers one idea on what employers can do to break that cycle.
<br><br>
My 4 year employment cycle generally looks like this<ul>
<li>Year One: "I'm in over my head. My <a href="http://en.wiktionary.org/wiki/semi-bluff">semi-bluff</a> was in-fact a bluff. They're going to fire me any day."
<li>Year Two: "It's nice to feel like a productive team member"
<li>Year Three: "This is fun, and I'm not bad at it. It's satisfying to pass on knowledge to teammates."
<li>Year Four: "This feels repetitive, that grass over there sure looks greener"
</ul>I expect that I, like many programmers, probably undervalue my contribution in the early days and overvalue my contribution in the latter days.
<br><br>
In Year Three and Four at <a href="http://drw.com">DRW</a> I spent some time thinking about how I felt, and observing the behavior of some colleagues that were also on year three and four. A few things stood out to me.<ul>
<li>A company you don't work at always seems to have infinite possibilities; however, after a few years with an employer, it's extremely clear what your options are. More importantly, it's very clear what limitations will likely always be there.
<li>A company you don't work at contains no code you're responsible for. Conversely, any company you've been with for 4 years probably has plenty of code you're not proud of. If you're responsible for that code, it's a constant reminder of your previous limitations. If you're not responsible for it, your co-workers aren't likely to let you forget about it anytime soon.
<li>There's always someone willing to pay you more than you're worth. After several years with a company it's likely that they're going to pay you what you're worth, but not what some other company thinks you're worth. I'm surprised that more companies don't pay (the employees they want to keep) what their "flawless market value" would be. In other words, what would you pay them if they interviewed, you determined what they knew, you determined what value they would bring, and you were completely ignorant of their flaws? That's what your competition is likely doing. That's what you're fighting against if you want to keep them around.
<li>A new job often offers a new challenge. Once you feel like you've given that challenge your best shot, what remains? If you did a great job, it's likely that you'll have plenty of other options. However, if you've done a good job, you may be stuck in a spot where there aren't as many open doors and challenges to choose from - not nearly as many as a position at another company will appear to offer.
</ul>
I was recently in Punta Cana for wedding, and I was on the beach - working on my laptop. My wife asked: don't you want some time off? My response was short and immediate: no. Later that evening my wife and I discussed my work situation. I observed that I'm in Year Five at DRW and I'm happy, happier than ever, strange - given my previous experiences. She asked if I thought that I was working too much, and if I thought that I would burn out. I remarked: I'd rather have a job that I love, that I don't like to be away from, than a job where I feel like I need a week or two off.
<br><br>
I hear you, nice work if you can get it. I don't have a general recipe for getting there, but I know how I got there.
<br><br>
Back in 2009 I interviewed at DRW. At the time I was working for <a href="http://www.thoughtworks.com/">ThoughtWorks</a>, and my client was <a href="http://www.forward.co.uk/">Forward</a>. I considered the founder of Forward to be a friend and someone I would gladly work for. I decided it was time to leave ThoughtWorks (after 3.5 years), and I was sure that Forward would be my future home. I remarked to my DRW recruiter "H" (who also happened to be a friend from my ThoughtWorks days) that one of the best things about Forward was knowing that I liked and trusted the man who ran Forward. H said nothing, but made a brilliant move.
<br><br>
In my interview I was grilled, killed even, and then things turned. I met with a guy who asked me a few questions and then told me about the company: the vision, the people, and where I could fit in. He was smart, easy to talk to, and someone I related to. We discussed things casually, it didn't feel like a company pitch in any way at all, it felt like small-talk - something I was very grateful for after the beating I'd taken previously in of the day. After everything concluded I hit the bar with my friends, including H. At that point they revealed to me that the guy I'd met was the partner at the firm that was (among other things) responsible for the firm's technology. I'd also met the CTO, and various other people responsible for technology in the firm. H had shown me that DRW, just like Forward, had what I like to call Awesome All the Way Up.**
<br><br>
Awesome All the Way Up has served me very well at DRW. To this day I remain in fairly common contact with the CTO and several of DRW's partners. About 6 months ago I asked 3 favors. First of all, I asked for enough money to pay someone's salary for 6 months. I identified a project that I wanted to undertake, and I needed help to complete it. Then things got unconventional, I asked if I could create a contract-to-hire situation. Even more unconventional, I pursued a friend and previous colleague who lived in Austin, Texas. DRW rarely uses contractors, and has no other remote employees that I'm aware of. An appropriate amount of questions were asked, but in the end my request was granted.
<br><br>
The experiment is on-going, but I'm very happy with our progress so far. That's all well-and-good, but the support of DRW is the important aspect of the story. I'm confident that their support of my unconventional requests was a major factor in ensuring my happiness in Year Five. We recently hired <a href="http://elhumidor.blogspot.com/">John Hume</a>, thus declaring success at some level already. However, if things had gone poorly, both parties could have gone their separate ways with little lost and lessons learned. More importantly to me, DRW would have continued to give me confidence that they were willing to take chances to provide me with opportunities and ensure my continued happiness at the firm.
<br><br>
There's a similar discussion around DRW allowing me to use Clojure as my primary development language. I'll spare you the long version. tl; dr: They gave me a reasonable amount of space to try something new, and supported me appropriately as we found more and more success.
<br><br>
Not all of my experiments are green-lighted, and I've also had unsuccessful outcomes. DRW has done a good job of not setting me up to fail; my ideas that have a low probability of succeeding are fleshed out and appropriately shot down. All experiments have risk measures put in place, limited downside, and are reassessed constantly. It's great to have support when things are going well, and it's essential to have support when things don't go as planned.
<br><br>
For me, that's been the secret for keeping me around more than 4 years: An appropriate amount of trust and a willingness to experiment.
<br><br>
A foreign thought also recently came to mind. For the first time in my life I can say that I see myself happy and successful at my current employer in 10 years. This is a question I've asked many people since it occurred to me. To date, +AdeOshineye (http://www.oshineye.com/) is the only person who's responded affirmatively. The results aren't surprising to me, but I do wonder why more employees and employers aren't looking for ways to extend relationships.
<br><br>
Perhaps the secret for keeping me around isn't more broadly applicable; however, simply asking what will keep an individual around is probably the more important message in this entry. It's good to know what will make someone happy now, but it seems like it's equally important to know what will make them happy in the long term. I suspect the answers will be at least a little, if not very different.
<br><br>
The way things currently stand, I'm looking forward to writing about Year Six.
<br><br>
** DRW became my home in the end; however, Forward continues to do well. I suspect Awesome All the Way Up would have ensured happy and gainful employment at either destination. I remain in regular contact with my friends at Forward.<div class="blogger-post-footer"><br/><a href="http://www.jayfields.com">© Jay Fields - www.jayfields.com</a></div>Jayhttp://www.blogger.com/profile/14491442812573747680[email protected]0