<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Ryan Weald's Blog]]></title>
  <link href="https://rweald.github.io/atom.xml" rel="self"/>
  <link href="https://rweald.github.io/"/>
  <updated>2026-08-07T12:33:05-07:00</updated>
  <id>https://rweald.github.io/</id>
  <author>
    <name><![CDATA[Ryan Weald]]></name>
    
  </author>
  <generator uri="https://jekyllrb.com/">Jekyll</generator>

  
  <entry>
    <title type="html"><![CDATA[Reproducing MindGuard with interchangeable judges: does GLM-5.2 or DeepSeek beat GLM-4.6]]></title>
    <link href="https://rweald.github.io/blog/2026/08/07/reproducing-mindguard-with-interchangeable-judges/"/>
    <updated>2026-08-07T11:28:00-07:00</updated>
    <id>https://rweald.github.io/blog/2026/08/07/reproducing-mindguard-with-interchangeable-judges</id>
    <content type="html"><![CDATA[<p>Sword Health <a href="https://swordhealth.com/newsroom/introducing-mindguard">released MindGuard</a> earlier this year with the weights and a clinician-labeled test set, which is rare in behavioral health safety work. I’m personally very interested in this area, so I wanted to play around and see if I could answer a few questions I had. Maybe even improve on their results using a newer judge model.</p>

<ol>
  <li>Could the results be replicated using a genuinely open-source harness?</li>
  <li>Did the pipeline depend on Sword’s proprietary clinical model, or could a general-purpose LLM stand in for it?</li>
  <li>Could a newer judge such as GLM-5.2 or DeepSeek improve on the paper’s choice of GLM-4.6?</li>
  <li>How much would the full experiment cost in API fees and compute?</li>
</ol>

<p><strong>TL;DR:</strong> I reproduced the MindGuard method and am releasing the <a href="https://github.com/rweald/mental-health-guard-harness">open-source harness</a> I used to do it. You do not need Sword’s proprietary clinical model. GLM-5.2 slightly outperformed GLM-4.6 in this reproduction, while DeepSeek was nearly identical and far cheaper. The entire study cost about $50.</p>

<h2 id="question-1-does-it-replicate">Question 1: Does it replicate?</h2>

<p>Yes. I was able to replicate the method with a newly written harness and a freshly generated training dataset. I am releasing that harness today as the <a href="https://github.com/rweald/mental-health-guard-harness">Mental Health Guard Harness</a>.</p>

<p>MindGuard is a distillation pipeline. A large high cost judge model reads a full synthetic conversation between a patient language model [PLM] and a clinical language model [CLM] and labels every patient turn for safety. A much smaller model, Qwen3Guard, is then fine-tuned to make that same call from a single turn in isolation. The small model is the one you actually deploy, since it is the only one cheap enough to run on every turn of every conversation.</p>

<p>I built a harness around the full pipeline: generating the conversations, running a judge over them, preparing and launching the LoRA fine-tunes on rented H100s through Modal, and evaluating both the labels and the resulting models. The harness is written in Python and is agnostic to the LLM provider API, so it could easily be converted to run on any cloud provider. Just for fun, I kept the evaluation local on my DGX Spark via Docker.</p>

<p>Before trusting any of my own numbers, I ran the published MindGuard-8B on my DGX Spark using the evaluation part of my harness. This produced an AUROC of 0.9839, within 0.002 of the paper’s reported 0.982, giving me confidence that my evaluation pipeline was working.</p>

<p>Several parts of my reproduction differed from the paper. Sword’s scenario library and CLM were unavailable. I also generated patient turns with GPT-5.6 rather than GLM-4.6, so the GLM-4.6 judge did not score dialogue it had helped generate. My reproduction used 2,282 training turns rather than 5,812, and LoRA fine-tuning rather than a full fine-tune.</p>

<p>A GLM-4.6 arm trained on my own 300 scenarios scored 0.981 against the published model’s 0.984. That is close enough to support a practical reproduction of their result, though the small gap could plausibly reflect the smaller training set or any of those other differences.</p>

<p>The <a href="https://github.com/rweald/mental-health-guard-harness">harness is available on GitHub</a>. It reproduces the pipeline described here, but users will still need to obtain the MindGuard model and clinician-labeled evaluation data under Sword’s stated license terms, and provide their own model-provider credentials and compute.</p>

<h2 id="question-2-did-it-need-their-clinical-model">Question 2: Did it need their clinical model?</h2>

<p>No, you don’t need their proprietary clinical model. Which is lucky, since had the answer been yes, the value of the method would be limited, because the one component you could not obtain would sit upstream of everything else.</p>

<p>While the judge labeling and fine-tuning never see the CLM responses, every CLM reply steers what the PLM says next. A CLM that reflects and validates draws out a different conversation than one that probes, and those PLM turns are the training data. The CLM shapes the entire training corpus indirectly, even though none of its own text ever receives a label.</p>

<p>Generating the dialogues with a frontier generalist and a well-written clinical prompt is a serviceable stand-in for a purpose-built therapist model, at least for manufacturing training dialogues within the narrow scope of this safety classification. The synthetic conversations landed where their scenarios intended: two of the three judges labeled all 185 scripted-unsafe turns as unsafe, while the third missed exactly one. Two also produced no false positives across the safe scenarios; GLM-4.6 flagged just one of the 68 deliberately ambiguous turns I kept as hard negatives. The classifiers trained on those dialogues then scored between 0.981 and 0.985 AUROC, the same band as the published MindGuard-8B at 0.984 in my harness.</p>

<h2 id="question-3-does-a-newer-judge-help">Question 3: Does a newer judge help?</h2>

<p>Yes, although the overall AUROC gap does not tell the full story.</p>

<p>Since I had to recreate the scenario library and generated conversations, this is not a controlled comparison against the original MindGuard pipeline. It is a controlled comparison between judges within my reproduction. Each judge labeled the same 300 scenarios and 2,282 patient turns, generated with GPT-5.6 as the PLM and Claude Sonnet 4.6 as the CLM. I then used the same base model, hyperparameters, hardware, and three random seeds for each arm. That produced nine fine-tuned models, all evaluated against Sword’s clinician-labeled test set, which was never used in training.</p>

<p>Before fine-tuning, I ran a face-validity check against the clinician labels. It suggested the pattern that later appeared in the fine-tuned models.</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left"><strong>Judge</strong></th>
      <th style="text-align: right"><strong>self-harm recall</strong></th>
      <th style="text-align: right"><strong>harm-to-others recall</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">DeepSeek V4 Flash</td>
      <td style="text-align: right">16/20 (0.80)</td>
      <td style="text-align: right">15/22 (0.68)</td>
    </tr>
    <tr>
      <td style="text-align: left">GLM-4.6</td>
      <td style="text-align: right">12/20 (0.60)</td>
      <td style="text-align: right">17/22 (0.77)</td>
    </tr>
    <tr>
      <td style="text-align: left">GLM-5.2</td>
      <td style="text-align: right">16/20 (0.80)</td>
      <td style="text-align: right">17/22 (0.77)</td>
    </tr>
  </tbody>
</table>

<p>GLM-5.2 found 16 of 20 self-harm turns, compared with 12 of 20 for GLM-4.6, while both found 17 of 22 harm-to-others turns. These small test-set differences were not statistically conclusive, but they confirmed that all three predetermined judge arms were plausible enough to justify the cost of the fine-tunes.</p>

<h3 id="fine-tune-results">Fine tune results</h3>

<table>
  <thead>
    <tr>
      <th style="text-align: left"><strong>Judge</strong></th>
      <th style="text-align: right"><strong>Classifier AUROC (mean ± sd)</strong></th>
      <th style="text-align: left"><strong>Seeds</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">GLM-5.2</td>
      <td style="text-align: right">0.98506 ± 0.00064</td>
      <td style="text-align: left">0.98505, 0.98443, 0.98571</td>
    </tr>
    <tr>
      <td style="text-align: left">GLM-4.6, the paper’s choice</td>
      <td style="text-align: right">0.98095 ± 0.00157</td>
      <td style="text-align: left">0.98170, 0.98201, 0.97916</td>
    </tr>
    <tr>
      <td style="text-align: left">DeepSeek V4 Flash</td>
      <td style="text-align: right">0.98069 ± 0.00091</td>
      <td style="text-align: left">0.98055, 0.98165, 0.97985</td>
    </tr>
  </tbody>
</table>

<p>Within that setup, GLM-5.2’s seed range did not overlap with either other judge’s, and its worst seed still beat the best seed from GLM-4.6 and DeepSeek. The tight seed spread shows that the fine-tunes were reproducible, but it does not make the difference between judges statistically certain. A paired bootstrap put GLM-5.2 ahead of GLM-4.6 by 0.0044 AUROC, with a confidence interval from -0.0008 to 0.0121 and a p-value of 0.13.</p>

<p>The more interesting result appears when the test set is split by risk category.</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left"><strong>Subgroup AUROC</strong></th>
      <th style="text-align: right"><strong>GLM-5.2</strong></th>
      <th style="text-align: right"><strong>GLM-4.6</strong></th>
      <th style="text-align: right"><strong>DeepSeek</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">self_harm</td>
      <td style="text-align: right">0.98172</td>
      <td style="text-align: right">0.96983</td>
      <td style="text-align: right">0.96953</td>
    </tr>
    <tr>
      <td style="text-align: left">harm_to_others</td>
      <td style="text-align: right">0.98810</td>
      <td style="text-align: right">0.99106</td>
      <td style="text-align: right">0.99083</td>
    </tr>
  </tbody>
</table>

<p>Almost all of the improvement came from self-harm, where GLM-5.2 gained about 0.012 AUROC. With only 20 positive examples in this subgroup, though, that result should be read as suggestive rather than definitive.</p>

<p>GLM-5.2 did lose about 0.003 on harm-to-others. The newer judge did not make the classifier uniformly better. It improved one clinical category while giving up a small amount on another.</p>

<h3 id="auroc-is-not-the-whole-story">AUROC is not the whole story</h3>

<p>AUROC measures performance across every possible threshold. A deployed safety classifier uses one threshold, so I also measured the false-positive rate required to reach high sensitivity.</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left"><strong>FPR @ 90% TPR</strong> (lower is better)</th>
      <th style="text-align: left"><strong>seed 0</strong></th>
      <th style="text-align: left"><strong>seed 1</strong></th>
      <th style="text-align: left"><strong>seed 2</strong></th>
      <th style="text-align: right"><strong>mean ± sd</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">GLM-5.2</td>
      <td style="text-align: left">0.0449 (49 FP, <strong>39</strong> TP)</td>
      <td style="text-align: left">0.0467 (51 FP, 38 TP)</td>
      <td style="text-align: left">0.0467 (51 FP, 38 TP)</td>
      <td style="text-align: right">0.0461 ± 0.0011</td>
    </tr>
    <tr>
      <td style="text-align: left">GLM-4.6</td>
      <td style="text-align: left">0.0412 (45 FP, 38 TP)</td>
      <td style="text-align: left">0.0394 (43 FP, <strong>39</strong> TP)</td>
      <td style="text-align: left">0.0485 (53 FP, 38 TP)</td>
      <td style="text-align: right">0.0430 ± 0.0048</td>
    </tr>
    <tr>
      <td style="text-align: left">DeepSeek V4 Flash</td>
      <td style="text-align: left">0.0375 (41 FP, 38 TP)</td>
      <td style="text-align: left">0.0403 (44 FP, 38 TP)</td>
      <td style="text-align: left">0.0403 (44 FP, 38 TP)</td>
      <td style="text-align: right"><strong>0.0394 ± 0.0016</strong></td>
    </tr>
  </tbody>
</table>

<table>
  <thead>
    <tr>
      <th style="text-align: left"><strong>FPR @ 95% TPR</strong> (lower is better)</th>
      <th style="text-align: left"><strong>seed 0</strong></th>
      <th style="text-align: left"><strong>seed 1</strong></th>
      <th style="text-align: left"><strong>seed 2</strong></th>
      <th style="text-align: right"><strong>mean ± sd</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">GLM-5.2</td>
      <td style="text-align: left">0.0623 (68 FP, <strong>41</strong> TP)</td>
      <td style="text-align: left">0.0714 (78 FP, 40 TP)</td>
      <td style="text-align: left">0.0595 (65 FP, 40 TP)</td>
      <td style="text-align: right"><strong>0.0644 ± 0.0062</strong></td>
    </tr>
    <tr>
      <td style="text-align: left">GLM-4.6</td>
      <td style="text-align: left">0.0760 (83 FP, 40 TP)</td>
      <td style="text-align: left">0.0778 (85 FP, 40 TP)</td>
      <td style="text-align: left">0.0769 (84 FP, 40 TP)</td>
      <td style="text-align: right">0.0769 ± 0.0009</td>
    </tr>
    <tr>
      <td style="text-align: left">DeepSeek V4 Flash</td>
      <td style="text-align: left">0.0788 (86 FP, <strong>41</strong> TP)</td>
      <td style="text-align: left">0.0723 (79 FP, 40 TP)</td>
      <td style="text-align: left">0.0733 (80 FP, 40 TP)</td>
      <td style="text-align: right">0.0748 ± 0.0035</td>
    </tr>
  </tbody>
</table>

<p>At roughly 90% sensitivity, DeepSeek is the cleanest of the three and GLM-5.2 is the noisiest. At roughly 95%, the order flips: GLM-5.2 produces about 16% fewer false positives than GLM-4.6, or around 14 fewer safe turns flagged in this test set. The answer depends on the operating point.</p>

<p>That is not enough data to declare a winner on this metric. There are only 42 unsafe turns, so each additional turn moves recall by more than two percentage points, and tied scores mean the models do not always land on exactly the same recall. The seed spread is also comparable to the differences between judges. I am reporting the result because it qualifies my headline: GLM-5.2 looks strongest at the higher-sensitivity operating point, but it is not uniformly better.</p>

<p>DeepSeek and GLM-4.6 differed by only 0.0004 AUROC in this experiment, and the paired bootstrap did not detect a difference ($p = 0.72$). Based on this experiment, I’d say DeepSeek remains a credible lower-cost alternative to the paper’s judge.</p>

<h2 id="question-4-what-does-it-cost">Question 4: What does it cost?</h2>

<p>About $50 for the entire study. That includes screening three judges, generating one dialogue set, producing three separate label sets, and training nine fine-tuned models.</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left"><strong>Phase</strong></th>
      <th style="text-align: right"><strong>Cost</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">Screening three judges against clinician labels</td>
      <td style="text-align: right">~$3</td>
    </tr>
    <tr>
      <td style="text-align: left">Authoring 300 scenarios and generating 300 dialogues</td>
      <td style="text-align: right">~$19</td>
    </tr>
    <tr>
      <td style="text-align: left">Labeling 2,282 turns three times</td>
      <td style="text-align: right">~$10</td>
    </tr>
    <tr>
      <td style="text-align: left">Nine LoRA fine-tunes, roughly 5 H100-hours</td>
      <td style="text-align: right">~$19</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Total</strong></td>
      <td style="text-align: right"><strong>~$50</strong></td>
    </tr>
  </tbody>
</table>

<p>Most of that cost comes from running three judge arms. A smaller experiment with one judge and three seeds would cost closer to $25 to $30: the shared data generation, one labeling pass, and less than two hours of H100 time at around four dollars per hour.</p>

<p>Labeling the full dataset with all three models was only about $10, while authoring the scenarios and generating the dialogues together was the largest API cost at about $19, matching the cost of fine-tuning on rented GPUs. That matched my expectation that producing enough synthetic conversations would be one of the largest parts of the inference budget. Screening all three predetermined judges against the clinician-labeled test set added only about $3 and confirmed that each was a plausible candidate before the more expensive fine-tunes.</p>

<p>GLM-5.2 beat GLM-4.6 while costing about 25% less for the same labeling work. DeepSeek was cheaper still, at roughly 4% of GLM-4.6’s cost, and its AUROC was nearly identical in this experiment. These numbers are only rough estimates from one provider during one week in mid-2026, and inference pricing changes quickly.</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left"><strong>Judge</strong></th>
      <th style="text-align: right"><strong>2,282 turns labeled</strong></th>
      <th style="text-align: right"><strong>Screening run</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">GLM-4.6</td>
      <td style="text-align: right">~$5.50</td>
      <td style="text-align: right">~$2.50</td>
    </tr>
    <tr>
      <td style="text-align: left">GLM-5.2</td>
      <td style="text-align: right">~$4.00</td>
      <td style="text-align: right">~$0.75</td>
    </tr>
    <tr>
      <td style="text-align: left">DeepSeek V4 Flash</td>
      <td style="text-align: right">~$0.20</td>
      <td style="text-align: right">~$0.04</td>
    </tr>
  </tbody>
</table>

<p>The larger point is that compute cost is not the issue reproducing this kind of work.
<strong>The bigger constraint is access to the expert-labeled evaluation data. We need more permissively licensed clinician validated data.</strong></p>

<hr />

<p><em>Farinhas et al., “MindGuard: Guardrail Classifiers for Multi-Turn Mental Health Support,” Sword Health, arXiv:2602.00950. MindGuard models and test set are released under CC-BY-NC-SA-4.0.</em></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Tool Calling is the Real Safety Feature]]></title>
    <link href="https://rweald.github.io/blog/2025/11/05/tool-calling-is-the-real-safety-feature/"/>
    <updated>2025-11-05T11:01:00-08:00</updated>
    <id>https://rweald.github.io/blog/2025/11/05/tool-calling-is-the-real-safety-feature</id>
    <content type="html"><![CDATA[<p><em>This post was <a href="https://www.wavelife.io/blog/tool-calling-is-the-real-safety-feature">originally published on the Wave blog</a> on November 5, 2025.</em></p>

<p>When an AI detects suicide risk, it shouldn’t improvise. It should perform a validated clinical assessment. In clinical care, that means something like the <a href="https://cssrs.columbia.edu/the-columbia-scale-c-ssrs/about-the-scale/">Columbia Suicide Severity Rating Scale</a>. Humans don’t make up the questions each time. Neither should a model.</p>

<p>We need probabilistic models to run deterministic, predefined assessments reliably. Some research is pushing LLMs in that direction, but it’s still early and unproven in production. The answer today is tool calling. When the model hits a risk flag, it can invoke a structured, evidence-based protocol: the same one a clinician would use. That makes its behavior predictable and testable.</p>

<p>Tool calling isn’t just for assessment, it’s how LLMs can take real, safe action. A model could directly schedule a session with a human coach or clinician, trigger alerts within an EHR so the care team can reach out, or even escalate to emergency services when criteria are met. These aren’t theoretical ideas; they’re how AI can integrate into existing care systems while keeping humans firmly in the loop.</p>

<p>Most evaluation frameworks focus on whether a model says the right thing when it encounters suicidal ideation. That’s a start, but it’s not enough. The evaluation needs to test what happens next: how the model uses tool calls to take action, route information, or trigger the right workflow. That’s what actually determines safety.</p>

<p>We’re building toward this kind of evaluation now. But it’s not something any one team or company can define alone. We need researchers, builders, clinicians, and other companies working together to figure out what reliable, safe tool calling should look like in mental health. And it needs to happen in the open. Shared standards are the only way to make sure “safety” means the same thing for everyone.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Simulation is the Lab: Building Safe, Measurable AI for Mental Health Care]]></title>
    <link href="https://rweald.github.io/blog/2025/10/31/simulation-is-the-lab/"/>
    <updated>2025-10-31T07:31:00-07:00</updated>
    <id>https://rweald.github.io/blog/2025/10/31/simulation-is-the-lab</id>
    <content type="html"><![CDATA[<p><em>This post was <a href="https://www.wavelife.io/blog/ai-simulation-mental-health">originally published on the Wave blog</a> on October 31, 2025.</em></p>

<p><a href="https://secondopinion.media/p/the-path-to-patient-facing-ai-follow-waymo-s-lead">Christina Farr’s recent <em>Second Opinion</em></a> piece compared patient-facing AI to self-driving cars and said healthcare should “follow Waymo’s lead.” It’s a good analogy, and in mental health care we can make it even more concrete by looking at how self-driving development worked.</p>

<p>Self-driving software advanced by logging unlimited hours in a virtual simulated environment, where it could be refined and tested before cars ever touched real roads. It also had a shared definition of quality: traffic laws. Those two pieces made safety measurable and progress possible.</p>

<p>If AI is going to earn trust in mental health, it needs the same foundations. Simulation to test safely at scale, and open, public, agreed-upon benchmarks for what “good care” means, just as traffic laws define good driving. Together, those give us the tools to measure progress and make safety real.</p>

<p>We’re building that layer now. But this can’t be done in isolation. Self-driving wouldn’t have worked if every company made up its own traffic laws, and the same is true here. At Wave, we want to help build shared benchmarks and realistic simulated patient environments so teams across mental health AI can test, learn, and iterate fast, safely.</p>

<p>That’s the foundation we need before real-world deployment. In self-driving, teams started with millions of simulated miles to refine software with zero risk. Then they ran closed-course tests under human supervision. Next came very limited public routes, expanding the radius as confidence grew. Apply the same layers here. Full autonomy, where AI runs a clinical conversation end-to-end still belongs in the simulator.</p>

<p>We’re not in the self-driving era yet. We’re in adaptive cruise control. Models can help with steering inputs like note writing, data search, or summarizing risk factors, but the human has to stay in the loop. Each step forward should teach us something new about context, safety, and failure modes.</p>

<p>Plenty of open questions here, and no analogy maps perfectly. We’re working through them in public because this feels too important to build entirely behind closed doors.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Spark Meetup: Monoids, Store, and Dependency Injection - Abstractions for Spark Streaming Jobs]]></title>
    <link href="https://rweald.github.io/blog/2014/01/20/spark-meetup-monoids/"/>
    <updated>2014-01-20T18:41:00-08:00</updated>
    <id>https://rweald.github.io/blog/2014/01/20/spark-meetup-monoids</id>
    <content type="html"><![CDATA[<p>Below is the presentation I gave at the Spark User Meetup on 01/16/2014</p>

<h3 id="monoids-store-and-dependency-injection---abstractions-for-spark-streaming-jobs">Monoids, Store, and Dependency Injection - Abstractions for Spark Streaming Jobs</h3>

<h4 id="abstract">Abstract:</h4>
<p>One of the most difficult aspects of deploying spark streaming as part of your technology stack is maintaining all the code associated 
with stream processing jobs. In this talk I will discuss the tools and techniques that Sharethrough has found most useful for maintaining a large number of spark streaming jobs. 
We will look in detail at the way Monoids and Twitter’s Algebrid library can be used to create generic aggregations.
 As well as the way we can create generic interfaces for writing the results of streaming jobs to multiple data stores.
 Finally we will look at the way dependency injection can be used to tie all the pieces together, enabling raping development of new streaming jobs.</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/C7gWtxelYNM" frameborder="0" allowfullscreen=""></iframe>
<script async="" class="speakerdeck-embed" data-id="916d7bc061cf0131881c3e1e04cfd46e" data-ratio="1.2994923857868" src="https://rweald.github.io//speakerdeck.com/assets/embed.js"></script>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Spark Summit 2013 - Productionalizing Spark Streaming]]></title>
    <link href="https://rweald.github.io/blog/2014/01/11/spark-summit-2013-productionalizing-spark-streaming/"/>
    <updated>2014-01-11T10:54:00-08:00</updated>
    <id>https://rweald.github.io/blog/2014/01/11/spark-summit-2013-productionalizing-spark-streaming</id>
    <content type="html"><![CDATA[<p>Below is the presentation I gave at <a href="https://spark-summit.org/summit-2013/">Spark Summit 2013</a></p>

<h3 id="productionalizing-spark-streaming">Productionalizing Spark Streaming</h3>

<p>At Sharethrough we have deployed Spark to our production environment to support several user facing product features. While building these features we uncovered a consistent set of challenges across multiple streaming jobs. By addressing these challenges you can speed up development of future streaming jobs. In this talk we will discuss the 3 major challenges we encountered while developing production streaming jobs and how we overcame them.</p>

<p>First we will look at how to write jobs to ensure fault tolerance since streaming jobs need to run 24/7 even under failure conditions. Second we will look at the programming abstractions we created using functional programming and existing libraries. Finally we will look at the way we test all the pieces of a job –from manipulating data through writing to external databases– to give us confidence in our code before we deploy to production</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/OhpjgaBVUtU" frameborder="0" allowfullscreen=""></iframe>
<script async="" class="speakerdeck-embed" data-id="a45f30f03dd70131600346451c48010b" data-ratio="1.2994923857868" src="https://rweald.github.io//speakerdeck.com/assets/embed.js"></script>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Analyzing DocGraph - What Type of Doctor Will You See Next?]]></title>
    <link href="https://rweald.github.io/blog/2013/06/02/what-doctor-will-you-see-next/"/>
    <updated>2013-06-02T09:29:00-07:00</updated>
    <id>https://rweald.github.io/blog/2013/06/02/what-doctor-will-you-see-next</id>
    <content type="html"><![CDATA[<p>In my previous posts analyzing the <a href="https://docgraph.org/?page_id=4">DocGraph</a> dataset I have looked at 
<a href="https://rweald.github.io/blog/2012/12/13/visualizing-geographic-connections-between-us-doctors/">the geographic connections between referrals</a> and
<a href="https://rweald.github.io/blog/2013/01/27/analyzing-out-of-state-patient-referrals-using-docgraph/">out of state referrals</a>. In this post I decided to change
directions from geographic analysis and instead focus on the different types of providers involved in patient referrals. In particular I wanted to take a crack at answering the question:
“what type of doctor will you see next?”</p>

<p>As always the first step to answering this question was to enrich the <a href="https://docgraph.org/?page_id=4">DocGraph</a> data with data from the NPI database. In particular we need the taxonomy code for each of the nodes in the <a href="https://docgraph.org/?page_id=4">DocGraph</a> dataset.
After the we have added taxonomy code to all the nodes we then want to aggregate all referrals by taxonomy code to shrink the size of our dataset down into something that is more easily managed on a single machine.
In order to achieve this goal with short iteration time I used <a href="https://bit.ly/10RKWmf">Amazon EMR</a> and <a href="https://hive.apache.org/">Apache Hive</a>. The distributed nature of <a href="https://hadoop.apache.org/">Hadoop</a> and <a href="https://hive.apache.org/">Hive</a> enabled me to join the large
NPI database with the even larger <a href="https://docgraph.org/?page_id=4">DocGraph</a> dataset and perform the necessary aggregation all in under 20 minutes with a cost of only $1.04. You can find the Hive script I used to perform the join and aggregation on <a href="https://bit.ly/16Br1Qo">Github</a>.</p>

<p>Once the Docgraph dataset had been aggregated by taxonomy code it was a simple matter of converting the taxonomy code to the human readable provider type. This was achieved using the <a href="https://www.nucc.org/index.php?option=com_content&amp;view=article&amp;id=14&amp;Itemid=125">Health Care Provider Taxonomy dataset</a> 
and some R code that you can find on <a href="https://bit.ly/11O4FrY">Github</a>. A little bit more aggregation to account for the multiple levels of taxonomy codes, including specialization, and the data needed to answer our question was ready. I also removed any referrals where both nodes were of the same provider
type as these are most likely noise in the dataset caused by the billing method through which the <a href="https://docgraph.org/?page_id=4">DocGraph</a> data was collected.</p>

<p>Below is a table showing the top 20 referrals between provider types. Not surprisingly we can see that the vast majority of patients are being referred for to Radiology 
for various types of test such as X-rays, CT scans, and MRIs. They are then referred back to an <em>Internal Medicine</em> doctor which I hypothesize is the physician acting as primary care.
Another interesting, but not all that surprising, relationship is the number of referrals between <em>Emergency Medicine</em> and <em>Internal Medicine</em>. Here I hypothesize that patients are being
seen for some emergency medical condition and then receive follow-up care from their primary care provider.</p>

<p>Perhaps the most interesting observation from this top 20 list is the number of times <em>Internal Medicine - Cardiovascular Disease</em> appears. I always knew that America had a problem with heart disease but I was still a bit surprised at the volume of this type of referral. I would love to hear if anyone else has a hypothesis for why there are so many referrals 
related to <em>Internal Medicine - Cardiovascular Disease</em>.</p>

<table border="0" class="table table-bordered table-striped">
  <tbody> 
    <tr class="firstline"> 
      <th>Provider Type Seen First </th>
      <th>Provider Type Seen Second </th>
      <th>Number of Patients</th> 
    </tr> 
    <tr> 
      <td class="cellinside">Radiology - Diagnostic Radiology
      </td>
      <td class="cellinside">Internal Medicine - General
      </td>
      <td class="cellinside">115,602,860
    </td></tr>

    <tr> 
      <td class="cellinside">Internal Medicine - General
      </td>
      <td class="cellinside">Radiology - Diagnostic Radiology
      </td>
      <td class="cellinside"> 91,632,055
    </td></tr>

    <tr> 
      <td class="cellinside">Internal Medicine - Cardiovascular Disease
      </td>
      <td class="cellinside">Internal Medicine - General
      </td>
      <td class="cellinside"> 54,260,749
    </td></tr>

    <tr> 
      <td class="cellinside">Radiology - Diagnostic Radiology
      </td>
      <td class="cellinside">Internal Medicine - Cardiovascular Disease
      </td>
      <td class="cellinside"> 49,406,691
    </td></tr>

    <tr> 
      <td class="cellinside">Internal Medicine - Cardiovascular Disease
      </td>
      <td class="cellinside">Radiology - Diagnostic Radiology
      </td>
      <td class="cellinside"> 47,820,945
    </td></tr>

    <tr> 
      <td class="cellinside">Internal Medicine - General
      </td>
      <td class="cellinside">Internal Medicine - Cardiovascular Disease
      </td>
      <td class="cellinside"> 47,351,852
    </td></tr>

    <tr> 
      <td class="cellinside">Radiology - Diagnostic Radiology
      </td>
      <td class="cellinside">Family Medicine - General
      </td>
      <td class="cellinside"> 45,078,839
    </td></tr>

    <tr> 
      <td class="cellinside">Family Medicine - General
      </td>
      <td class="cellinside">Radiology - Diagnostic Radiology
      </td>
      <td class="cellinside"> 40,181,846
    </td></tr>

    <tr> 
      <td class="cellinside">Emergency Medicine - General
      </td>
      <td class="cellinside">Radiology - Diagnostic Radiology
      </td>
      <td class="cellinside"> 33,797,598
    </td></tr>

    <tr> 
      <td class="cellinside">Emergency Medicine - General
      </td>
      <td class="cellinside">Internal Medicine - General
      </td>
      <td class="cellinside"> 32,236,140
    </td></tr>

    <tr> 
      <td class="cellinside">Radiology - Diagnostic Radiology
      </td>
      <td class="cellinside">Specialist - General
      </td>
      <td class="cellinside"> 27,710,610
    </td></tr>

    <tr> 
      <td class="cellinside">Specialist - General
      </td>
      <td class="cellinside">Internal Medicine - General
      </td>
      <td class="cellinside"> 26,478,301
    </td></tr>

    <tr> 
      <td class="cellinside">Internal Medicine - General
      </td>
      <td class="cellinside">Specialist - General
      </td>
      <td class="cellinside"> 24,876,128
    </td></tr>

    <tr> 
      <td class="cellinside">Specialist - General
      </td>
      <td class="cellinside">Radiology - Diagnostic Radiology
      </td>
      <td class="cellinside"> 23,929,823
    </td></tr>

    <tr> 
      <td class="cellinside">Radiology - Diagnostic Radiology
      </td>
      <td class="cellinside">Emergency Medicine - General
      </td>
      <td class="cellinside"> 23,424,750
    </td></tr>

    <tr> 
      <td class="cellinside">Internal Medicine - General
      </td>
      <td class="cellinside">Family Medicine - General
      </td>
      <td class="cellinside"> 22,561,522
    </td></tr>

    <tr> 
      <td class="cellinside">Radiology - Diagnostic Radiology
      </td>
      <td class="cellinside">Internal Medicine - Nephrology
      </td>
      <td class="cellinside"> 22,479,825
    </td></tr>

    <tr> 
      <td class="cellinside">Radiology - Diagnostic Radiology
      </td>
      <td class="cellinside">Internal Medicine - Pulmonary Disease
      </td>
      <td class="cellinside"> 21,796,186
    </td></tr>

    <tr> 
      <td class="cellinside">Family Medicine - General
      </td>
      <td class="cellinside">Internal Medicine - General
      </td>
      <td class="cellinside"> 20,872,086
    </td></tr>

    <tr> 
      <td class="cellinside">Internal Medicine - Cardiovascular Disease
      </td>
      <td class="cellinside">Family Medicine - General
      </td>
      <td class="cellinside"> 19,047,613
    </td></tr>

  </tbody>
</table>

<p>If you would like to see more than just the top 20 referrals by provider type you can download the complete list <a href="https://bit.ly/19zzTER">here</a></p>

<p>Finally, I can’t resist a sexy visualization that helps to convey the elegance of the <a href="https://docgraph.org/?page_id=4">DocGraph</a> dataset. Below you will find a visualization of the
referrals between provider types. The thickness of the edge reflects the number of patients that are referred between the two provider types. To create the visualization I used the open source <a href="https://gephi.org/">Gephi</a> graph visualization platform.</p>

<p><span style="font-size: 0.8em; font-style: italic;">
  click on the image below to see the full size version
</span></p>

<p><a href="https://rweald-docgraph-analysis.s3.amazonaws.com/referrals-by-provider-graph.png">
  <img src="https://rweald-docgraph-analysis.s3.amazonaws.com/referrals-by-provider-graph.png" width="800" height="800" alt="visualization of referrals by provider" />
</a></p>

<p>I hope you have enjoyed my analysis. 
I am always open to feedback and would love to collaborate on analysis related to <a href="https://strata.oreilly.com/2012/11/docgraph-open-social-doctor-data.html">DocGraph</a> or open health data in general.
If you are interested in collaborating please email me ryan [at] weald.com or message me on twitter <a href="https://twitter.com/rweald">@rweald</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[LA RubyConf 2013 - Building Recommendation Systems in Ruby]]></title>
    <link href="https://rweald.github.io/blog/2013/04/29/la-rubyconf-2013-building-recommendation-systems-in-ruby/"/>
    <updated>2013-04-29T08:06:00-07:00</updated>
    <id>https://rweald.github.io/blog/2013/04/29/la-rubyconf-2013-building-recommendation-systems-in-ruby</id>
    <content type="html"><![CDATA[<p>Below is the presentation I gave at LA RubyConf 2013 titled, “<em>People who liked this talk also liked … Building Recommendation Systems Using Ruby</em>”</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/fh1y1BUTJxE" frameborder="0" allowfullscreen=""></iframe>

<script async="" class="speakerdeck-embed" data-id="2438b36061a7013038f7123139414c5a" data-ratio="1.2994923857868" src="https://rweald.github.io//speakerdeck.com/assets/embed.js"></script>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Analyzing Out-of-State Patient Referrals Using DocGraph]]></title>
    <link href="https://rweald.github.io/blog/2013/01/27/analyzing-out-of-state-patient-referrals-using-docgraph/"/>
    <updated>2013-01-27T14:38:00-08:00</updated>
    <id>https://rweald.github.io/blog/2013/01/27/analyzing-out-of-state-patient-referrals-using-docgraph</id>
    <content type="html"><![CDATA[<p>I previously built a <a href="https://rweald.github.io/blog/2012/12/13/visualizing-geographic-connections-between-us-doctors/">visualization of the U.S. medical graph</a> using the 
<a href="https://strata.oreilly.com/2012/11/docgraph-open-social-doctor-data.html">DocGraph</a> dataset.
The visualization prompted me to ask the question, does the state where you live affect the likelihood you will be referred to a doctor in another state?</p>

<p>Using the full <a href="https://strata.oreilly.com/2012/11/docgraph-open-social-doctor-data.html">DocGraph</a> dataset I was able to answer this question; in short North Carolina had the highest percentage of patients referred out-of-state with ~ 28% of referrals going out of state. Michigan and California had the lowest percent with only ~10% of referrals going out of state.</p>

<p>In the remainder of this post I shall describe the process I used to obtain these result and provide a more detailed look at the impact state has on probability of inter-state referrals.</p>

<p>The first step in the analysis was joining the DocGraph referral graph with the 
<a href="https://www.cms.gov/Regulations-and-Guidance/HIPAA-Administrative-Simplification/NationalProvIdentStand/index.html">National Provider Identifier database</a>. 
By joining DocGraph with the NPI database I was able to determine the state of the referring physician as well as the state of the physician the patient was being referred to. After augmenting the DocGraph with this additional information it was simply a matter of aggregating referrals grouped by state. Once aggregated I had a state to state adjacency matrix which could be further aggregated to generate the graphs shows below.</p>

<p>For details on reproducing this analysis and all the code used <a href="https://github.com/rweald/docgraph-data-analysis/tree/master/state-level-graph-analysis">visit Github</a>. There are also some limitations to this analysis that are described in the footnotes <a href="#limitations">1</a>.</p>

<p>Below is a <a href="https://en.wikipedia.org/wiki/Choropleth_map">choropleth map</a> representing the percent of patients that were referred outside of the state. As you can see North Carolina, Pennsylvania have the highest percent out-of-state referrals. There is also an area of increased out-of-state referrals in the <a href="https://en.wikipedia.org/wiki/File:Census_Regions_and_Division_of_the_United_States.svg">mountain region</a>.</p>

<p><em>Click on any of the images below to see a full size version</em>
<a href="https://bit.ly/Wvyfes">
  <img src="https://s3.amazonaws.com/rweald-docgraph-analysis/percent-leaving-state-choropleth-dev.png" alt="percent-out-of-state-referrals" height="450" width="800" />
</a></p>

<p>A complement to the above image is shown below; The color represents the percent of patients that are referred within the same state. As you would expect the larger states such as California, Texas, and New York have the highest percentage of patients referred within the same state.</p>

<p><a href="https://bit.ly/X4RRH9">
  <img src="https://s3.amazonaws.com/rweald-docgraph-analysis/percent-in-state-choropleth-dev.png" alt="percent-in-state-referrals" height="450" width="800" />
</a></p>

<p>For those readers who want more detail on the statistical distributions of state level referrals you can find <a href="https://en.wikipedia.org/wiki/Kernel_density_estimation">kernel density estimate</a> plots in the footnotes <a href="#distributions">2</a>.</p>

<p>After analyzing the probability of inter-referrals I got curious where all these out-of-state referrals were going. As a first step towards understanding out-of-state referrals I assembled a <a href="https://en.wikipedia.org/wiki/Heat_map">heat map</a>. This heat map provides some details on which states patients are being referred to. Each square in the heat map represents an entry in the state to state adjacency matrix contained in the DocGraph network.</p>

<p><a href="https://bit.ly/W9mpdx">
  <img src="https://s3.amazonaws.com/rweald-docgraph-analysis/inter-state-referrals-heatmap.png" alt="inter-state-referral-heatmap" height="450" width="800" />
</a></p>

<p>The results above should have provide a good answer to the question of the impact of state on likelihood of out-of-state referrals. In addition we can get an idea of which states have the most inter-state referral traffic. Overall I think this analysis brings us one step closer to unlocking the potential of the <a href="https://strata.oreilly.com/2012/11/docgraph-open-social-doctor-data.html">DocGraph</a> data to help us understand the U.S. health graph <a href="#limitations">1</a>.</p>

<p>I hope you have enjoyed my analysis. 
I am always open to feedback and would love to collaborate on some research related to analyzing the <a href="https://strata.oreilly.com/2012/11/docgraph-open-social-doctor-data.html">DocGraph</a>
data set. 
If you are interested in collaborating on research related to <a href="https://strata.oreilly.com/2012/11/docgraph-open-social-doctor-data.html">DocGraph</a>
 please email me ryan [at] weald.com or message me on twitter <a href="https://twitter.com/rweald">@rweald</a></p>

<div style="border-top: 1px solid grey"> </div>
<p>#####Footnotes</p>
<div style="font-size: 80%;">
  <span style="font-style: bold:"> 1.</span>
  <p id="limitations">
  There are a couple of important limitations of the data to remember when interpreting this analysis. The DocGraph data set only includes data from 2011; we can assume that physician behavior is much the same today as it was in 2011, however without a sample from some other time period we can not be sure. Secondly, DocGraph only represents Medicare referrals which may not be representative of the entire healthcare system. Unfortunately a more comprehensive dataset including private referrals is not available to me at this time. Therefore, the DocGraph dataset is the best referral sample I could get as a private citizen.
  </p>

  <span style="font-style: bold:"> 2.</span>
  <a id="distributions" href="https://bit.ly/WhQSVV">
    <img src="https://s3.amazonaws.com/rweald-docgraph-analysis/general-statistical-plots.png" alt="percent-in-state-referrals" height="360" width="640" />
  </a>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Visualizing the Geographic Connections Between U.S. Doctors]]></title>
    <link href="https://rweald.github.io/blog/2012/12/13/visualizing-geographic-connections-between-us-doctors/"/>
    <updated>2012-12-13T08:05:00-08:00</updated>
    <id>https://rweald.github.io/blog/2012/12/13/visualizing-geographic-connections-between-us-doctors</id>
    <content type="html"><![CDATA[<p>I recently acquired access to the <a href="https://strata.oreilly.com/2012/11/docgraph-open-social-doctor-data.html">DocGraph</a> data set on
<a href="https://www.medstartr.com/projects/93-phase-ii-next-level-doctor-social-graph">MedStartr</a>. 
This data set contains a social network of U.S. doctors, with each connection representing
a physician referring a patient to another physician. 
Given this new unique data I thought it would be interesting to investigate the geographic connections between doctors. What better way to start
analyzing the data than to make a sexy visualization.</p>

<p>To create the final visualization I had to combine multiple data sets to enrich the doctor social graph with geographic coordinates. 
I began by taking a sample of 1 million connections from
<a href="https://strata.oreilly.com/2012/11/docgraph-open-social-doctor-data.html">DocGraph</a> and joining it with the 
<a href="https://en.wikipedia.org/wiki/National_Provider_Identifier">National Provider Identifier</a> (NPI) database.
By joining these two data sets I was able to get the zip code of each physicians practice. The final step was converting the zip codes to 
latitude-longitude coordinates using
a <a href="https://federalgovernmentzipcodes.us/">publicly available zip code database</a>. Now that the data was in the correct format I began work on the visualization.</p>

<p>The visualization I choose was heavily inspired by the great
work of <a href="https://www.facebook.com/notes/facebook-engineering/visualizing-friendships/469716398919">Paul Butler at Facebook</a>.</p>

<p>Using a similar method to the one documented in <a href="https://flowingdata.com/2011/05/11/how-to-map-connections-with-great-circles/">Nathan Yau’s tutorial</a> I graphed the
connections between physicians using <a href="https://en.wikipedia.org/wiki/Great_circle">great circles</a>. In order to see the cluster density I layered the connections
using Euclidean distance, with the longest paths being drawn first.
All of the code used to generate this visualization is open source and can be found on <a href="https://github.com/rweald/docgraph-data-analysis/tree/master/visualize-geographic-connections">Github</a></p>

<p>Below is the resulting visualization. Note the areas of high and low density as you move from the east coast over to the west coast.
There are also some interesting connections from
Hawaii and Puerto Rico to the Continental United States.</p>

<p><a href="https://s3.amazonaws.com/rweald-docgraph-analysis/map-of-connections-fullsize.png">
  <img src="https://s3.amazonaws.com/rweald-docgraph-analysis/map-of-connections-thumbnail.png" alt="Doctor to Doctor connections visualized" />
</a></p>

<p>You can download the full sized graphic <a href="https://s3.amazonaws.com/rweald-docgraph-analysis/map-of-connections-with-text-fullsize.png">here</a>.
<span style="font-size: 0.8em; font-style: italic;">
  I recommend you right-click and “save link as” because the file is approximately 40MB.
</span></p>

<p>This visualization is only the beginning. The added feature of geography opens the door to many interesting analyses.
I would love to collaborate on some research related to analyzing the <a href="https://strata.oreilly.com/2012/11/docgraph-open-social-doctor-data.html">DocGraph</a>
data set. If you are interested in collaborating on research related to <a href="https://strata.oreilly.com/2012/11/docgraph-open-social-doctor-data.html">DocGraph</a>
 please email me ryan [at] weald.com or message me on twitter <a href="https://twitter.com/rweald">@rweald</a></p>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Building Data Driven Products With Ruby - RubyConf 2012]]></title>
    <link href="https://rweald.github.io/blog/2012/12/03/building-data-driven-products-with-ruby-rubyconf-2012/"/>
    <updated>2012-12-03T20:36:00-08:00</updated>
    <id>https://rweald.github.io/blog/2012/12/03/building-data-driven-products-with-ruby-rubyconf-2012</id>
    <content type="html"><![CDATA[<p>Below is the presentation I gave at RubyConf 2012 titled, “Building Data Driven Products With Ruby.”</p>

<p>You can view the slides on <a href="https://speakerdeck.com/rweald/building-data-driven-products-with-ruby">Speaker Deck</a></p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/XIqRdB5HCYM" frameborder="0" allowfullscreen=""></iframe>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Linear Regression Using Ruby]]></title>
    <link href="https://rweald.github.io/blog/2012/09/12/linear-regression-using-ruby/"/>
    <updated>2012-09-12T07:45:00-07:00</updated>
    <id>https://rweald.github.io/blog/2012/09/12/linear-regression-using-ruby</id>
    <content type="html"><![CDATA[<h4 id="posted-on-the-sharethrough-engineering-blog">*Posted on the <a href="https://www.sharethrough.com/2012/09/linear-regression-using-ruby/">Sharethrough Engineering Blog</a></h4>

<p><em>Abstract:</em></p>

<p>I walk you through the basics of
linear regression, and show you how you can perform <em>simple linear regression</em> using Ruby</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Banking Your Profits, How to upgrade to Rails 3]]></title>
    <link href="https://rweald.github.io/blog/2012/04/15/banking-your-profits/"/>
    <updated>2012-04-15T00:00:00-07:00</updated>
    <id>https://rweald.github.io/blog/2012/04/15/banking-your-profits</id>
    <content type="html"><![CDATA[<p>Let me start off by saying this is not a post touting all the great new features available in the latest version of Rails. I am not going to try and convince you that there is no way you can be productive staying on your current version of Rails. Instead this is a post about the way you can improve the overall quality of your codebase and reduce technical debt even if you never fully complete the upgrade. I am going to outline the process that we used at <a href="https://sharethrough.github.com">Sharethrough</a> to improve the quality of our codebase while upgrading from Rails 2 to Rails 3.</p>

<p>The driving principle behind this post is “Banking your profits”. In
software development that means making small focused commits on your
master branch and using <em>continuous integration</em>[<a href="#ci">1</a>] to get those small changes integrated with the rest of your production code. By banking these profits along the way you gaining value even if you never succeed with the larger effort.</p>

<p>So how can you possibly make small focused commits when you are working on an undertaking as monumental as a Rails 3 upgrade?
The key to our success was small short lived Branches. The rules that governed these branches are as follows:</p>

<p>1) No branch may live longer than 24 hours</p>

<p>2) You can not make any unnecessary changes that could not be backported.</p>

<p>Following these rules you are able to shift your mindset. Rather than an
all or nothing sprint we instead methodically identified technical debt
that was hindering the upgrade but not directly a result of Rails API
incompatibilities. It was really quite amazing how much of the upgrade
pain was actually the result of tight coupling and
<em>SOLID</em>[<a href="#solid">2</a>] design principle violations rather than Rails 3 incompatibilities.</p>

<p>Whenever we encountered a piece of debt that was hindering our upgrade we would switch back to the master branch and fix the code. Following this method the all or nothing part of the upgrade only took 2 days! The best part was even if we had never succeeded on the final portion of the upgrade we would have drastically improved the quality of the code allowing the team to move faster.</p>

<p>If you follow the technique outlined here you will improve the quality of your codebase regardless of whether the upgrade is successful.</p>

<p>P.S.</p>

<p>Want to work with me tackling hard problems across the stack using TDD and pair programming?
<a href="https://www.sharethrough.com/engineering/">Sharethrough is hiring talented engineers</a></p>

<p><a name="ci"></a> [1] <a href="https://en.wikipedia.org/wiki/Continuous_integration">https://en.wikipedia.org/wiki/Continuous_integration</a></p>

<p><a name="solid"></a> [2] <a href="https://en.wikipedia.org/wiki/SOLID_\(object-oriented_design\)">https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[SDRuby Lightning Talk - Give Yourself Some Backbone]]></title>
    <link href="https://rweald.github.io/blog/2011/07/16/sdruby-lightning-talk-give-yourself-some-backbone/"/>
    <updated>2011-07-16T11:02:00-07:00</updated>
    <id>https://rweald.github.io/blog/2011/07/16/sdruby-lightning-talk-give-yourself-some-backbone</id>
    <content type="html"><![CDATA[<p>Below is a lightening talk I gave at an SD Ruby Meetup. It was my first every tech presentation to a public industry audience.</p>

<script async="" class="speakerdeck-embed" data-id="499a83b05d21013169236e4c83706996" data-ratio="1.2994923857868" src="https://rweald.github.io//speakerdeck.com/assets/embed.js"></script>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Using Mongoid Alongside ActiveRecord]]></title>
    <link href="https://rweald.github.io/blog/2011/05/26/mongoid-activerecord-side-by-side/"/>
    <updated>2011-05-26T00:00:00-07:00</updated>
    <id>https://rweald.github.io/blog/2011/05/26/mongoid-activerecord-side-by-side</id>
    <content type="html"><![CDATA[<p>MongoDB is a very popular document oriented database and more apps are
using it every day. However, we all know about the problems that mongo
has with data durability. So you might not want to use it as a complete
replacment for ActiveRecord and your favorite sql store. 
<a href="http://mongoid.org">Mongoid</a> is an ActiveModel compliant ORM for
MongoDB. Below I will outline how you can use Mongoid alongside
ActiveRecord in your rails 3 app.</p>

<p>1) Add mongoid to your gemfile</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
  <span class="n">gem</span> <span class="s2">"mongoid"</span><span class="p">,</span> <span class="s2">"~&gt; 2.0"</span>
  <span class="n">gem</span> <span class="s2">"bson_ext"</span><span class="p">,</span> <span class="s2">"~&gt; 1.3"</span>

</code></pre></div></div>

<p>2) Run the mongoid generator in your projects root directory</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rails</span> <span class="n">generate</span> <span class="n">mongoid</span><span class="ss">:config</span>
</code></pre></div></div>

<p>This will generate a config/mongoid.yml file where you can configure
your connection to mongodb.</p>

<p>3) Right now mongoid has overriden activerecord as the default orm so
any attempts to generate migrations or ActiveRecord models will fail. 
Therefore we must configure our default generators so we can still use
activerecord.</p>

<p>To do that simple add the following line to your config/application.rb
file</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">config</span><span class="p">.</span><span class="nf">generators</span> <span class="k">do</span> <span class="o">|</span><span class="n">g</span><span class="o">|</span>
    <span class="n">g</span><span class="p">.</span><span class="nf">orm</span> <span class="ss">:active_record</span>
  <span class="k">end</span>

</code></pre></div></div>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[2011 Experimenting With Goliath And Eventmachine]]></title>
    <link href="https://rweald.github.io/blog/2011/05/12/2011-experimenting-with-goliath-and-EventMachine/"/>
    <updated>2011-05-12T00:00:00-07:00</updated>
    <id>https://rweald.github.io/blog/2011/05/12/2011-experimenting-with-goliath-and-EventMachine</id>
    <content type="html"><![CDATA[<p>After hearing lots of buzz surrounding <a href="https://github.com/postrank-labs/goliath">Goliath</a> the new asynchronous web server for ruby I thought I would give it a try for a particular problem I had. As part of <a href="https://github.com/icl/cove">COVE</a>, an open source online video ethnography tool, we have to handle large video file uploads. The application is written in Rails which is great except when you have really long running connections. With long running connections it ties up your mongrels and reduces your ability to service request.</p>

<p>The reason for this is because Rails is an inherently I/O blocking.
When you run your application in production using
<a href="http://www.modrails.com/">Passenger</a> or <a href="https://github.com/blog/517-unicorn">Unicorn</a> you essentially fork worker processes which are each responsible for servicing 1 requests at a time. To prevent memory bloating if a worker takes to long to respond or consumes too much memory it is killed. Well that presents a bit of a problem when you are talking about streaming file uploads that will require an active connection be left open while the file is uploaded. This large file upload request will block one of our worker processes which present an interesting problem. Since our process is blocked it is unable to service any additional request. This will lead to serious response time issues as our worker will be tied up handling these slow requests. To solve this we could spin up more worker processes, but this in turn takes more memory and more CPU and more resources in general.There must be a simpler solution!</p>

<p>It turns out there is in fact a simpler solution…<a href="https://en.wikipedia.org/wiki/Reactor_pattern">Event Driven Programming</a> and the
<a href="https://en.wikipedia.org/wiki/Event-driven_programming">Reactor Pattern</a>. I know what you are thinking, He’s talking about NodeJS. Well yes and no, NodeJS is indeed a javascript event based asyncronous web server. However, I like ruby and I want to program my web service in ruby so where does that leave me; <a href="https://rubyeventmachine.com/">Eventmachine</a>. EventMachine is a c++ based event-processing library with a rich ruby API that allows for event oriented programming using an event loop and callbacks. Programming a web service using EventMachine can be a little bit of a pain in the ass as your code quickly starts to look like spaghetti and that is where Goliath comes in.</p>

<p>Goliath is described as “Non-blocking, Ruby 1.9 Web Server.” It supports
the full rack API and utilizes ruby 1.9.2’s fibers to make readable top
down code. If you want to learn more you can check out some great
articles by <a href="https://www.igvita.com/2011/03/08/goliath-non-blocking-ruby-19-web-server/">Ilya Grigorik</a>. Essentially goliath gives us a great way to write code that follows a top down flow and it easy to read, but in reality it is running asynchronously using EventMachine. Now what the heck does that mean to me you ask. Well what that means is in under 30 lines of code I was able to write an asynchronous file upload server.</p>

<p>And here it is:</p>

<div><script src="https://gist.github.com/rweald/969981.js"></script></div>

<p>This was just my first plunge into the world of Non-blocking evented code so I am by no means an expert. If you see that I have made a terrible mistake or just want to give me some pointers feel free to do some. 
Just remember I am still young and while my college peers were out partying I was writing this code so try and make all criticism constructive</p>

<p>In my next post I will document the upload client that also takes
advantaged of EventMachine and fibers to compute checksums and upload
files to the web service.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Caching Responses From Remote APIs]]></title>
    <link href="https://rweald.github.io/blog/2011/04/05/caching-responses-from-external-apis/"/>
    <updated>2011-04-05T00:00:00-07:00</updated>
    <id>https://rweald.github.io/blog/2011/04/05/caching-responses-from-external-apis</id>
    <content type="html"><![CDATA[<p><a href="http://secure.dokbot.com">Dokbot</a>, the project that I am currently
working on, utilizes the mendeley API to add citations to posts. To 
achieve this the application allows users to click an add citation
button which brings up a modal view where the user can enter a search
term that will be sent off the the mendeley API. To provide the a
positive user experience the search form must be highly responsive. This
presented a problem because the <a href="https://mendeley.com">mendeley</a> API
although resonably responsible was not quite snappy enought to provide
the UX we were looking for.</p>

<p>To remidy this problem we decided to route the search request through
our own application servers. Although at first glance this might appear
to be a bad idea as it would increase latency, it turns out it actual
decreased the average latency. The cause for this decrease in
latency; caching. It turns out that most users enter the same search
term almost every time they enter a citation. With this in mind we wrote
some code in our application that caches the responses from mendeley API
that way for any given search query we only have to make 1 request to
the mendeley API. All subsequent requests for the search term will be
returned from our application cache rather than a request to the API.</p>

<p>Caching was also a resonable solution for this particular problem
because the mendeley search results change very infrequently.</p>

<p>You can see the code below that was used to cache the mendeley API
response using whatever cache <a href="https://guides.rubyonrails.org/caching_with_rails.html">Rails</a> is configured to use.</p>

<p>####The Code</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">search_mendeley</span><span class="p">(</span><span class="n">query</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span>
  <span class="k">raise</span> <span class="s2">"no query specified"</span> <span class="k">unless</span> <span class="n">query</span>

  <span class="n">papers</span> <span class="o">=</span> <span class="no">Rails</span><span class="p">.</span><span class="nf">cache</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="n">query</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">query</span><span class="o">|</span>
    <span class="n">response</span> <span class="o">=</span> <span class="no">Mendeley</span><span class="o">::</span><span class="no">API</span><span class="o">::</span><span class="no">Documents</span><span class="p">.</span><span class="nf">search</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
    <span class="n">papers</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s2">"documents"</span><span class="p">][</span><span class="mi">0</span><span class="o">..</span><span class="mi">5</span><span class="p">]</span>
  <span class="k">end</span>

  <span class="k">return</span> <span class="n">papers</span>
<span class="k">end</span>
</code></pre></div></div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Mongodb Indexes With Rspec]]></title>
    <link href="https://rweald.github.io/blog/2011/03/07/mongodb-indexes-with-rspec/"/>
    <updated>2011-03-07T00:00:00-08:00</updated>
    <id>https://rweald.github.io/blog/2011/03/07/mongodb-indexes-with-rspec</id>
    <content type="html"><![CDATA[<p>I recently had need to test some geospatial queries in a rails
application.
At first this seems like nothing out of the ordinary but there are 
a couple of minor details that if forgotten can result in failing tests</p>

<p>The main difference between geo queries and your average run of the mill
query is the need for and index. 
Normally when a simple unit test suite is run you don’t worry about
building indexes as you wont be querying large amounts of data to speed 
is not an issue. Besides if you are reading this you are using Rspec 
which means you are not too concerned with your test speed.</p>

<p>However, if you want to test geo queries in MongoDB you will have to 
ensure that your index is built or the query can not be executed.
This is because geospatial queries can only be run against a special 2D index 
and not against the underlying data.</p>

<p>Now the obvious solution would be to place some code in your
spec_helper file that will create the indexes. 
I felt like this was a bit to heavy handed since I only wanted 
to test the geospatial queries in 1 describe block.</p>

<p>So to fix the problem I choose to add a call to Mongoid::Indexes create_indexes
method within my before block.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">describe</span> <span class="s2">".guides_nearby"</span> <span class="k">do</span>
  <span class="n">before</span><span class="p">(</span><span class="ss">:each</span><span class="p">)</span> <span class="k">do</span>
    <span class="vi">@guide</span> <span class="o">=</span> <span class="no">Factory</span><span class="p">(</span><span class="ss">:guide</span><span class="p">)</span>
    <span class="no">Guide</span><span class="p">.</span><span class="nf">create_indexes</span>
    <span class="vi">@result</span> <span class="o">=</span> <span class="no">Guide</span><span class="p">.</span><span class="nf">guides_nearby</span><span class="p">(</span><span class="s2">"San Diego,United States"</span><span class="p">)</span>
  <span class="k">end</span>
  <span class="n">it</span> <span class="p">{</span><span class="vi">@result</span><span class="p">.</span><span class="nf">first</span><span class="p">.</span><span class="nf">should</span> <span class="o">==</span> <span class="vi">@guide</span><span class="p">}</span>
<span class="k">end</span>
</code></pre></div></div>
]]></content>
  </entry>
  
</feed>
