For the Love of Code

A bitty blog

Let Me ways.count

How do I love thee?

There are so many things I love about code. I love the logic and the thought-process. I love the constant learning and discovery. I get a little thrill out of taking something complex and breaking it down systematically... So many things...

Lately, it has occurred to me that something I've been particularly enraptured by is the idea that code can be used in many different ways for many different reasons. It can be used to build super useful, world-changing applications, but sometimes it can be used to while away a weekend afternoon attempting to code 'Moonlight Sonata'. I think sometimes it feels as though one must exclusively think in different caps, and that spending time programming must be at the expense of other types of pursuits. However, they need not be incompatible. Code can be functional, efficient, and productive, but it can also be imaginative and experimental.

So, one of my favorite takeaways from the past couple of months is that code can be fun. I mean, code is always fun, (even when grappling with elusive bugs for hours on end, tearing every shred of sanity out one by one, right?). Yet, I've been introduced to the idea that code can also be creative and expressive in a way I hadn't previously considered. It's inspirational to be surrounded by people who code for the sake of coding, sometimes just for the hell of it.

At one point in the semester we were briefly introduced to a gem called Banjo, https://github.com/dabit/banjo. It was a moment of magical epiphany to realize that music could be expressed as code. Maybe that's a big fat, 'duh'. Of course it can. But, I guess I never considered the possibility that I could do it. Playing around with the gem was a little challenging. I began by taking the sample files and modifying them, like twinkle twinkle gone wild. It's really amazing to write some lines of code and hear the output as sound. Then, I tried converting some of my favorite pieces of music to code, which was incredibly fun, but yielded somewhat less substanital results. Despite trying to start with something easy, I spent... more time than I'd like to admit trying to write 4 bars of music. An attempt at a simple arpeggio yielded something like this.

play(a(1)).every(3)
play(cs(2)).every(3, -1)
play(e(2)).every(3, -2)

I'll definitely play with this more. Maybe one day, month, ...year, I'll have something more exciting to share, but for now, the pleasure is in the process.

On that er.. note, another thing that blew my mind is code poetry. Like, that's a thing!? People write beautiful functioning code that is also poetry. It even has a Wikipedia page, https://en.wikipedia.org/wiki/Code_poetry. After being introduced to the http://timelessrepo.com/haiku site of code haikus, an entire new world of possibility unfolded before me. One project that combined code and literary art was the Stanford code poetry slam, http://news.stanford.edu/news/2013/december/code-poetry-slam-122013.html, where participants used code, poetry, and also multimedia to artistically and programmatically encapsulate ideas. The winner performed her piece by reciting the poem as she typed and projected the code onto the wall. Then, the output from the script was read by various computer generated voices. Another fascinating project was code {poems}, which compiled and published an entire book of code poetry. Submissions were selected by a panel of literary programmers, and were written in a variety of languags like c++, Python, DOS, Ruby, and HTML.

Excerpt from code {poetry}:

Creation?

# Creation def dstBit(mass,rot,vel): bMass=mass bRot=rot bVel=vel def dstCld(mass,rot): mass=mass rot=rot def Stir(dstBit1,dstBit2): CldMass=dstBit1.mass+dstBit2.mass CldRot=dstBit1.vel*dstBit2.vel return dstCld(CldMass,CldRot) def Sprk(dstCld):return StellarObject(dstCld.mass) def Life(planet,seed):return None dstBit1=dstBit(8.3,5.2,-7.1) dstBit2=dstBit(5.3,3.2,5.4) Cld=Stir(dstBit1,dstBit2) Planets=[] for i in range(8): Planets[i]=Stir(Cld,dstBit1) Sol=Sprk(Cld) Life(Planets[2])

http://code-poems.com/news.html
http://www.wired.com/2013/04/code/

My own attempts at code poetry were pretty silly and my midi code songs less than impressive, but it's an interesting and mind-flexing challenge to undertake. The logical analytical side gets to have a playdate with with the creative, inventive side. Not that everything must be or should be expressed in code, but it sure is nice to know that it can.

Me and My Arel

Beneath the fantastical query interface of Active Record is a trusty little helper named Arel. According to the documentation, Arel is a SQL AST manager for Ruby. It

  1. Simplifies the generation of complex SQL queries
  2. Adapts to various RDBMSes

So, what does this mean, and what does Arel do beneath the surface?

The Point! Arel is an object-oriented Ruby library for relational algebra

Relational algebra is a mathematical system, in which the operands are relations (or variables representing relations), and the operators are common procedures on these relations in a database. By definition as an algabraic system, operators and operands are combined to form expressions that produce new values. So, all of the things we want to do with our database, like selecting and getting attributes, are expressed as evaluations of relations and operations. The core relational algebra operations are: set operations (union, intersection, and difference); selection (picking rows); projection (picking columns); products/ joins, and renaming. So, for example, a selection query can be mathematically formulated as R1:= σc(R2), where c is the condition to be satisfied with reference to attributes of R2.

The Not So Pointless Forest of Abstract Syntax Trees

Arel implements this relational algebra system by representing queries as nodes in a data structure called an abstract syntax tree (AST). An abstract syntax tree is just a graph which breaks the syntax down into abstract pieces and represents their syntactic relationships as paths. What is the point of all these nodes? Having queries represented as nodes is really powerful, because it makes queries composable and allows for creation or modification through method calls. So a query can be built up modularly through combinations of parts, as well as with other queries. Like interchangable blocks, the pieces can configured to form many different results.

In the spirit of object-oriented design, this is a very Rubyist solution for managing unweildy queries, because responsibilities and logic can be separated into objects and comprehensive pieces with particular jobs and explicit names, that can be reused and chained together. Thus, complex queries become simplified into more managable parts with much more resiliance and variability. This flexibility is at the heart of Arel's functionality, but it additionally extends to the higher level ORM framework, like Active Record, which is built on top. And, so this is a really large force behind the magic of the Active Record query interface.

In this transformative story, there are three big supporting characters: the manager, the visitor, and the collector.

The Pointed Man-ager

...because "A point in every direction is the same as no point at all."
Managers are objects responsible for creating and modifying the tree. For instance, The Select Manager is responsible for composing select statements. So, if we select all from a table, (table.project(Arel.star)), an instance of SelectManager is returned. Similarly, there are managers for insert, update, and delete. If we want to compose an insert query, we can instantiate an insert manager instance (insert_manager = Arel::InsertManager.new(ActiveRecord::Base)), and tell the manager to create the query, (insert_manager.insert([[table[:attribute], "value"]])). When methods are called to modify the query, the manager goes in and updates the appropriate nodes of the tree. We can then call the to_sql method on the manager instance to have the resulting SQL statement returned.

The Leaf Visitors

Arel processes the output by using the extrinsic visitor pattern, which enables Arel to remain flexible and database agnostic. This also abstracts the output processing away from the tree, so that the structure doesn't need to change in order to produce different types of queries. There are a number of different types of visitors in the Visitor directory, but the big database workhorse is ToSql. Other visitors include, MySQL, PostgreSQL, and SQLite. And since the point of Arel is to generate SQL statements, all of the database visitors inherit from ToSql. With all of these visitors, Arel must be really smart about which visitor to use. It does this by having the visitor call an accept method on itself, with the root node as an argument. Then, it looks at the root node and determines which visit method to execute from the root node's type. So, the nodes don't need to concern themselves with results, as the leaves need not concern themselves with the harvest.

The Rock - Collector

Then, bringing it all together, is the collector. The collector is an object that gathers the results from the visitor. It's just a fancy string. For example, the collector PlainString is initialized with an @str attribute set to ''. The SQLString collector then inherits from PlainString. Within the to_sql method (which lives in the Tree Manager), the collector gets the visitor from the connection (engine.connection.visitor). Then the collector's value method is called to produce to the final result, which is the resulting SQL query.

The Point of No Return - Dot

There is also a Visitor called Dot, which will create a diagram from the Abstract Syntax Tree in Graphviz dot format. Rather than calling to_sql on the manager, we can also call to_dot, and get a pretty diagram output. So, if we have a table of boats and we want to select all the boats, we can do the following:
boats = Arel::Table.new(:boats, ActiveRecord::Base)
select_manager = boats.project(Arel.star)
select_manager.to_sql #=> "SELECT * FROM \"boats\"" (to_sql returns the expected sql)
File.write("arel.dot", select_manager.to_dot) (to_dot returns the the AST diagram)
Then, we can convert the dot file to a png, and...

images

  • https://github.com/rails/arel
  • http://infolab.stanford.edu/~ullman/fcdb/aut07/slides/ra.pdf
  • http://web.info.uvt.ro/~oaritoni/inginerie/Cursuri/DesignPatterns/L7/Visitor/nordberg.ps.pdf
  • http://jpospisil.com/2014/06/16/the-definitive-guide-to-arel-the-sql-manager-for-ruby.html


Professor Butts RacksUp and Talks Middleware

images
use SpoonToMouth
use JerkLadle
use ThrowCrackerPastParrot
use ParrotJumps
use PerchTilts
use SeedsInPail
use PullCord
use IgniteRocket
use SickleCutsString
use PendumlumSwings
use NapkinSwings
run ProfessorButtsAndTheSelfOperatingNapkin

class ProfessorButtsAndTheSelfOperatingNapkin
  def call(env)
    [200, {“Content-Type” => “text/plain”}, [“SelfOperatingNapkin”]]
  end
end

Professor Butts RacksUp and Talks Middleware

While futzing around with a recent Rack lab, I found myself feeling like I was trying to operate a manual transmission without understanding how the engine works. So, this is an attempt to bring some clarity to my understanding of Rack and how it is integrated into http facing applications.

Professor Butts, I don’t get it. What is Rack?

Rack is a middleware program that serves as an intermediary between web servers and web applications. It is an interface that provides a level of abstraction over some of the different stages of request/response handling, such as authentication, authorization, caching, and execution. At a basic level, it wraps the HTTP requests/responses into a streamlined protocol, so that the logic of application functionality doesn’t have to mix concerns with the whole business of communication between server-application.

At the core of its functionality, Rack applications must simply respond to a call method that takes an evironment hash as an argument. This env arg contains data pertaining to the incoming request, such as REQUEST_METHOD; PATH_INFO, SERVER_PORT, and HTTP_VARIABLES, sort of like …the postage of on a letter? The purpose of env seemed mysterious at first, but it is really just a hash with CGI-type variables that must conform to the rack standard environment spec. Then, the outgoing response is forumulated as an array containing three items: a status, headers, and a body that must respond to an ‘each’ method.

Why middleware?

A particularly powerful aspect of Rack lies in its use middlware. Middlware just refers to software that is… in the middle. It acts as the connection layer between interacting applications. And Rack is itself also a type of middleware - middleware upon middleware. The middleware in Rack are just Ruby classes that have an initialize method taking an application as an argument and also have a call method. They simply act as filters around the request to the application and modifiers to the response. The Rack architecture utilizes the middleware modules by building them into a stack to chain the processes in a pipeline design pattern. By separating concerns into this logical chain of modules, it distills all the steps of the task down into one simple method call.

class IgniteRocket
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, response = @app.call(env)
    rocket_launched = “ &$%#*** >==> ”
    [status, headers, response.last + rocket_launched]
  end
end


class SickleCutsString
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, response = @app.call(env)
    sickle = “ –(/– ”
    [status, headers, response.last + sickle]
  end
end


Pipline Processing?

I think Rack’s pipeline processing design may be most simply imagined as a series of sequential tasks, with the output of each stage being passed down the line. Pipeline design reminds me of a Rube Goldberg machine, with lots of little processes happening in succession. Computations are passed along the stack like a conveyer belt to configure the response. This process chain provides an organized, modular way to sift and separate the various concerns of transfer protocol, making the handling more simple and streamlined. So, without a lot of fuss, Rack gives me to power and flexibility to initiate a request with a lift of my spoon, …throw a cracker, feed a parrot, fill a pail, launch a tiny rocket into space, …and respond with a napkin in my face.

Am I Just an Instance?

Object-oriented programming is an elegant design pattern due to its fundamental abstraction of logic, and the ability to encapsulate data storage and transfer in an organized system of properties and behavior. The oo model is so beautiful and logical because it is dependant on relationships and communication, which mirrors some of the most powerful and efficient systems in nature, from ant colonies to neural networks. Classes can share the same data in the form of class methods and class variables, but instances may have unique values and behavior through instance methods and variables. Ie. We are all humans, @@alive = true, trying to make sense of @@life_the_universe_and_everything = 42, but are also different and unique individuals, with different @characteristics and @experiences.

In particular, object-oriented programming in Ruby is empowering and liberating, because of the lack of authoritarian restriction sometimes present in other languages. As a person who is loosely devout to categorization and right angles, oop in Ruby can seem at first like the wild west of coding. Coming from some Java experience, which tends to be strongly typed, Ruby seems at first like an irresponsible caretaker, letting variables hang around with whomever they choose. However, it is this freedom that enables dynamic assignment and interaction. The programmer is liberated from fussing over types and typecasting, focusing rather upon functionality and logical relationships. Ruby trusts the human, because it was written for the human, and doesn’t impose stringent rules to chastise at every incompatible type.

Like many others here at Flatiron, there was a time when programming was the last thing I would have imagined myself doing. Coding always seemed like a mysterious realm where pedantic geniuses were permanantly hunched over machines, typing endless lines of crytic mathematical prescience. It was such an internal upheaval to discover this love for coding that it is still sometimes difficult to believe. Yet I need only to call upon self.loves_to_code #=> true, to verify its validity. Now, I can hardly imagine my life without code. I suppose fate is a clever (rubyist) programmer.

It occurs to me that learning to let ourselves love something new, such as coding, may be more difficult the more strongly we type our properties. We may resist assigning our attributes to unknown types, because we have defined ourselves and our variables so strictly. My Java self would have triggered an onslaught of compile-time errors at any attempt to assign this type of Programmer. Conversely, my Ruby self allows me to embrace new ideas and experiences, and yet, still remain the same self. I have come to deeply appreciate the Ruby language, because it allows me to focus on expression and meaning, to view the self as a whole, rather than belaboring the mechanics of every thought and decision.

So, if, in moments of existential crisis, I can hardly recognize this version of self, with instance variables so different from the self that existed not so very long ago, perhaps there is some solace in believing that perhaps I am merely an instance with a particular object identity, taking up some insignificant, temporal space in memory. My properties may have changed, but my identity has not. In moments of doubt, I’ll call upon my methods.