def things_n_stuff

Adventures in Code

Scope, Safe Ignorance, and Passing Objects

Today’s post is on something that was confusing to me and is probably confusing to other budding ruby developers. 100% of the credit for any understanding is owed to a combination of Avi, Jeffrey Baird, Sandi Metz, a definition I found online from the Dave Thomas ruby book, and osmosis from classmates. Unless something’s wrong, in which case it’s 100% me.

Ah Befuddlement, I Know ye Well

Anyone who’s dabbled in ruby and tried to understand Object Oriented Programming must understand scope. Everything in ruby is an object, and there are limitations (or at least should be) to what kinds of other things each object has access to and can affect. One way to visualize this is as an electrical outlet.

If you only have one thing plugged into an outlet, like a drill, it’s simple to remove that plug or put it in a different socket if you subsequently want to plug in a chainsaw. (People use electric chainsaws, right?) On the other hand, if your outlet is chocked with a million plugs and extension cords it get trickier to find the cord you want, and if you try to change the setup later it’s easy to unplug your monitor when you thought you were pulling on the lamp chord.

Proper Ignorance vs Entanglements

Ruby object are somewhat similar and a million times more elegant. A ruby object needs to know/have access to only the stuff it should, in order to do its job, nothing more, nothing less. This is what prevents unnecessary entanglements, and allows you (and me) to build awesome, powerful modularity into programs, and also what inclines rubyists towards the convention of building numerous small, single-purpose, clearly defined and clearly labeled methods instead of larger, more-comprehensive ones. Eluminating this way of building is Metz’s ballywick; check out her talk: http://www.poodr.info/blog. (Also a super nice and interesting lady.)

Scope-arama

One first speedbump in learning to build and think this way is both obvious and surprizing when you first arrive at it: if I’m building wonderful, clean, isolated methods and single-purpose objects, how can I get anything done? If I have an object/message in a Spaceship class, how can I get it over to an object of the GroundControl class? Elegantly, of course, and many different ways. Ruby’s about choice! However you choose to do it though, the process relies on the concept of approriately ignorant object, and scope.

Your Ruby is Haunted

One key to understanding scope is understanding self. (…or finding Dave Thomas’ explanations of self somewhere online.) In ruby the idea of ‘self’ is attached to whatever part of your program is currently being processed. If you create an instance of a class and give it an attribute, the only one who will know the value of that attribute is the instance itself.

How to Pass a Pirate

To demo this way of getting messages between classes I’ll walk through an example I found very helpful, given to me by the super-fantabulous Jeffrey Baird – a teacher here at the Flatiron School. Definitely good for beginners, but probably not absolute beginners. I’m also going to skip ahead to the relevant part.

Setup: make 4 files, pirate_test.rb, ship_test.rb, and pirate.rb and ship.rb. (download the gem if you like, or run a different test-suite.)Copy the test content into the appropriate file, run, add code to the appropriate file, run, repeat until you get the tests to pass.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ship_test.rb
require 'fis/test'
require_relative 'pirate3'
require_relative 'ship3'
include Fis::Test

test 'should instantiate a ship' do
  assert Ship.new
end

test 'a ship should know all the pirates on it' do
  pirate =Pirate.new
  ship = Ship.new
  ship.name = "Black Pearl"

  pirate.ship = ship

  assert ship.pirates.include?(pirate)
  
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#pirate_test.rb
require 'fis/test'
require_relative 'ship3'
require_relative 'pirate3'

include Fis::Test

test "should instantiate a pirate class" do
  assert Pirate.new
end

test "pirate should have a name" do
  pirate = Pirate.new
  pirate.name = "Dan"
  assert_equal pirate.name, "Dan"
end

test "pirate should know what ship it belongs to" do
  pirate = Pirate.new
  ship = Ship.new
  pirate.ship = ship 

  assert_equal pirate.ship, ship
  
end
1
2
3
4
5
6
7
8
9
10
11
#ship.rb
class Ship
  def name=(name)
    @name = name
  end

  def name
    @name
  end

end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#pirate.rb
class Pirate

  def name= name
    @name = name
  end

  def name
    @name
  end

  def ship= ship
    @ship = ship
  end

  def ship
    @ship
  end
  
end

At this point your pirate tests should be passing, and running your ship_test.rb file is giving you this:

ruby ship_test.rb 
pass: should instantiate a ship
fail: a ship should know all the pirates on it

So. How do you get a ship to know all of the pirates on it? Here’s where we need to rexamine the notion of self and scope. We want to be able to ask a ship, ‘Hey ship, who are all of your pirates?’ So first we’ll want the Ship class to keep a list of all the pirates available to the class. Let’s use a constant to store an array of all pirates. Then we’ll give every instance a(n instance) method that will simply show all the pirates.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ship.rb
class Ship

PIRATES =[]

  def name=(name)
    @name = name
  end

  def name
    @name
  end

  def pirates
    PIRATES
  end

end

Now our Ship class has an empty list setup to store pirates, and you can call pirates on any ship instance and get that list. But how do we populate the list? The Ship class doesn’t have access to any pirates, doesn’t know their name, but we need to get them on the ships’ instances. Instances of Ship also don’t know any of the pirates. I need to gets me some pirates into the PIRATES constant in the ship class, hopefully without creating any new unnecessary connections between the classes. Let’s check out the Pirate class again.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Pirate

  def name= name
    @name = name
  end

  def name
    @name
  end

  def ship= ship
    @ship = ship
  end

  def ship
    @ship
  end

end

What references do we have to ship? Well, we have a lovely getter and setter for adding a ship as an attribute for pirate instances, ship= and ship. But what do these methods “know about?” If we’ve made a pirate instance called johnny, when we call johnny.ship = “The Sea Bitch”, self is johnny and we’re passing the ship name “The Sea Bitch” to the johnny instance. At that moment we’ve connected some information from the Ship class (a ship.name) and an object from the Pirate class. The argument passed to ship= is an instance of Ship that was already created and given a name. At the same ‘moment’, ie. while self is passing through the ship= method you can piggy-back on the values present. How?

The key is realizing that we have a ship.pirates method, and remembering that when you call pirate.ship=, self is a pirate instance and the passed-argument is a ship instance. Key: as soon as that ship instance arrives into the method and its reciever, the method has the ability to call the appropriate Ship class’s methods on the ship instance. You want to give it the current instance of pirate, so give it SELF! Modify the ship= method:

1
2
3
4
  def ship=(ship)
    @ship = ship 
    ship.pirates << self
  end

It’s that clean! What’s going on? Basically we alter the method to allow us to do pirate.ship=. So we can set the ship for a pirate. Then, assigning the ship instance passed in as an argument to the @ship instance variable allows us to set the name of the ship for the instance. ship.pirates << self allows us to add the instance that ship= is being called on (an instance of pirate) to THE RESULT of callin the pirates method on an instance of ship.

What can get confusing is that it seems like we’re playing around in the Pirate class to add something to the Ship class, but what we’re actually doing is telling an instance of the Pirate class to add itself to the PIRATES list inside the ship class, as soon as it is assigned a ship attribute. We’re using objects and their attributes to communicate with other objects and atributes. And we’re keeping objects decently ignorant about all things besides their appropriate attributes.

Cool.

Sampling Code Organization

Fairly soon I’ll hopefully begin cleaning up and open-sourcing a few projects I’ve been working on. To get a better idea of how programmers organize their codebase I’m going to look at a super-simple app.

For simplicity and clarity (and fun) I’m checking out the Bubs App on github by the just stupidly awesome Zach Hollman.

Bubs

The Bubs functionality is straightforward enough: “ⒷⓊⒷⓈ helps you write really obnoxious text from your command line. Try it in your commit messages- your coworkers will love you.” Love it. Need more pointless fun in my life. (Also love The Wire.)

Install and run. I get some odd formatting because of over-personalized .bashprofile etc., but otherwise all good.

Smaller icon

So What’ve We got:

  • bubs Holds everything
  • bubs/bin/
    • contains a file labeled bubs
    • is an executable file, tells bash to use ruby and requires the gem
    • grabs the arguments following “bubs”, assigns to a variable and sends that variable object to the Bubs class as an argument to the class method “copy”
    • prints the result to the console
  • bubs/lib/
    • contains one file with one small (clear and well-commented) ruby class
    • runs the image conversion and returns it to the executable file in /bubs/bin
  • bubs/.gitignore/
    • the file you all know and love
  • bubs/LISCENSE.md
    • the ‘please play nice and don’t sue me’ file.
  • bubs/README.md
    • the ‘how to use and install’ file
  • bubs/Rakefile
    • not super clear on this one, but I think it’s kind of similar to a task compiler for your app written in ruby. A ruby Makefile.
  • bubs/bubs.gemspec
    • again not super clear here. Spec sheets are usually tests, but Holman says that this is the “rakegem gemspec template”. Seems to simply list out settings and tasks for the rakefile, and pull all of the files together.

That’s all for now. Next up, dissecting a program with a few more layers, Evoke, by thumblemonks.

(Hints of) Functional Programming in Ruby

Cursory yields little

I keep hearing about functional programming. I had a vague notion of what that entails and a bit of curiosity, so a wonderful TA at the Flatiron School suggested a speakerdeck presentation for me to check out. The results are fairly mixed.

As a burgeoning Ruby developer I pick up hints of the ongoing larger conceptual war for programming language/paradigm supremacy, but all I know so far are the lovely objects of Ruby and the messy, almost-consist forrest of special characters of a few other languages. Just a “barbarian’s” perspective I’m sure, but still.

So when I picked up Pat Shaghnessey’s slides on Functional Programming in Ruby on speaker deck, I was hoping for a bit of elightenment about the advantages of mixing paradigms. All I really knew about functional prior was that functional programming treats actions like mathematical functions. And as I see from Shaghnessey’s slides that is the case, and one of it’s primary differences from how I’ve thought of Ruby-like object-oriented programming. Functional takes input, runs it through the function magic, and consistently spits out the transformed input on the other side. Unlike object oriented languages in general, functional focuses on being state-independent. So a function always has the same effect on input, with very few side effects or variations based on other structures.metaphysics

The presentation itself was high on the “Gee that seems cool” factor, but still left me mostly in the dark and googling for answers. I’ve always liked working through Rube-goldberg style function puzzles and tracking input and output so following the actual functions was easy even when I couldn’t parse the haskel. Also yeah, haskel seems cool to write but awful to read.

Things got more interesting at the midpoint. Seeing beneath the hood on the collect method is fun, and getting the code for lazy enumeration is pretty cool. I wish programming books in general would speak more about the internal workings of object as they describe the functionality, lengthy as that would be. I’m definitely going to have to read this again after a few more weeks of programming… Structure of Lazy Enumerator

I was also reminded that I really need to dig deeper and learn about the Enumerable module and the Enumerator class.

Haskel itself looks a bit crazy. The contrast of Haskell’s vs Ruby’s handling of infinity was nifty and mysterious.
What's going onWhat's going on

But by the end of the presentation I couldn’t tell anymore if Shaughnessy was a proponent of using function programming within Ruby, or if he was showing how much ‘better’ Haskell is at certain tasks and how cool he is for using it. Both could be the case. Obviously the presentation is missing speach, context, and the oral component, but my takeaway is that it would appear that using aspects of functional within Ruby code holds much promise for optimization but limitations. Hmm. I think I could’ve guessed that before. I have few additional details than I had before.

Yargh

Terror of the Blank Canvas

“Keep it small. 5 points, 2 or 3 sentences on each point. Perfect is the enemy of done.” With this clear direction from Avi I set out to write my first blog post and, naturally, instantly discovered an enormity of perfectionism and writer’s block that I never new existed.

I first wrote a draft about Bloom’s Taxonomy of Learning Phases and learning to code. I wrote a second draft about my experiences teaching myself Chinese immersively, and the similarities between that process and my nascent steps into programming.

These posts may still make it to the web, but in the process of banging around on them I became fascinated with the source of my own hesitation: why should I have any amount of ego or insecurity at all about entering the world of coders, or in speaking about code? I am an complete beginner after all. Absolute metrics of capability and success should mean little at this point; a more valid measure ought to be the amount and direction of progress.

Impulse

I’m just starting out as a developer and have far more questions then pith and witticisms at so far. I do know that my curiosity seems to play a key role in driving my internal engagement and momentum, so as a first step I’m taking a sedimentary sample of my current knowledge, interests, and skill with coding. This will hopefully provide a useful baseline for measuring progress.

Sailing off the Edge of the World

What follows are a few things that I find absolutely fascinating right now, simply intriguing, perplexing, know nothing about, or want to know some things about. These are questions I’m looking forward to seeking answers to, and questions whose pursuit will bring ancillary fascination and skills. If things go well, as I progress in programming the burning question of the moment will only get more interesting.

  • What is threading?

  • Given the format of objects and classes, how much of a full complete concept of program should you have before Actually beginning to work on it?

  • How the hell can git make some sort of tiny file that exactly references every single tiny bit of data of all of your original files, plus tracking data and history etc, and yet can be transmitted at some tiny size and incredibly fast rate?How can you make make something that is an exact Copy of something else, without it being the thing itself, or at least the same size as the thing? It’s practically metaphysical. (When I was really young and started getting into maps, an old geoscientist at Swarthmore College told me that there is no such thing as an accurate map, because to build a completely accurate map or model is to rebuild the thing itself. It must be the same scale and size, have the same dynamism and interactivity between the parts. Git be magic?

  • What the heck are deltas?

  • At this point I’ve written tiny (super tiny) programs and scripts that flow from an initial conception quickly and fluidly. Many of the best practices in developing that we’re learning reading about seem to ensure good, working code that matches the goal via processes that slow down or structure the code creation.
  • Moving forward, how can I best maximize and instill habits and practices now that will help me quickly build fast and powerful models?
  • How can I quickly and effectively build good tests that help me help guide the course of my development projects, without interrupting the fund of creativity and inventing, and finally altering the process of my workflow?

  • I have a NorthFace shirt and a backpack that I bought when I was first getting into climbing and mountaineering. Almost 15 years later the bag and shirt are both still kickin’, and I’m wearing the shirt today in an urban environment. I dragged that bag up and down rock faces, often literally, and then have carried it filled with too-many books and laptops for more than a decade since. It’s lost the padding in the arm pads and looks a bit faded, but it is still an awesomely functional bag; it’s still tougher and more function than 90% of what’s made today, even by the same company, and has none of the extra bling and straps that climbers tend to cut off their bags anyway. How do I make code like this? Should I? Code that will hold up for years, that can be refactored and trimmed, whose essence is speed and functionality? That people love to use? That carries it’s first load and then adapts to different usage years from now?

  • There’s so many overlapping technologies and programming languages! How do you choose what to use for what kinds of projects and what parts of projects?

  • What does it mean to really ‘get’ http and tcp/ip? Is that a language to learn or simply a convention of interactions between other kinds of software and hardware?

  • How can I easily build inobtrusiveness add “bullet-proof” security measures into every app that I write?

  • What should I have for lunch?