Jekyll2022-07-01T05:40:22+00:00https://pezra.me/feed.xmlPeter WilliamsWhat could possibility go wrong?South America - Santiago (and Atlanta)2022-05-30T04:00:00+00:002022-05-30T04:00:00+00:00https://pezra.me/blog/2022/south-america-santiago-and-atlanta<p>I was booked to fly from Denver to Santiago with a short layover in Atlanta. However, my flight from Denver was slightly delayed so i miss the Santiago leg and had to spend 24 hours in Atlanta (there is only one flight to Santiago per day). This turned out to be really nice. I took the opportunity to visit the <a href="https://en.wikipedia.org/wiki/Martin_Luther_King_Jr._National_Historical_Park">Martin Luther King Jr National Historical Park</a>. It was a Sunday so the museum, etc were closed but it is a interesting neighborhood to walk around.</p>
<p><img src="/photos/PXL_20220529_151614099.jpg" alt="visitor center through trees" /></p>
<p><img src="/photos/PXL_20220529_154003598.MP.jpg" alt="cool looking church" /></p>
<p>After that i headed to the nearby <a href="https://piedmontpark.org">Piedmont Park</a>. There was a Jazz festival happening so I lazed about the park listening to <a href="https://www.joealtermanmusic.com">Joe Alterman</a> and some other artists that escape my memory until it was time to head the airport. All in all it was a great way to spend an unexpected visit to Atlanta.</p>
<p><img src="/photos/PXL_20220529_160953610.jpg" alt="downtown Atlanta over pond" /></p>
<p>Then i was on to Santiago. My flight arrived early the next morning so i connected with Joshua and Sophia and we started exploring Santiago starting with the Plaza de Armas.</p>
<p><img src="/photos/PXL_20220530_171421524.MP.jpg" alt="the crew for this adventure" />
<img src="/photos/PXL_20220530_171452144.jpg" alt="" /></p>
<p>Santiago is covered in beautiful street art which makes wandering around a real treat.</p>
<p><img src="/photos/PXL_20220530_180346842.jpg" alt="mural and tree lined street" /></p>
<p>We ended the day watching a beautiful sunset from <a href="https://en.wikipedia.org/wiki/San_Cristóbal_Hill">San Cristóbal Hill</a>.</p>
<p><img src="/photos/PXL_20220530_212730504.jpg" alt="sunset over Santiago Chile" /></p>
<p>Tomorrow we are off to explore other parts of Chile.</p>Peter WilliamsI was booked to fly from Denver to Santiago with a short layover in Atlanta. However, my flight from Denver was slightly delayed so i miss the Santiago leg and had to spend 24 hours in Atlanta (there is only one flight to Santiago per day). This turned out to be really nice. I took the opportunity to visit the Martin Luther King Jr National Historical Park. It was a Sunday so the museum, etc were closed but it is a interesting neighborhood to walk around.15902019-01-06T06:59:18+00:002019-01-06T06:59:18+00:00https://pezra.me/blog/2019/01/1590<p style="text-align: left;">
Esra and I at Neon Masquerade. The bands were awesome and black lights are always fun!
</p>
<p><img src="/wp-content/uploads/2019/01/MVIMG_20190105_192510.jpg" /></p>Peter WilliamsEsra and I at Neon Masquerade. The bands were awesome and black lights are always fun!Why i don’t love schemas2018-09-21T03:05:35+00:002018-09-21T03:05:35+00:00https://pezra.me/blog/2018/09/why-i-dont-love-schemas<p>Once, long ago, i thought that schemas were great and that they could provide much value. Schemas hold the promise of declaratively and unambiguously defining message formats. Many improvements would be “easy” once such a definition was available. Automated low-code validations, automagically created high quality, verifiably correct documentation, clearer understanding of inputs, etc. I tried fiercely to create good schemas, using ever better schema languages (<a href="http://www.relaxng.org/compact-tutorial-20030326.html">RelaxNG compact syntax</a>, anyone) and ever more “sophisticated” tools to capture the potential benefits schemas.</p>
<p>At every turn i found the returns on investment disappointing. Schema languages are hard for humans to write and even harder to interpret. They are usually unable to express many real world constraints (you can only have that radio with this trim package, you can only have that engine if you not in California, etc). High quality documentation is super hard even with a schema. Generation from schema solves the easy part of documentation, explaining why the reader should care is the hard part. Optimizing a non-dominate factor in a process doesn’t actually move the needle all that much. Automated low-code validations often turned out hamper evolution far more than they caught real errors.</p>
<p>I wasn’t alone in my disappointment. The whole industry noticed that XML, with its schemas and general complexity was holding us back. Schemas ossified API clients and servers to the point that evolving systems was challenging, bordering on impossible. Understanding the implications of all the code generated from schemas was unrealistic for mere mortals. Schema became so complex that it was impossible to generate human interpretable documentation from them. Instead people just passed around megs of XSD files and call it “documentation”.</p>
<p>JSON emerged primarily as a reaction to the complexity of XML. However, XML didn’t start out complex, it accreted the complexity over time. Unsurprising the cycle is repeating. JSON schema is a thing and seems to be gaining popularity. It is probably a fools errand to try steming the tide but i’m going to try anyway.</p>
<p><img src="https://pbs.twimg.com/media/DdhLJQJWkAEf4Qr.jpg" alt="doomed to watch everyone else repeat history" /></p>
<p>What would it take for schemas to be net positive? Only a couple of really hard things.</p>
<h2 id="humans_first">Humans first</h2>
<p>Schema languages should be human readable first, and computer readable second. Modern parser generators make purpose built languages easy to implement. A human centered language turns schemas from something that is only understandable by an anointed few into a powerful, empowering tool for the entire industry. RelaxNG concise syntax (linked above) is a good place to look for inspiration. The XML community never adopted a human readable syntax and it contributed to the ultimate failure of XML as a technology. Hopefully we in the JSON community can do better.</p>
<h2 id="avoid_the_one_true_schema_cul_de_sac">Avoid the One True Schema cul de sac</h2>
<p>This one is more of a cultural and education issue than technical one. This principle hinges on two realizations</p>
<ol>
<li>A message is <strong>only</strong> valuable if at least one consumer can achieve some goal with that message.</li>
<li>Consumers want to maximize the number goals achieved</li>
</ol>
<p>However, consumers don’t necessarily have the same goals as each other. In fact, any two consumers are likely to have highly divergent goals. Therefore, they are likely to have highly divergent needs in messages. A message with which one consumer can achieve a goal may be useless to another. Therefore, designing a schema to be used by more than consumer is an infinite-variable optimization problem. Your task is to minimize the difference between the set of valid messages and the set of actually processable messages for <em>every possible</em> consumer! (<a href="#appendix-a">See appendix A for more details</a>) A losing proposition if there ever was one.</p>
<p>To mitigate this schema languages should provide first class support for “personalizing” existing schemas. A consumer should able to a) declare that it only cares about some subset of the properties defined in a producer’s schema and b) that it will accept and use properties not declared in a producer’s schema. This would allow consumers to finely tune their individual schemas to their specific needs. This would improve evolvability by reducing incidental coupling, increase the clarity of documentation by hiding all irrelevant parts of the producer’s schema, and improve automated validation by ignoring irrelevant parts of messages.</p>
<p>We as a community should also educate people in the dangers of The One True Schema pattern.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Designing schemas for humans and avoiding the One True Schema are both really hard. And, unfortunately, i doubt our ability to reach consensus and execute on them. Given that i think most message producers and basically all message consumers are better avoiding schemas for anything other than documents.</p>
<hr />
<h3 id="appendix_a_where_in_i_get_sorta_mathy_about_why_consumers_shouldnt_share_schemas_unless_they_have_the_same_goals">Appendix A: Where in i get sorta mathy about why consumers shouldn’t share schemas unless they have the same goals</h3>
<p>I don’t know if this will help other people but it did help me clarify my thinking on this issue.</p>
<p>A particular consumer, C, needs messages to contain certain information to achieve its goal.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>m = set of all messages
mC = {m | m in M, m contains info needed by consumer C}
</code></pre></div></div>
<p>For any particular schema there is some subset of all messages that are valid.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mV = {m | m in M, m is valid against schema S}
</code></pre></div></div>
<p>As the schema approaches perfection for consumer C the set of valid messages approaches the set of messages actually processable by the consumer.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mC = lim mV as S->perfectSchemaFor(C)
</code></pre></div></div>
<p>In practice, however, there is always some mis-match between the set of valid messages and the set of messages actually processable by the consumer. Some technically invalid messages contain enough information for the consumer to achieve its goal. Some technically valid messages will contain insufficient information. The mis-match may be due to bugs, a lack of expressiveness in the schema language or just poor design. The job of a schema designer is to minimize the mis-match.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mC ≠ mV
mC ⊄ mV
mC ⊅ mV
</code></pre></div></div>
<p>Now consider a second consumer of these messages.</p>
<p>A particular consumer, D, needs messages to contain certain information to achieve its goal.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mD = {m | m in M, m contains info needed by consumer D}
</code></pre></div></div>
<p>The information needed by consumer D will, in general, be different from the information needed by consumer C. Therefore, the set of messages processable by C will, in general, not equal the set of messages processable by D.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mC ≠ mD (in general)
</code></pre></div></div>
<p>The kicker: the perfect schema for consumer C is, in general, different from the perfect schema any other consumer. Minimizing the difference between <code class="language-plaintext highlighter-rouge">mV</code> and <code class="language-plaintext highlighter-rouge">mC</code> will tend to increase the difference between <code class="language-plaintext highlighter-rouge">mV</code> and <code class="language-plaintext highlighter-rouge">mD</code>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>perfectSchemaFor(C) ≠ perfectSchemaFor(D)
</code></pre></div></div>Peter WilliamsOnce, long ago, i thought that schemas were great and that they could provide much value. Schemas hold the promise of declaratively and unambiguously defining message formats. Many improvements would be “easy” once such a definition was available. Automated low-code validations, automagically created high quality, verifiably correct documentation, clearer understanding of inputs, etc. I tried fiercely to create good schemas, using ever better schema languages (RelaxNG compact syntax, anyone) and ever more “sophisticated” tools to capture the potential benefits schemas.supervisor child startup in elixir2018-04-26T00:29:20+00:002018-04-26T00:29:20+00:00https://pezra.me/blog/2018/04/supervisor-child-startup-in-elixir<p>Fact: <a href="https://hexdocs.pm/elixir/Supervisor.html#module-start_link-2-init-2-and-strategies">Supervisors</a> <strong>fully</strong> serialize the startup of their children. Each child’s <code class="language-plaintext highlighter-rouge">init/1</code> function runs to completion before the supervisor starts the next child.</p>
<p>For example, given modules <code class="language-plaintext highlighter-rouge">ModuleA</code> and <code class="language-plaintext highlighter-rouge">ModuleB</code> that implement both the <code class="language-plaintext highlighter-rouge">init/1</code> callback and this supervisor:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Supervisor.start_link([
ModuleA,
ModuleB
], strategy: :one_for_one)
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">ModuleA</code> child process will be started and its <code class="language-plaintext highlighter-rouge">init/1</code> function will run to completion before the <code class="language-plaintext highlighter-rouge">ModuleB</code> child process starts. This is true regardless of the strategy used.</p>
<h2 id="so_what">so what?</h2>
<p>This fact can often simplify application startup and error handling scenarios. For example, consider a situation where several processes need a token to interact with an API. The application must acquire this token on startup. If the token expires or the server revokes the token the application must acquire a brand new token and distribute it to all the processes.</p>
<p>We can implement that behavior simply and easily using serialization and appropriate crash handling strategy of a supervisor.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>defmodule MyApi.TokenManager do
use GenServer
def init(_) do
token = fetch_token_from_api!()
{:ok, token}
end
def handle_call(:get_token, _from, token) do
{:reply, token, token}
end
end
defmodule MyApi.ThingDoer do
use GenServer
def handle_call(:do_thing, _from, _state) do
token = MyApi.TokenManager.get_token()
# do stuff with token; crash if it doesn't work
en
end
defmodule MyApi.OtherThingDoer do
use GenServer
def handle_call(:do_other_thing, _from, _state) do
token = MyApi.TokenManager.get_token()
# do stuff with token; crash if it doesn't work
en
end
Supervisor.start_link([
MyApi.TokenManager,
MyApi.ThingDoer,
MyApi.OtherThingDoer
], strategy: :one_for_all)
</code></pre></div></div>
<p>In this example <code class="language-plaintext highlighter-rouge">MyApi.TokenManager.init/1</code> acquires the token before returning. That means the token is ready by the time <code class="language-plaintext highlighter-rouge">MyApi.ThingDoer</code> and <code class="language-plaintext highlighter-rouge">MyApi.OtherThingDoer</code> start. If at any point to the API server revokes the token, or it expires, the next thing doer to try to use it can just crash. That crash will cause the supervisor to shutdown the remaining children and restart them all beginning with <code class="language-plaintext highlighter-rouge">MyApi.TokenManager</code> which will acquire a new, working token.</p>
<p>With this approach <code class="language-plaintext highlighter-rouge">MyApi.ThingDoer</code> and <code class="language-plaintext highlighter-rouge">MyApi.OtherThingDoer</code> don’t need any specific error handling code around token management. The removal of situation-specific error handling logic makes them simpler and more reliable.</p>Peter WilliamsFact: Supervisors fully serialize the startup of their children. Each child’s init/1 function runs to completion before the supervisor starts the next child.hypermedia format manifesto2018-03-29T18:05:40+00:002018-03-29T18:05:40+00:00https://pezra.me/blog/2018/03/hypermedia-format-manifesto<p>Through my work developing and consuming APIs i have come to value:</p>
<ul>
<li><strong>evolvability</strong> over message and implementation simplicity</li>
<li><strong>self describing messages</strong> over reduced message sizes</li>
<li><strong>standards</strong> over bespoke solutions</li>
<li><strong>human readability</strong> over client simplicity</li>
<li><strong>uniformity</strong> over flexibility</li>
</ul>
<p>I value the things on the right, but i value the things on the left more.</p>
<h3 id="evolvability_over_message_and_implementation_simplicity">evolvability over message and implementation simplicity</h3>
<p>APIs and the producers and consumers of APIs must be able to evolve over time. Evolvability inherently means that the message and implementations will be more complex. Designers and implementers must have forward compatibility in mind at all times. This forward compatibility mindset produces features that add value only after months, years or even decades of life. Having those features is more complex than not, but the return on those investments is worth the cost.</p>
<h3 id="self_describing_messages_over_reduced_message_sizes">self describing messages over reduced message sizes</h3>
<p>Embedding all the information needed to interpret a message simplifies client implementation and improves evolvability. However, embedding all that information necessarily increase the size of the message. For most APIs the additional data transfer is just not important enough to give up the benefits of self-describing messages.</p>
<h3 id="standards_over_bespoke_solutions">standards over bespoke solutions</h3>
<p>Standards allow reuse of code and of knowledge. Standards often encode hard-won practical experience about what works and what doesn’t. However, standard solutions often don’t fit as well as purpose-designed solutions to specific problems.</p>
<h3 id="human_readability_over_client_simplicity">human readability over client simplicity</h3>
<p>It is important that APIs be understandable by mere mortals. An average developer should be able to easily understand and explore an API without specialized tools. Achieving human readability while also honoring the other values often means that clients must become more complicated.</p>
<h3 id="uniformity_over_flexibility">uniformity over flexibility</h3>
<p>There should be a small number of ways to express a particular message. This makes consumer and producer implementations simpler. However, this means that existing APIs will likely be non-conformant. It also means that some messages will be less intuitive and human readable.</p>
<h2 id="why_now">why now</h2>
<p>There has been a fair bit of discussion in <a href="https://httpapis.slack.com/messages/C1JQJUF2T">HTTP APIs hypermedia channel</a> (<a href="http://slack.httpapis.com/">get an invite</a>) lately about hypermedia formats (particularly those of the JSON variety). Personally, i find all of the existing options wanting. I’m not sure the world needs yet another JSON based hypermedia format but the discussion did prompt me to try to articulate what i value in a format. The format is blatantly stolen from <a href="http://agilemanifesto.org/">the agile manifesto</a>.</p>Peter WilliamsThrough my work developing and consuming APIs i have come to value:How i judge software engineers2018-03-13T04:32:32+00:002018-03-13T04:32:32+00:00https://pezra.me/blog/2018/03/how-i-judge-software-engineers<p>My kid’s teachers routinely provide rubrics for assignments. At first blush, rubrics are tools to make grading an assessment easier. They are effective in that role. They turn out to be at least as effective at communicating expectations. Readers of a rubric can quickly and easily determine what is important.</p>
<p>Recently i developed a rubric to help me judge the performance of engineers (it was review season yet again). The engineers on my team have appreciated the transparency and clarity this tool provides. Hopefully, it will be helpful to others.</p>
<p>The Rubric is divided into two sections. One about results and the other about behavior. Both of these are important. Good, pro-social behavior is just as important in engineers as strong results.</p>
<h3 id="results">Results</h3>
<table style="font-size: 80%;">
<tr>
<th colspan="1" rowspan="1">
</th>
<th colspan="1" rowspan="1">
3
</th>
<th colspan="1" rowspan="1">
2
</th>
<th colspan="1" rowspan="1">
1
</th>
<th colspan="1" rowspan="1">
</th>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Continuous improvement
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
always leaves code substantially better than they found it
</li>
<li>
manages scope of refactors to match time available
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
often improves code as part of normal work
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
sometimes improves code as part of normal work
</li>
<li>
often has to abandon refactors due to time constraints
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
rarely improves existing code
</li>
</ul>
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Communication
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
communicates intentions early and clearly
</li>
<li>
often provides material support to teammates (developers, QA, on-call person, etc)
</li>
<li>
regularly creates & maintains runbook (particularly when on call)
</li>
<li>
keeps stakeholder informed (particularly when on call)
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
communicates intentions after it is hard to change course
</li>
<li>
regularly supports teammates
</li>
<li>
occasionally maintains runbook
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
rarely communicates intentions
</li>
<li>
sometimes supports teammates
</li>
<li>
doesn’t maintain runbook
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
never communicates intentions
</li>
<li>
never supports teammates
</li>
<li>
never creates or improves runbook entries
</li>
</ul>
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Production support
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
prioritizes concurrent incidents correctly
</li>
<li>
use critical thinking and problem-solving skills to resolve issues quickly
</li>
<li>
handles lower priority issues (eg, jenkins nodes down) when there are no higher priority incidents
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
prioritizes concurrent incidents correctly
</li>
<li>
use critical thinking and problem solving skills to resolve issues
</li>
<li>
handles lower priority issues (eg, jenkins nodes down) when there are no higher priority incidents
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
prioritizes concurrent incidents correctly
</li>
<li>
ignores lower priority issues (eg, jenkins nodes down) even when there are no high priority incidents (works stories while on call)
</li>
<li>
relies too heavily on others (rather than using critical thinking and problem-solving skills)
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
bad attitude
</li>
<li>
incorrectly prioritizes concurrent incidents
</li>
<li>
always ignores lower priority issues (jenkins nodes down)
</li>
<li>
doesn’t communicate incident status to stakeholders
</li>
<li>
relies on others to resolve issues (throws it over the wall)
</li>
</ul>
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Code Quality
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
functional
</li>
<li>
well factored
</li>
<li>
documentation on classes/modules and public method/functions
</li>
<li>
PRs require trivial changes
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
functional
</li>
<li>
well factored
</li>
<li>
poorly documented
</li>
<li>
PRs require minor changes
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
functional
</li>
<li>
poorly factored
</li>
<li>
undocumented
</li>
<li>
PRs require some rework
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
buggy
</li>
<li>
poorly factored
</li>
<li>
undocumented
</li>
<li>
PRs require substantial rework
</li>
</ul>
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Productivity
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
usually delivers more stories per sprint than the average engineer
</li>
<li>
usually delivers more points per sprint than the average engineer
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
occasionally delivers more stories/points per sprint than the average engineer
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
usually delivers fewer stories/points per sprint than the average engineer
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
delivers substantially fewer stories/points per sprint than the average engineer
</li>
</ul>
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Testing
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
public contracts well tested
</li>
<li>
key scenarios have acceptance tests
</li>
<li>
tests are independent of current implementation
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
public contract partially tested
</li>
<li>
key scenarios have acceptance tests
</li>
<li>
tests are independent or current implementation
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
public contract partially tested
</li>
<li>
tests dependent on current implementation
</li>
<li>
acceptance tests check too many edge cases
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
no unit or functional tests
</li>
</ul>
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Feedback
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
often reviews PRs
</li>
<li>
feedback is substantive and useful
</li>
<li>
reviews show understanding of PRs intent and the code that interacts with it
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
regularly reviews PRs
</li>
<li>
advice would materially improve PRs
</li>
<li>
reviews show understanding of PRs intent
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
sometimes reviews PRs
</li>
<li>
reviews are superficial
</li>
<li>
reviews are hard to understand
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
never reviews PRs
</li>
</ul>
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Product & domain knowledge
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
understands the domain
</li>
<li>
understands most of the supported features of the product
</li>
<li>
understands some of the historical features of the product
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
understands the domain
</li>
<li>
understands many of the supported features of the product
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
some knowledge of the domains
</li>
<li>
limited knowledge of product features
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
no knowledge of utility and grid edge domain
</li>
<li>
no knowledge of product
</li>
</ul>
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Personal goals
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
goals are SMART
</li>
<li>
goals drive achievement of team and corporate goals in material ways
</li>
<li>
achieves goals on time
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
goals are SMART
</li>
<li>
goals weakly support team and corporate goals
</li>
<li>
achieves goals
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
goals have no relation to team and corporate goals
</li>
<li>
achieves goals
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
goals are vague or unattainable
</li>
<li>
goals work against team and corporate goals
</li>
<li>
doesn’t achieve goals
</li>
</ul>
</td>
</tr>
</table>
<h3 id="behavior">Behavior</h3>
<table style="font-size: 80%;">
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Attitude
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
polite and engaging even when under stress (eg, when on call)
</li>
<li>
accepts setbacks and moves forward
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
normally polite but brusque when under stress
</li>
<li>
accepts setbacks and moves forward
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
normally polite but rude when under stress
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
rude
</li>
<li>
dismissive
</li>
</ul>
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Courage
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
courageous in all aspects of work every day
</li>
<li>
strives for greatness even when difficult
</li>
<li>
occasionally fails spectacularly
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
often courageous in most aspects of work
</li>
<li>
occasionally fails
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
sometimes courageous in some aspects of work
</li>
<li>
rarely fails
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
often timid
</li>
<li>
usually takes least risky (and rewarding) approach
</li>
</ul>
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Motivation
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
highly motivated to succeed
</li>
<li>
accepts challenges and new responsibilities
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
motivated to succeed
</li>
<li>
grudgingly accepts new challenges and responsibilities
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
resists new challenges and responsibilities
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
lacks motivation
</li>
<li>
rejects all new challenges and responsibilities
</li>
</ul>
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Strategic thinking
</th>
<td colspan="1" rowspan="1">
plans for 6 month – 2 year horizon
</td>
<td colspan="1" rowspan="1">
plans for 3 – 6 month horizon
</td>
<td colspan="1" rowspan="1">
plans for 1 – 3 month horizon
</td>
<td colspan="1" rowspan="1">
no planning
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Trustworthiness
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
earns trust of others
</li>
<li>
reliably meets commitments
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
honest
</li>
<li>
occasionally fails to meet commitments
</li>
<li>
sometimes fails to gain the trust of others
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
fails to meet commitments
</li>
<li>
occasionally misconstrues the facts
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
often misconstrues the facts
</li>
<li>
widely distrusted
</li>
</ul>
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Learning
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
seeks out learning opportunities
</li>
<li>
applies lessons learn to enhance success
</li>
<li>
elicits relevant experiences from others
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
interested in learning
</li>
<li>
applies lessons learn to enhance success
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
learns when pushed
</li>
<li>
resists change
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
uninterested in learning
</li>
<li>
resists change
</li>
</ul>
</td>
</tr>
<tr>
<th style="white-space: unset;" colspan="1" rowspan="1">
Pairing*
</th>
<td colspan="1" rowspan="1">
<ul>
<li>
improves productivity and morale of pairs
</li>
<li>
pairs most of the time
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
pairs effectively
</li>
<li>
pairs most of the time
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
pairs ineffectively
</li>
<li>
pairs some of the time
</li>
</ul>
</td>
<td colspan="1" rowspan="1">
<ul>
<li>
reduces productivity and morale of pairs
</li>
<li>
rarely pairs
</li>
</ul>
</td>
</tr>
</table>
<ul>
<li>Optional. If your team pairs at a matter of course this is <strong>very</strong> important. If your team works as individuals then ignore this row.</li>
</ul>Peter WilliamsMy kid’s teachers routinely provide rubrics for assignments. At first blush, rubrics are tools to make grading an assessment easier. They are effective in that role. They turn out to be at least as effective at communicating expectations. Readers of a rubric can quickly and easily determine what is important.15382018-03-11T18:04:19+00:002018-03-11T18:04:19+00:00https://pezra.me/blog/2018/03/1538<p>Skiing a beautiful spring day at Loveland ski area.</p>
<p><img loading="lazy" class="wp-image-1537 alignnone size-full" src="https://barelyenough.org/wordpress/wp-content/uploads/2018/03/img_20180311_0953456327057713772973280.jpg" width="3000" height="2250" srcset="https://barelyenough.org/wordpress/wp-content/uploads/2018/03/img_20180311_0953456327057713772973280.jpg 3000w, https://barelyenough.org/wordpress/wp-content/uploads/2018/03/img_20180311_0953456327057713772973280-150x113.jpg 150w, https://barelyenough.org/wordpress/wp-content/uploads/2018/03/img_20180311_0953456327057713772973280-300x225.jpg 300w, https://barelyenough.org/wordpress/wp-content/uploads/2018/03/img_20180311_0953456327057713772973280-768x576.jpg 768w, https://barelyenough.org/wordpress/wp-content/uploads/2018/03/img_20180311_0953456327057713772973280-600x450.jpg 600w, https://barelyenough.org/wordpress/wp-content/uploads/2018/03/img_20180311_0953456327057713772973280-700x525.jpg 700w" sizes="(max-width: 3000px) 100vw, 3000px" /></p>Peter WilliamsSkiing a beautiful spring day at Loveland ski area.Eclipse 20172017-08-21T20:00:26+00:002017-08-21T20:00:26+00:00https://pezra.me/blog/2017/08/eclipse-2017<p><img loading="lazy" width="2560" height="1440" alt="" src="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124025105.jpg" title="" class="size-full wp-image-1525" srcset="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124025105.jpg 2560w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124025105-150x84.jpg 150w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124025105-300x169.jpg 300w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124025105-768x432.jpg 768w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124025105-600x338.jpg 600w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124025105-700x394.jpg 700w" sizes="(max-width: 2560px) 100vw, 2560px" />10 minutes to totality</p>
<p><a href="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125452786.jpg"><img loading="lazy" width="2560" height="1440" alt="" src="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125452786.jpg" title="" class="size-full wp-image-1526" srcset="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125452786.jpg 2560w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125452786-150x84.jpg 150w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125452786-300x169.jpg 300w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125452786-768x432.jpg 768w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125452786-600x338.jpg 600w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125452786-700x394.jpg 700w" sizes="(max-width: 2560px) 100vw, 2560px" /></a>Sunset at 12:56</p>
<p><a href="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125706575.jpg"><img loading="lazy" width="2560" height="1440" alt="" src="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125706575.jpg?retry=7" title="" class="size-full wp-image-1527" srcset="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125706575.jpg 2560w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125706575-150x84.jpg 150w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125706575-300x169.jpg 300w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125706575-768x432.jpg 768w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125706575-600x338.jpg 600w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_125706575-700x394.jpg 700w" sizes="(max-width: 2560px) 100vw, 2560px" /></a>And the light is back</p>
<p><a href="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_120108862.jpg"><img loading="lazy" width="4160" height="2340" src="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_120108862.jpg" alt="" class="wp-image-1530 alignnone size-full" srcset="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_120108862.jpg 4160w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_120108862-150x84.jpg 150w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_120108862-300x169.jpg 300w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_120108862-768x432.jpg 768w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_120108862-600x338.jpg 600w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_120108862-700x394.jpg 700w" sizes="(max-width: 4160px) 100vw, 4160px" /></a><a href="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124321798.jpg"><img loading="lazy" width="2340" height="4160" src="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124321798.jpg" alt="" class="wp-image-1531 alignnone size-full" srcset="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124321798.jpg 2340w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124321798-84x150.jpg 84w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124321798-169x300.jpg 169w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124321798-768x1365.jpg 768w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124321798-576x1024.jpg 576w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170821_124321798-700x1244.jpg 700w" sizes="(max-width: 2340px) 100vw, 2340px" /></a></p>Peter Williams10 minutes to totality15232017-08-20T22:30:08+00:002017-08-20T22:30:08+00:00https://pezra.me/blog/2017/08/1523<p>Sometimes Audrey is still just a kid playing at the park.</p>
<p><a href="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_175504160.jpg"><img loading="lazy" width="2340" height="4160" src="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_175504160.jpg" alt="" class="wp-image-1522 alignnone size-full" srcset="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_175504160.jpg 2340w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_175504160-84x150.jpg 84w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_175504160-169x300.jpg 169w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_175504160-768x1365.jpg 768w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_175504160-576x1024.jpg 576w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_175504160-700x1244.jpg 700w" sizes="(max-width: 2340px) 100vw, 2340px" /></a></p>Peter WilliamsSometimes Audrey is still just a kid playing at the park.15202017-08-20T19:58:48+00:002017-08-20T19:58:48+00:00https://pezra.me/blog/2017/08/1520<p>Doing our touristly duty (Great Platte River Road Archway Monument) while waiting on the eclipse. </p>
<p><a href="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_135221478.jpg"><img loading="lazy" width="1440" height="2560" src="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_135221478.jpg" alt="" class="wp-image-1519 alignnone size-full" srcset="https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_135221478.jpg 1440w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_135221478-84x150.jpg 84w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_135221478-169x300.jpg 169w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_135221478-768x1365.jpg 768w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_135221478-576x1024.jpg 576w, https://barelyenough.org/wordpress/wp-content/uploads/2017/08/IMG_20170820_135221478-700x1244.jpg 700w" sizes="(max-width: 1440px) 100vw, 1440px" /></a></p>Peter WilliamsDoing our touristly duty (Great Platte River Road Archway Monument) while waiting on the eclipse.