Today I paired with Doug. A large part of today was working with Rails using vim. One of my biggest takeaways from today was a couple of neat vim tricks. Here are the most important ones that I have come across:
Cursor Movement
h => moves cursor one spot left
j => moves cursor one spot down
k => moves cursor one spot up
l => moves cursor one spot right
w => moves cursor to the next word in the file
b => moves cursor to the previous word in the file
nG => moves cursor to the selected line number in the file (where n represents a
line number)
Inserting Text
a => add text after cursor
i => add text before cursor
o => add text in a new line below text
shift + a => add text at the end of the line
shift + i => add text at the beginning of the line (ignores leading whitespace)
Altering Text
x => delete character under cursor
X => delete character before cursor
dd => delete a line
D => delete text from cursor to end of the line
Y => copy line to buffer
p => paste text from buffer
u => undo last change
ctrl + r => redo last change
Working With Multiple Windows
:vsp filepath => creates a vertical split screen and loads up the specified file (where
filepath is the relative path of the intended file)
:sp filepath => creates a horizontal split screen and loads up the specified file (where
filepath is the relative path of the intended file)
ctrl + w + (h, j, k, or l) => moves cursor to an adjacent window (left, down, up, or
right depending on what key combo you selected)
8th Light Apprenticeship
Tuesday, December 27, 2011
Friday, December 23, 2011
Day 120
Today I paired with Brian Pratt and made an app for the ios platform in Objective-C. The app took credit card information, encrypted it, and sent it to a server using SSL. Before today, I haven't had any experience implementing SSL on servers.
SSL is used when the client wants to ensure that it is communicating with and only with the intended server. It accomplishes this by encrypting/decrypting its data with its public and private keys.
Anything encrypted with the public key can only be decrypted with the server's private key and vice versa. So if somebody encrypted a message with the the proper public key, send it off to a server, and got a response of data that could be decrypted with that same public key, then that somebody could be sure that they were communicating with the intended server. Additionally, if somebody was recording all of the data being transmitted, they wouldn't be able to understand any of it because they don't have the private key that the server has.
The only way SSL can be broken is by guess and check. If the key is 40 bits in size, the key can be broken given the proper amount of time and resources. However if a key is 128 bits or larger, (given our current computing power) it would take significantly longer than the age of the universe to “guess” the private key (according to http://luxsci.com/blog/how-does-secure-socket-layer-ssl-or-tls-work.html).
SSL is used when the client wants to ensure that it is communicating with and only with the intended server. It accomplishes this by encrypting/decrypting its data with its public and private keys.
Anything encrypted with the public key can only be decrypted with the server's private key and vice versa. So if somebody encrypted a message with the the proper public key, send it off to a server, and got a response of data that could be decrypted with that same public key, then that somebody could be sure that they were communicating with the intended server. Additionally, if somebody was recording all of the data being transmitted, they wouldn't be able to understand any of it because they don't have the private key that the server has.
The only way SSL can be broken is by guess and check. If the key is 40 bits in size, the key can be broken given the proper amount of time and resources. However if a key is 128 bits or larger, (given our current computing power) it would take significantly longer than the age of the universe to “guess” the private key (according to http://luxsci.com/blog/how-does-secure-socket-layer-ssl-or-tls-work.html).
Tuesday, December 20, 2011
Day 117
Today I spent all day pairing with Colin. Before today I had never worked on a project that 300+ other developers were working on at the same time. There were steps that Colin and I had to go through to get our code pushed to the master branch that seemed like really good ideas.
All code committed had to be written by a pair programming team or reviewed by somebody else on the team. Taking this measure increases the likelihood that the code being committed is clean code. Additionally, obvious mistakes are more likely to get caught before it gets added to master.
In order to push code to master, it is a convention (at the company Colin is doing work for) to push the changes to a machine that runs the full suite of tests. This ensures that all of the code is working as it was intended to work. If a test fails, the code doesn't get merged.
While these precautions will never ensure that broken or "dirty" code don't get added to the project, they seem to be extremely effective measures.
All code committed had to be written by a pair programming team or reviewed by somebody else on the team. Taking this measure increases the likelihood that the code being committed is clean code. Additionally, obvious mistakes are more likely to get caught before it gets added to master.
In order to push code to master, it is a convention (at the company Colin is doing work for) to push the changes to a machine that runs the full suite of tests. This ensures that all of the code is working as it was intended to work. If a test fails, the code doesn't get merged.
While these precautions will never ensure that broken or "dirty" code don't get added to the project, they seem to be extremely effective measures.
Monday, December 19, 2011
Day 116
Today I finished working on the data store and model for the project I am working on; then I paired with Micah on Limelight for Clojure. My big takeaway from today was how pair programming can create extremely refined code. Refined code is a result of the many benefits that come with working effectively while pair programming.
Much of the difficulty that comes with building software isn't caused by the syntax. The root of the complexity lies in the specific business rules for a given project. Creating good abstractions is a major key to building great software that delivers value to its users. Since these abstractions have to be understood by people reading the application with little or no context as to how the whole app works, it is crucial that they are created by multiple people.
If an abstraction can be easily understood by its creator it doesn't mean that anybody else will be able to understand them. The creator has more context than the future readers of the code.
With pair programming, if two people are able to understand an abstraction, it is much more likely that other people will be able to understand them as well. The process of pair programming and ping pong pairing ensures that both parties understand exactly how each abstraction works. If there is any confusion, they talk about other potential approaches and make modifications as they see fit.
Much of the difficulty that comes with building software isn't caused by the syntax. The root of the complexity lies in the specific business rules for a given project. Creating good abstractions is a major key to building great software that delivers value to its users. Since these abstractions have to be understood by people reading the application with little or no context as to how the whole app works, it is crucial that they are created by multiple people.
If an abstraction can be easily understood by its creator it doesn't mean that anybody else will be able to understand them. The creator has more context than the future readers of the code.
With pair programming, if two people are able to understand an abstraction, it is much more likely that other people will be able to understand them as well. The process of pair programming and ping pong pairing ensures that both parties understand exactly how each abstraction works. If there is any confusion, they talk about other potential approaches and make modifications as they see fit.
Friday, December 16, 2011
Day 115
Today I got started building a fire pump testing application in Clojure. One of the first things that we tackled was storing and retrieving data from a custom data store. Part of that was making a function that searched for records. We are storing our records as a vector of maps. The following functions are some very cool functions we created to search for records based off of a matcher:
(defn is-subset? [record matcher] (empty? (clojure.set/difference (set matcher) (set record))))
(defn find-records [records matcher] (filter #(is-subset? % matcher) records))
To use this code you would pass a collection of records (with your records being in map form), then pass a matcher (a map with key val pairs that might match part of some records). The following is how you can use the find-records function from the repl:
user=> (find-records [{:a 1 :b true} {:a 1 :b false}] {:b true})
({:a 1, :b true})
user=> (find-records [{:a 1 :b true} {:a 1 :b false}] {:a 1})
({:a 1, :b true} {:a 1, :b false})
user=> (find-records [{:a 1 :b true} {:a 1 :b false}] {:a 2})
()
user=> (find-records [{:a 1 :b true} {:a 1 :b false}] {})
({:a 1, :b true} {:a 1, :b false})
This works by the find-records function grabbing each record in the collection that is-subset? returns true for. The is-subset? function takes the record and makes a set of key/val vectors out of it; then it checks to see if the matchers are contained in the current record.
(defn is-subset? [record matcher] (empty? (clojure.set/difference (set matcher) (set record))))
(defn find-records [records matcher] (filter #(is-subset? % matcher) records))
To use this code you would pass a collection of records (with your records being in map form), then pass a matcher (a map with key val pairs that might match part of some records). The following is how you can use the find-records function from the repl:
user=> (find-records [{:a 1 :b true} {:a 1 :b false}] {:b true})
({:a 1, :b true})
user=> (find-records [{:a 1 :b true} {:a 1 :b false}] {:a 1})
({:a 1, :b true} {:a 1, :b false})
user=> (find-records [{:a 1 :b true} {:a 1 :b false}] {:a 2})
()
user=> (find-records [{:a 1 :b true} {:a 1 :b false}] {})
({:a 1, :b true} {:a 1, :b false})
This works by the find-records function grabbing each record in the collection that is-subset? returns true for. The is-subset? function takes the record and makes a set of key/val vectors out of it; then it checks to see if the matchers are contained in the current record.
Thursday, December 15, 2011
Day 114
Today I finished my project management training class and mapped out a possible design for a new client project. Additionally I went to a Heroku meetup last night and got exposed to a very cool concept. Breaking up a monolithic application into multiple components (a component-based application).
According to Luca Deri of the IBM Zurich Research Laboratory, an individual component must have the following attributes:
So why is this design pattern a better approach to building large scale applications?
Individual components are easier to extend than a whole application. Since individual components typically have a single responsibility, they are a lot more flexible. Often times, as parts of software get loaded with features, they get harder to extend.
Individual components are more reusable. When you extract functionality into small components, each component gets decoupled. When this decoupling occurs, the functionality gets more reusable.
According to Luca Deri of the IBM Zurich Research Laboratory, an individual component must have the following attributes:
- it is not statically linked to the application but it is loaded at runtime
- it has the ability to be replaced (i.e. a new version of the component can replace a previous one) at runtime while the application is running
- it has a well-defined interface that makes it possible to communicate with other components independently from the type of the services provided.
So why is this design pattern a better approach to building large scale applications?
Individual components are easier to extend than a whole application. Since individual components typically have a single responsibility, they are a lot more flexible. Often times, as parts of software get loaded with features, they get harder to extend.
Individual components are more reusable. When you extract functionality into small components, each component gets decoupled. When this decoupling occurs, the functionality gets more reusable.
Wednesday, December 14, 2011
Day 113
Today I spent the first half of the day in Libertyville at a client meeting, then the second half of my day was spent at the project management training seminar in Chicago. My big takeaway from today has to do with how the software creation process affects the amount of value you can bring to a client.
A lot of companies create a design for features up front, then they develop them, then they test them. When taking this approach design, development, and testing rarely take the same amount of time. Therefore features will usually end up sitting in a waiting list for some period of time between design, dev, and/or testing. Additionally, every once in a while, code will get sent back up the process to be refactored.
If companies use test driven development and let the tests guide the design decisions, then all of the features can be implemented by one pair programming team. This is extremely beneficial to clients because if they send a request through the development pipeline, their requests never sit in a waiting list or get sent back up the line for refactoring. Instead all refactoring is done as the feature is being built. This style of development seems to be the most beneficial.
A lot of companies create a design for features up front, then they develop them, then they test them. When taking this approach design, development, and testing rarely take the same amount of time. Therefore features will usually end up sitting in a waiting list for some period of time between design, dev, and/or testing. Additionally, every once in a while, code will get sent back up the process to be refactored.
If companies use test driven development and let the tests guide the design decisions, then all of the features can be implemented by one pair programming team. This is extremely beneficial to clients because if they send a request through the development pipeline, their requests never sit in a waiting list or get sent back up the line for refactoring. Instead all refactoring is done as the feature is being built. This style of development seems to be the most beneficial.
Subscribe to:
Posts (Atom)