<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet href="/templates/default/atom.css" type="text/css" ?>

<feed version="0.3" 
   xmlns="http://purl.org/atom/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:admin="http://webns.net/mvcb/"
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
   xmlns:wfw="http://wellformedweb.org/CommentAPI/">
    <link href="http://blog.fugue88.ws/rss.php?version=atom0.3" rel="service.feed" title="David Owen’s blog" type="application/x.atom+xml" />
    <link href="http://blog.fugue88.ws/"                        rel="alternate"    title="David Owen’s blog" type="text/html" />
    <link href="http://blog.fugue88.ws/rss.php?version=2.0"     rel="alternate"    title="David Owen’s blog" type="application/rss+xml" />
    <title mode="escaped" type="text/html">David Owen’s blog</title>
    <tagline mode="escaped" type="text/html">Forward motion</tagline>
    <id>http://blog.fugue88.ws/</id>
    <modified>2012-10-23T21:52:11Z</modified>
    <generator url="http://www.s9y.org/" version="1.5.2">Serendipity 1.5.2 - http://www.s9y.org/</generator>
    <dc:language>en</dc:language>
    <info mode="xml" type="text/html">
        <div xmlns="http://www.w3.org/1999/xhtml">You are viewing an ATOM formatted XML site feed. Usually this file is inteded to be viewed in an aggregator or syndication software. If you want to know more about ATOM, please visist <a href="http://atomenabled.org/">Atomenabled.org</a></div>
    </info>

    <entry>
        <link href="http://blog.fugue88.ws/archives/2012-10/Lessons-from-application-development-with-databases" rel="alternate" title="Lessons from application development with databases" type="text/html" />
        <author>
            <name>David Owen</name>
                    </author>
    
        <issued>2012-10-19T21:24:11Z</issued>
        <created>2012-10-19T21:24:11Z</created>
        <modified>2012-10-23T21:52:11Z</modified>
        <wfw:comment>http://blog.fugue88.ws/wfwcomment.php?cid=16</wfw:comment>
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://blog.fugue88.ws/rss.php?version=atom0.3&amp;type=comments&amp;cid=16</wfw:commentRss>
    
        <id>http://blog.fugue88.ws/archives/2012-10/16</id>
        <title mode="escaped" type="text/html">Lessons from application development with databases</title>
        <content type="application/xhtml+xml" xml:base="http://blog.fugue88.ws/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>I recently finished up the main development effort of a new project.  It incorporates a lot of database techniques I'd used in previous projects, and several that I hadn't.</p>

<h5>Description</h5>

<p>The application is written in <a href="https://www.djangoproject.com/">Django</a>, but uses <a href="http://www.sqlalchemy.org/">SQLAlchemy</a> to the nearly complete exclusion of Django's own ORM.  The only thing that touches Django's ORM is the session module.</p>

<p>The view-handling functions perform first-level security checks, input scrubbing and coercion from strings to other types, and reporting errors to the user.  These functions then call into logic functions, which perform most of the interaction with the database.  Database interactions use SQLAlchemy as basically a wrapper over the DBAPI, using strings for queries and passing parameters positionally.</p>

<p>The database is <a href="http://www.postgresql.org/">PostgreSQL</a> (which has an excellent set of features).  Database views and database functions do all the heavy lifting; the logic functions themselves mostly use their own parameters to filter or sort view results (at the database), do a simple join or two, or perform data updates.  The views do a <em>lot</em> of aggregation, including statistics, modeling, and forecasts; much of the aggregation uses <a href="http://www.postgresql.org/docs/9.1/interactive/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS">window functions</a>.</p>

<p>A migration system handles all schema updates, which include: data structure (CREATE/ALTER/DROP TABLE), data (UPDATE), views (CREATE/DROP VIEW), functions (CREATE/DROP FUNCTION), and grants (GRANT/REVOKE).</p>

<p>Migrations are managed by a small set of simple bash scripts called <a href="http://trac.fugue88.ws/pg-migrate">pg-migrate</a>.  Migrations have a single total order, with individual migrations identified by contiguous positive ordinals.  A migration script is a single SQL file, named with its ordinal, a hyphen, and some brief descriptive text allowed in filenames, and a <code>.sql</code> extension.  The bash scripts automatically wrap individual migrations in transaction blocks during execution.</p>

<h5>What went well</h5>

<p>Using database views is a huge win for abstraction.</p>

<p>Views are the first level of named abstraction for queries, like functions are for code in general-purpose languages.  By giving names to parts of complicated queries, they become much easier to understand.</p>

<p>It's very easy to play with queries at psql's REPL until they're right, then freeze them into views.  If you decide that a query's grouping, partitioning, or aggregating must be changed, it's often easier to modify a query than it would be to modify the equivalent nested and sequential loops in non-declarative code.</p>

<p>With views, program logic becomes very simple&mdash;just selecting from a view, maybe filtering and ordering, but very little post-processing.</p>

<p>Views don't lose optimization.  The query planner essentially expands all views used in a query to derive one base-level query, then applies its optimization heuristics over that.  Thus, a database can optimize across named-view boundaries.  Typically, a procedural language cannot optimize across calls between different compilation units, and an object-oriented language cannot even optimize across any dynamic dispatch calls (i.e. invoking a method on an object).  What might require looping over the data dozens of times in a typically-factored object-oriented solution, when translated into equivalent database views, could very well be accomplished in a single pass over the data.</p>

<p>Migrations were also a big success.  Deploys were quick&mdash;I could do several a day.  Many deploys happened with <em>zero</em> downtime, without using any kind of database or application fail-over.</p>

<p>Migrations were designed to stop at useful points if a human needed to update data before continuing.</p>

<h5>What went poorly</h5>

<p>I put site-specific data into some early migrations.  Major mistake!  I had to fix-up early migrations in order to cleanly build databases for new sites.</p>

<p>Modifying existing views is sometimes difficult.  Changing the output columns or column-types of a view means you must DROP it first, then CREATE it over again.  Otherwise, you can get away with CREATE OR REPLACE.  In either case, you must pull up the definition from the last migration (the view's definition in a database dump is annotated to show type information and scope-resolution, but this is too clumsy to edit as a primary source).</p>

<p>If a view must be DROP'd for an update, every view that references it must also be DROP'd then CREATE'd again.  Because of this, a migration which changes a single view can get very large by pulling in every dependent view.</p>

<p>In this project, editing views was different from editing the program.  The source files for a program are a snapshot of the entire program&mdash;to change the program, change the snapshot, then reload the program.  Editing the views, on the other hand, required applying changes through a diff (the migration).  The snapshot could not be edited in place.  Diffs naturally have a different language than snapshots, as they express how to modify something that already exists while maintaining integrity, whereas snapshots express the structure that will exist, <em>ex nihilo</em>.</p>

<p>I also lacked any sort of rigor in defining views near the beginning of the project.  Some views unnecessarily included all of the underlying tables' fields.  When the structure of those tables changed, the views had to change as well.</p>

<p>Queries in Python are painful.  They're all strings, so they don't wrap like code, and can't bind directly with variables.</p>

<h5>Paths to improvement</h5>

<p>A migration should be named with only a number.  Comments at the beginning of the file can provide explanatory text.  The migration scripts would be augmented to parse these leading comments and display them to the user, when requested.</p>

<p>Split schema definition into two parts, tentatively called <i>structure</i> and <i>world</i>.  <i>Structure</i> would be expressed in migration files, and include operations to alter domains, tables, table constraints, or to update existing data to accommodate changing structure or constraints.  It would also include any data that is not site-specific (site-specific data being banned from migrations).  <i>World</i> would be a snapshot description of everything else&mdash;views, functions, etc.</p>

<p>To perform a migration, the migration scripts would drop everything in <i>world</i>, apply any pending migration scripts, then reload everything in <i>world</i>.  Consideration would have to be given to reloading <i>world</i> in the event that a migration fails.  Dropping <i>world</i> would also be disadvantageous to migrations that would benefit from defined views in order to update existing data.</p>

<p>The system should allow <i>world</i> to be split into multiple files, for some modicum of modularity.  The system would have an option to discover a working load-order and save that order to a file, so that the modules may be reloaded quickly and without trial-and-error, for production migrations.</p>

<p>Views should be classified by type.  I have discovered three basic types:</p>

<ol>

  <li>An <i>extension</i> view, which extends a table with some extra, easy-to-calculate or easy-to-join fields.  Such views seldom have aggregations, and joins are usually one-to-one.  Extension views should include every field of the base table.  Code will usually query an extension view instead of its underlying table, to get the extension fields in addition to the base fields.  Extension views are named after the underlying table, with <code>_ext</code> appended.</li>

  <li>A <i>processing</i> view.  These views may perform significant aggregation and joining over several tables, to provide some well-defined, narrowly-scoped, output.  Processing views include /only/ the applicable primary keys (or candidate keys) from the underlying tables, plus their own contributions.  Processing views are named according to their purpose.</li>

  <li>A <i>summary</i> view.  Summary views are based on a single table or single extension view, but join information from related processing views.  They include most or all fields from all data sources.  Summary views are named with an appended <code>_summary</code>.</li>

</ol>

<p>This scheme maximally decouples processing views, being the most complex, from changes in underlying tables.  Extension and summary views have simple definitions, often using * in their select lists, and so are not so annoying to update to match participating tables.</p>

<p>I would also consider using SQLAlchemy's table-definition features.  <em>However</em>, it can't be the definitive source from which the database is built (because you can't express migrations there; it's a snapshot language, not a diff language).  This would allow better code-formatting and comprehension by IDEs of table and field names and such.  This would violate the DRY principle (don't repeat yourself), though.</p>
 
            </div>
        </content>

        
    </entry>
    <entry>
        <link href="http://blog.fugue88.ws/archives/2011-04/Perceived-shortcomings-of-style-checkers-and-a-potential-solution" rel="alternate" title="Perceived shortcomings of style checkers (and a potential solution)" type="text/html" />
        <author>
            <name>David Owen</name>
                    </author>
    
        <issued>2011-04-09T23:56:03Z</issued>
        <created>2011-04-09T23:56:03Z</created>
        <modified>2011-05-17T13:58:51Z</modified>
        <wfw:comment>http://blog.fugue88.ws/wfwcomment.php?cid=15</wfw:comment>
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://blog.fugue88.ws/rss.php?version=atom0.3&amp;type=comments&amp;cid=15</wfw:commentRss>
    
        <id>http://blog.fugue88.ws/archives/2011-04/15</id>
        <title mode="escaped" type="text/html">Perceived shortcomings of style checkers (and a potential solution)</title>
        <content type="application/xhtml+xml" xml:base="http://blog.fugue88.ws/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Style-checkers check code for certain statically-determinable
properties.  These properties may affect dynamic behavior (e.g. all
references are definitely initialized before use), or they may be
purely textual (e.g. code is indented in a particular way).

<p>Teams use style-checkers to ensure some typical dynamic and textual
standard in the code base.  The idea is that common errors can be
prevented, and that a common textual style will aid readability,
especially between code from different authors.<a
href="#en1"><sup>1</sup></a>

<p>In reality, style-checking is far from ideal, especially regarding
textual consistency.  Some section of code may have notably
<em>worse</em> readability if wrapped to the project’s standard of 80
columns.  Some object allocation may not <em>have</em> a matching
deällocation because it is live for the program’s entire run.

<p>No matter the reason, exceptions to the rules always come up, and
this is where style-checking becomes really difficult: how do you
handle the exceptions?  If you do nothing, exceptions will accumulate
until the style-checker’s report is overwhelming.  At best, the report
will be ignored; at worst, it will become demoralizing to developers.
In such a situation, style-checking may be worse than no
style-checking at all.

<p>To keep the report positively motivating, you must make a change
somewhere:

<ul>

<li>You could alter the code to make it compliant with the style
rules.  This may directly compromise either the design integrity or
actual readability of the code.

<li>You could alter the style rules so that the case is no longer
exceptional.  But the new rule will probably be more complicated, have
more edge cases, and still have other (and new) exceptions.  Besides,
which is better: writing rules, or writing code?

<li>You could mark the exception in the code with some kind of
meta-comment, so that the style-checker ignores it on future runs;
but, this adds clutter to the code and runs counter to the goal of
readability.

<li>You could mark the exception somewhere else.  This keeps the code
clean, and the developers in control, but this database would have to
be intelligent enough to keep up with code motion as the project
develops.  The database should also be version-controlled with the
source that it annotates.

</ul>

<p>This last approach would yield a “perfect” solution: it would only
ever mark newly-introduced problems in the code.  A “conservative,”
approximate solution (one that marks every new problem, and might mark
a few old) is possible if we make the following assumptions:

<ul>
<li>Code is under version-control;
<li>The style-checker is run before or as part of the process of committing code to the main branch; and,
<li>Genuine problems, when reported, will actually be addressed.
</ul>

<p>Given these constraints, we can see that a style-checker could
report on errors associated only with code features that are new or
changed in the current version, relative to the latest main-line
version.  If this is the case, it would assume that any style
exception in the main-line is there intentionally, and should not be
reported on again (it would have been reported when it was previously
committed)—it would not need to track exceptions in a separate
database.  I call this “differential style-checking.”

<p>The code features that the style-checker tracks could be either
lines of text, or nodes of parse-trees.  The latter might be more
accurate, but the former might be easier to implement and good enough
in most cases.

<p>Here is a proof-of-concept.  It works on only one <a
href="http://www.python.org/">Python</a> file at a time, and the
output is messy, but it demonstrates the essential principles. <a
href="http://www.logilab.org/project/pylint">pylint</a> version
0.19.0, as packaged in <a href="http://www.ubuntu.com/">Ubuntu</a>
10.04, is the style-checker, with which I have no experience prior to
writing this.

<pre><code>#!/bin/bash

 
usage() {
    echo $0 trunk_dir proposed_dir file
    exit 1
}


comment() {
    # $1 the file to comment
    # $2 the line number
    # $3 the comment to append
    head -n $(( $2 - 1 )) $1 >/tmp/tmp.py
    local target_line=$(head -n $2 $1 |tail -n1)
    echo "$target_line #{$3}" >>/tmp/tmp.py
    tail -n +$(( $2 + 1 )) $1 >>/tmp/tmp.py
    mv /tmp/tmp.py $1
}


process() {
    local type
    local line
    local msg
    local old_ifs="$IFS"
    IFS=":"
    while read type line msg
    do
        [ "$msg" ] &&amp; comment $1 $line "$type:$msg"
    done
    IFS="$old_ifs"
}


TRUNK=$1; shift
PROPOSED=$1; shift
FILE=$1; shift

[ -d "$TRUNK" -a -d "$PROPOSED" -a "$FILE" ] || usage
[ "$1" ] &&amp; usage

STRIPPED=${FILE%.py}
MODULE=${STRIPPED//\//.}

pushd $TRUNK >/dev/null
cp $FILE /tmp/left.py
pylint -rn $MODULE 2>/dev/null |process /tmp/left.py
popd >/dev/null

pushd $PROPOSED >/dev/null
cp $FILE /tmp/right.py
pylint -rn $MODULE 2>/dev/null |process /tmp/right.py
popd >/dev/null

diff -u /tmp/{left,right}.py |egrep '^[+@]'</code></pre>

<p>For a sample run, I will use the <a
href="http://trac.edgewall.org/">Trac</a> project, which I greatly
respect.  At revision 10114, the <a
href="http://www.postgresql.org/">PostgreSQL</a> backend received a
change, which we will analyze.

<pre><kbd>
cd /tmp
svn co -r10113 http://svn.edgewall.org/repos/trac/branches/0.12-stable 10113
svn co -r10114 http://svn.edgewall.org/repos/trac/branches/0.12-stable 10114
diffstyle 10113 10114 trac/db/postgres_backend.py
</kbd></pre>

<p>The (wrapped) output is:

<pre style="white-space: pre-wrap">+++ /tmp/right.py       2011-04-09 09:59:48.274189942 -0600
@@ -237,6 +237,11 @@
+    def update_sequence(self, cursor, table, column='id'): #{C:PostgreSQLConnection.update_sequence: Missing docstring} #{R:PostgreSQLConnection.update_sequence: Method could be a function}
+        cursor.execute("""
+            SELECT setval('%s_%s_seq', (SELECT MAX(id) FROM %s))
+            """ % (table, column, table))
+</pre>

<p>We see that, according to pylint’s default checks, two new
(potential) problems were introduced: the new method doesn’t have a
docstring, and the new method could be a function outside of a
class.<a href="#en2"><sup>2</sup></a>

Running pylint normally on <code>postgres_backend.py</code> revision
10114 produces 47 warnings.  (The entire Trac packages yields 10065.)

<pre><kbd>pylint -rn trac.db.postgres_backend |egrep '^[A-Z]' |wc -l
pylint -rn trac |egrep '^[A-Z]' |wc -l</kbd></pre>

<h5>End notes</h5>

<ol>

<li>I believe that style-checkers can effectively guard against some
types of runtime errors, just as compilers can.  I don’t believe
that style-checkers can be an effective judge of textual style.

<li>In this case, the style-checker got it wrong.  This must be a
method, because it is invoked polymorphically; although, it need not
be an instance method—it could be a class method.

</ol>
 
            </div>
        </content>

        
    </entry>
    <entry>
        <link href="http://blog.fugue88.ws/archives/2010-09/Making-and-maintaining-a-good-sleep-cycle" rel="alternate" title="Making and maintaining a good sleep cycle" type="text/html" />
        <author>
            <name>David Owen</name>
                    </author>
    
        <issued>2010-09-25T12:22:00Z</issued>
        <created>2010-09-25T12:22:00Z</created>
        <modified>2011-04-11T16:38:41Z</modified>
        <wfw:comment>http://blog.fugue88.ws/wfwcomment.php?cid=10</wfw:comment>
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://blog.fugue88.ws/rss.php?version=atom0.3&amp;type=comments&amp;cid=10</wfw:commentRss>
    
        <id>http://blog.fugue88.ws/archives/2010-09/10</id>
        <title mode="escaped" type="text/html">Making and maintaining a good sleep cycle</title>
        <content type="application/xhtml+xml" xml:base="http://blog.fugue88.ws/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>During most of college, I had an awesome sleeping habit.  My alarm
was set for 7:30 am every day, without exception.  And, every day,
without exception, I would wake up at 7:28 am, two minutes ahead of
the alarm.

<p>It didn’t matter when I went to bad the night before.  10:00 pm,
2:00 am, it didn’t matter; though, if I had stayed up late, I would
get sleepy sooner and go to bed earlier next time.

<p>But near the end of college, that magic broke.  I started
struggling to maintain a decent wake schedule, waking up closer to
10:00 am, even with a normal day-time job.

<p>Although I still don’t have the amazing abilities I had in college,
I was able to get myself back to a good wake schedule.  Here’s how I
do it.

<h5>Reinforce your alarm response</h5>

<p>On a day that you have some extra time, set your normal alarm for a
few minutes from now.  Get in bed, close your eyes, and relax.  As
soon as your alarm goes off, jump out of bed.  Yes, really: jump.
Don’t just roll out—be active.  Repeat this several times.

<p>This is especially useful if you find yourself sleeping through
your alarm, and not remembering that it even went off.

<h5>Align your eating schedule</h5>

<p>Your sleeping rhythm is affected by several inputs, one of those
being digestion.

<p>Eat breakfast soon after waking.  I usually eat something within 10
minutes of waking, although an hour or so might be just as good.
Don’t put off breakfast!  It tells your body that this is a time to be
awake.

<p>Don’t eat right before sleeping.  If you must eat something, keep
it small and light.  Fat and protein extend your digestion, and will
make you sleep in.  Avoid simple carbohydrates as well, as they will
keep you awake.

<h5>Fast to make drastic adjustments</h5>

<p>If your sleep schedule is way off of where you want it to be, skip
dinner.  The lack of digestion lets your body sleep more easily, and
you’ll be more likely to eat a larger breakfast in the morning,
kicking your digestion into full gear.

<p>If you constantly struggle to keep your sleep schedule set, you
might consider fasting (dinner) on a regular basis.

<h5>Get plenty of sunshine</h5>

<p>Sun shining on your skin creates vitamin D and other chemicals that
are essential to effective use of other nutrients, good mood, and even
your sleep cycle.

<p>If you work inside most of the day, take regular breaks to go
outside.  Walk around the building at the least, or find some nearby
landscaping that you like and lay down in the sun.

<p>If you really can’t get natural sunlight, many people recommend
full-spectrum lamps as fairly good substitutes.

<h5>Have something to look forward to</h5>

<p>If you go to sleep with nothing but worries, you’re much more
likely to want to sleep in.  The day has nothing positive, so why not
put it off, right?

<p>So, about 30-60 minutes before you go to bed, think of one or two
very positive things for the coming day.  Then, make sure to visualize
those as vividly as possible as you fall asleep.  When your alarm goes
off in the morning, you’ll wake up excited, even if you’re not
consciously thinking about those things.

<p>Don’t try to come up with something positive once you’re already in
bed—you’re likely to fall asleep before you do, or to not have enough
visualization time for them to sink in well enough.  Take the time to
prepare for tomorrow!

<p>You might be in genuinely stressful or negative situations right
now that are near impossible to avoid thinking about.  That’s okay;
acknowledge it, but always keep it in terms of some form of
improvement, and make something to look forward to.  Your life is your
own, to make better, or not, as you wish.

<h5>Be consistent</h5>

<p>Set your alarm, get out of bed on time, eat early, enjoy the sun,
and think positive, every single day, even if it’s a weekend, holiday,
or vacation.  Good, well-chosen habits are a key to success. 
            </div>
        </content>

        
    </entry>
</feed>