Wednesday, December 16, 2009

Passed NREMT-P!


I'm finally done with every certification I need. Seriously the alphabet soup I've taken seemed to never end! Thanks again to everyone who has helped, I wouldn't be here without all of the support.

Friday, December 11, 2009

Code Review Find

double PIE = 3.141592654;
No, that code did not pass the review.

Monday, October 26, 2009

Passed!


I passed the North Carolina EMT-Paramedic exam! It has been three years since I started my journey into EMS, one I would recommend to anyone looking for a rewarding and challenging volunteering field. Thanks to all the folks online who've helped me along the way with Cardiology, I wouldn't have scored 100% on rhythms without you guys.

Update: my certification went active today. So I'm officially a North Carolina EMT-Paramedic.

Monday, September 28, 2009

Long Time no Post

Tuesday marks the end of my initial education as a Paramedic. In preparation I have been studying with books, exam preparations, notes, other students, etc. I will say however, that there is one common thread between the practice exams: bogus questions.

These are questions which make no attempt to assess critical thinking or evaluate knowledge in a certain area, they attempt solely to trick the student. After enough of these trick questions, the student becomes ingrained in finding the catch. Answering the questions becomes a game and not a test of ones knowledge. For instance (not an actual question, just an example):

A patient complaining of cephalgia would most likely:

  1. Have a headache

  2. Have an ear ache

  3. Have clubbed fingers

  4. Be a dick

If you answered, "have a headache," congratulations, you know useless medical trivia and probably have little clinical skills. If you answered, "be a dick," you possess a high degree of critical thinking skills. What patient in the world is going to complain about "cephalgia", unless they're a raging...well, you know what.

If the question asked, "which of the following symptoms would be cause for concern in a patient with an acute onset of hypertension," and "Headache (cephalgia)" was the answer, the question would not only test clinical knowledge, but teach the student a (useless) medical term for a headache. If the answer was given only as cephalgia, then the question would test for nothing.

Update: I passed my paramedic final and will take the North Carolina EMT-Paramedic exam October 23rd. I hope to complete the National Registry testing in November.

Monday, July 13, 2009

Replacing Invalid Characters v. Performance

It appears a large amount of StackOverflow posts focus on eeking out an impossible amount of performance for rather mundane tasks. Sometimes, when you read the question, you can't help but wonder why they even want to improve the performance of the given algorithm. The odds are most performance enhancements would come at the expense of readability. However, that does not mean it isn't worth taking a look at--especially if you're bored and don't want to do something else.

I had some fun with the following question: Most efficient way to remove special characters from string. Just from looking at the specification given, my guess is this is going to get called maybe 100 times at the most. O(f(n)) where n is 100 is boring. Even more interesting is that the given solution from the poster is already quite good (barring a logic error). Here is the OP's solution without any logical errors:

public static string RemoveSpecialCharacters(string str)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.Length; ++i)
{
if ((str[i] >= '0' && str[i] <= '9')
|| (str[i] >= 'A' && str[i] <= 'Z')
|| (str[i] >= 'a' && str[i] <= 'z')
|| (str[i] == '.' || str[i] == '_'))
sb.Append(str[i]);
}
return sb.ToString();
}

As a frequent code reviewer, I think this method looks great. In fact, running this method against a corpus of 10000 randomly generated lines with 4096 characters executes in 0.0479ms/string. This is very fast. The simplest improvement would be to prefill the StringBuilder to str.Length characters. This results in a new runtime of 0.0442ms/string. Now we're cooking with gas!

A few posters suggested regular expressions. Well, the naive approach (uncompiled) takes 0.489ms/string which is 10 times slower. Making the regular expression compiled takes 0.363ms/string, still 8 times slower. However, take a look at the new code you must maintain:

static Regex replacer = new Regex(@"[^a-zA-Z0-9_.]+", RegexOptions.Compiled);
public static string RemoveSpecialCharacters(string str)
{
return replacer.Replace(str, String.Empty);
}

Ok, so a big drop in performance, but perhaps a big gain in readability and maintainability. However, the OP's algorithm is surely very simple to read. So the regular expressions make sense if this method is going to be called a few times on small strings.

Another suggestion was to use foreach rather than a for-loop. This results in another minor speedup to 0.0412ms/string. The last of the improvements suggested was to go with a lookup table. Personally it is my least favorite because it will be less readable and maintainable. C# 3.0 can help us some, using LINQ to improve those.

static bool[] allowedChars = new List<bool>(
from ii in Enumerable.Range(0, 128)
let c = (char)ii
select (c >= '0' && c <= '9')
|| (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c == '.')
|| (c == '_')
).ToArray();

public static string RemoveSpecialCharacters(string str)
{
StringBuilder sb = new StringBuilder(str.Length);
for (int ii = 0; ii < str.Length; ++ii)
{
if (str[ii] < allowedChars.Length && allowedChars[str[ii]])
sb.Append(str[ii]);
}
return sb.ToString();
}

Take a look at how many extra lines of code we have added. This solution may be the fastest so far, at 0.0399ms/string, but it is also bordering on the ugliest. However, we haven't even touched on the simplest improvement that can be made which results in the largest absolute increase in performance. If you replace the StringBuilder with a char[] a 100% speedup can be achieved!

public static string RemoveSpecialCharacters(string str)
{
int idx = 0;
char[] chars = new char[str.Length];
foreach (char c in str)
{
if ((c >= '0' && c <= '9')
|| (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c == '.') || (c == '_'))
{
chars[idx++] = c;
}
}
return new string(chars, 0, idx);
}

This method runs in a blazing 0.0299ms/string, is simple to read, is easy to maintain, and is highly performant. We have a winner folks.

Tuesday, April 7, 2009

Shortness of Breath x 2 days

Age, circumstance, and anything else I feel like has been changed.
This unit was dispatched to a 76yo M C/C SOB x2 days. Pt found seated in chair, w/ patent airway, no obvious respiratory distress, and no apparent life threatening airway. Pt states concern for pneumonia. Pt denies CP. Rhonchi bilateral lower lobes. HR 62, BP 128/70, RR 18, SaO2 97% r/a. Placed on O2 @ 2lpm via NC. SOB gradual w/o pain, worse with exertion, better with rest, "can't catch breath." Pt has no PMD, denies any prior PMD visits, no meds, NKDA. Pt seated fowlers on stretcher, seatbelts secured, taken via stretcher to ambulance. 3-lead monitor shows sinus brady, frequent PVCs, ST elev II/III. 12L ECG shows 2mm ST elev II/III/aVF w/ reciprocal changes I/aVL, ST depression V2-V5. Pt vital signs unchanged, denies CP. Feels "better" w/ O2. 4x 81mg ASA PO. Code STEMI alert given to receiving hospital, no questions. Care transferred to Cath Lab, written and verbal report given to receiving nurse.
We got to watch the cath lab at work:
  • RCA: right marginal artery occlusion
  • LAD: diagonal artery occlusion
  • CX: complete circumflex occlusion
No stents placed, scheduled for CABG.

Tuesday, March 24, 2009

A Difference in Education

You learn interesting things about yourself based on why you miss questions on a test. For instance, on Monday night it became apparent that I have the biochemistry education of a lower order ape. I can speak in big medical terms, but fundamentally my understanding is along the lines of, "air goes in and out, blood goes round and round."

This isn't necessarily a bad thing, my degree is in computer science. So as a programmer, I find that my understanding is based on my rough implementations in code rather than the actual biochemical mechanisms. This is useful in terms of my own understanding, but hardly common ground with other students.

I think I need to take some biochemistry courses so I'm not dragging my knuckles on the floor of the ambulance.

Tuesday, March 3, 2009

Exceptions and Constructors

You should never include any work in a constructor which may leave the object in an inconsistant state. Constructors should be atomic and consistant. You should avoid having side effects in a constructor. However, sometimes you cannot avoid doing additional work in a constructor.

For example, you are designing a stream like class which acquires an unmanaged resource in the constructor. Following RAII, you implement the necessary logic to clean up your unmanaged resource in Dispose and Finalize. Given the following pseudo-code, what is a possible error condition we are not current designed to handle:
public MyType()
{
Check.Invariant(argumentInvariant1);
// ...
Check.Invariant(argumentInvariantN);

// 1. ACQUIRE
this.AcquireUnmanagedResource();

// 2. Set up our base properties from the resource
this.RetrieveConfiguration();
}

~MyType()
{
this.Dispose(false);
}

public void Dispose()
{
this.Dispose(true);
GC.SupressFinalize(this);
}

private void Dispose(bool disposing)
{
if (!this.isDisposed)
{
// RELEASE
this.ReleaseUnmanagedResource();

if (disposing)
{
this.DisposeManagedResources();
}
}
}
What would happen if #2 threw an exception? Well, it is more obvious in this example than in most code in the wild, but our Dispose or Finalize will not be called! Our unmanaged resource will not be released, and we will be leaked.

An appropriate solution would, perhaps, be the following modification to the constructor:
public MyType()
{
Check.Invariant(argumentInvariant1);
// ...
Check.Invariant(argumentInvariantN);

try
{
// 1. ACQUIRE
this.AcquireUnmanagedResource();

// 2. Set up our base properties from the resource
this.RetrieveConfiguration();
}
catch(Exception)
{
// RELEASE
this.Dispose(true);

throw; // propagate the exception
}
}
Now, if #2 should fail we will release the unmanaged resource and not leak anything. Keep in mind this will require a Dispose method which is resistant to an inconsistant object state. However, the design contract for IDisposable basically requires this anyways.

Tuesday, February 17, 2009

Basics and Paramedics

Recently I was asked what the difference was between an EMT-Basic and a Paramedic. It is simple, Basics have the ground beneath their feet, four walls around them, and a roof above their head. More importantly to the Basic, and to their patient, is the door. Behind this door is a Paramedic. A Paramedic who doesn't know if they are on the ground or falling to meet the ground. They really only have the walls they've put up around them. At least at this point, I can't fathom the ceiling for a Paramedic. The responsibilities and expectations are limitless when looking through the door at the Basic.

Monday, February 16, 2009

C# XML Documentation Guide

Today I found what is perhaps the most comprehensive guide to writing good C# XML Documentation. Many thanks to the Dynicity guys for producing this.

Saturday, February 7, 2009

Self-inflicted, unintentional GSW

You can imagine the thought process associated with being dispatched to your first gun shot wound. The narrative has been altered to change specificity and situation.
This unit was dispatched to a 32yo male w/ self-inflicted unintentional GSW x1 to the hand. Additional information from caller while en route informed pt conscious and alert. Dispatch notified LEO, en route. Arrived on scene to find two bystanders in an open field. Pt found sitting in passenger seat of van with ~5cm hole in the front windshield. No gun visible. LEO arrived ~2 min after EMS, secured .40cal handgun. Pt states he reached for the handgun on the floorboard of the van and it went off accidentally. Pt had a patent airway, no respiratory distress, and displayed his L hand which had no apparent active bleeding. Rapid trauma exam revealed no life threatening injuries. <5cc blood estimated lost. L hand had ~1cm entrance wound on anterior palmar aspect ~3cm from medial border and ~2cm from wrist. ~1cm exit wound on medial border ~3cm from entrance and ~4cm from wrist. Powder burns noted at entrance wound. Skin warm/dry, pupils sluggish, pulse fast/bounding. Pt refused further physical examination. Wound irrigated with sterile water, bandaged, wrapped with gauze. Pt refused further treatment. Pt refused transport. Pt advised of treatment/transport options and injury severity. Pt signed refusal. LEO witnessed refusal.

Sunday, January 18, 2009

Paramedic Clinicals

So Friday was the first of many clinical shifts (500 hours total) I will be doing as a Paramedic student. My patients ranged in age from 11 to 92, with problems ranging from fractures to overdoses to a suspected DVT. I triaged patients, assessed vitals, started IV's, pushed medications, wiped asses, and did everything else I could find to do.

One aspect of our clinical time is a state requirement that we accomplish a given number of procedures. This is both a good and a bad thing. You want your certified Paramedics to be useful when they get their card. You also want your new Paramedics to be more than just some monkey starting your IV. But when you take those requirements and add to it a finite amount of patients and a finite amount of clinical time, an obvious problem is created. Any economist will tell you that the students will apply game theory to patient care, asking the question, "what interventions can I use," rather than, "what interventions, if any, are appropriate".

More players enter the game when you show your preceptor the clinical guidelines which include these requirements. Suddenly, you have a proxy, rummaging through charts looking for flags indicating a required intervention! This isn't necessarily a bad thing, I obviously need to be competent at starting IV's, administering medication, birthing children, et cetera. I just should not be particularly concerned about only having 500 hours to accomplish X number of IV starts, Y medication administrations, Z child births, et cetera ad nauseam.

The state clinical requirements should make the student more concerned with the academic approach, starting with patient assessment and ending with a clear and organized treatment plan. It shouldn't matter if I'm the one providing any required interventions, just that I'm able to provide any appropriate intervention when required.

So you can see why I'd find it funny that my first IV stick as a medic student was a heavily tattooed habitual IV drug user requiring cardiac blood labs. He was nearly devoid of useful veins and definately required blood drawn. A disgustingly green paramedic student tends to fall towards the bottom of the list of people you'd like performing this procedure. But not being one to avoid a challenge, I tried to follow some scar tissue to what felt like a vein, but my angle of attack was too high and I nicked and rolled it.

Swiiing and a miss.

Even with a little extra traction and some fancy needle movement I couldn't establish a patent line. The patient wisely asked that the nurse try the next stick, due to that being the only vein we could find sans a vein running along his thumb. I'm sure the fact that my shirt said EMS Intern on it played no small role in his decision to ask that somebody else make the try.

My mind is still debating if there was more learned attempting his IV or reading his ECG.