Skip to content

existence, refactored

With kindness comes naïveté. Courage becomes foolhardiness. And dedication has no reward.

Archive

Tag: fundamentals

Last Friday, I got to teach about collections and closures in Ruby for ECC. That gave me an idea to write a post about one of the mistakes people coming from other languages tend to make when going into Ruby.

Let’s take the first problem from Project Euler:

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.

Looks simple enough. In pseudocode, your typical fresh grad programmer might do this:

sum <- 0
for i <- 1 to 999
  if i % 3 == 0 or i % 5 == 0
    sum += i
  end if
end for

A rubyist, however, will compress that 6 line program into a single line. Here is one possible solution:

(1..999).select { |x| x % 3 == 0 or x % 5 == 0 }.reduce(:+)

This line of code chains the 3 main components of the algorithm above:

  1. (1..999) - find a way to process numbers from 1 to 999. Here we created a Range that we can process as a whole.
  2. .select { |x| x % 3 == 0 or x % 5 == 0 } - process only the multiples of 3 and 5. Here, the method called selects only the elements that return true inside the passed block.
  3. .reduce(:+) - find the sum of the elements. Here we used the shorthand form of Ruby's reduce operation that sums the elements.

Let's try a harder example, problem 6:

(1..100).reduce(:+) ** 2 - (1..100).map { |x| x * x }.reduce(:+)

Here we see Ruby's map, which simply creates a copy of the source collection and applying the mapping function to each element. The map above is pretty trivial; we could even replace it with the long form of the reduce method.

(1..100).reduce(:+) ** 2 - (1..100).reduce(0) { |sum, x| sum + x * x }

While method chaining wouldn't be new to the novice developer, the concept of passing functions to methods, allowing greater flexibility, will be. Functional programming has been long forgotten even at the top universities in this country.

Another problem is that method chains can be too long. Some people call these chains "train wrecks". Obviously, this is a subjective matter, but one cannot deny that very long method chains are hard to debug. For example, here's one possible solution to problem 20:

(2..100).reduce(:*).to_s.scan(/./).map { |x| x.to_i }.reduce(:+)

This line simply:

  1. creates a range from 2 to 100 (1 is ignored in the factorial)
  2. calculate the factorial by multiplying them together
  3. convert it to a string
  4. create an array whose elements consist of single characters from the string (split("") also works)
  5. convert each element to integer
  6. calculates the sum of the elements

One way of debugging this long method chain would be to insert a tap method call to inspect the intermediate value of the chain. For example, if you do this:

(2..100).reduce(:*).to_s.scan(/./).map { |x| x.to_i }
.tap { |x| puts x.inspect }.reduce(:+)

you'll get the array of numbers before the reduce.

irb(main):001:0>(2..100).reduce(:*).to_s.scan(/./).map { |x| x.to_i }
.tap { |x| puts x.inspect }.reduce(:+)
[9, 3, 3, 2, 6, 2, 1, 5, 4, 4, 3, 9, 4, 4, 1, 5, 2, 6, 8, 1, 6, 9, 9, 2, 3, 8, 8
, 5, 6, 2, 6, 6, 7, 0, 0, 4, 9, 0, 7, 1, 5, 9, 6, 8, 2, 6, 4, 3, 8, 1, 6, 2, 1,
4, 6, 8, 5, 9, 2, 9, 6, 3, 8, 9, 5, 2, 1, 7, 5, 9, 9, 9, 9, 3, 2, 2, 9, 9, 1, 5,
 6, 0, 8, 9, 4, 1, 4, 6, 3, 9, 7, 6, 1, 5, 6, 5, 1, 8, 2, 8, 6, 2, 5, 3, 6, 9, 7
, 9, 2, 0, 8, 2, 7, 2, 2, 3, 7, 5, 8, 2, 5, 1, 1, 8, 5, 2, 1, 0, 9, 1, 6, 8, 6,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
=> 648

Not exactly pretty, nor is it the most interesting use of tap, but it still gets the work done.

As a bonus, I'd just like to share a realization I had a while back.

Web developers shouldn't have to have problems with list processing because they deal with lists all the time: in SQL!

Think about it, you can define filter options in WHERE clauses, while map and reduce can be done in the SELECT clause. Assuming you have a table numbers with a column number with 100 records, each corresponding to numbers from 1 to 100, problem 6 can be solved by the following SQL statement:

SELECT SUM(number) * SUM(number) - SUM(number * number) FROM numbers

In our age of rampant consumerism, it’s easy to fall into the trap of believing that you could only achieve great things only with the best equipment available.

There are two unfortunate side effects to this mentality:

  1. People who can’t get those equipment are discouraged from even trying out that field, and
  2. People who can get those equipment think they’re a lot better than they actually are.

But the reality is you don’t need to shell out tons of cash to be good at what you want to do. Ask any expert from any field, from the arts, to scientific fields, to sports, and they will all tell you one thing: focus on the basics.

Here’s what Freddie Wong (maker of famous After Effects heavy videos like Flower Warfare and Time Crisis) has to say about this:

continue reading…

Taylor and Deming

Whenever you’re reading books or watching presentations on management, two names are bound to show up.

continue reading…

Traffic lights highlight the importance of conventions. What would you do if you encounter a traffic light colored purple, white, and orange?

Like revision control, fresh graduates are introduced to the foreign concept of code conventions (or “coding standards”) once they enter professional software teams. As implied by the term, “code conventions” are a set of standards and guidelines that developers have to follow when coding in their software project.

Contrary to what many people think, code conventions are not there simply to make code style consistent throughout large projects with hundreds of thousands of lines of code. Nor is it simply an unnecessary tool used by senior developers to assert their control over the project that only complicates coding.

In fact, properly defined code conventions help manage complexity.

continue reading…

Pareto Principle

In the next few posts, I’ll be posting about other fundamentals that I have missed so that we could move on to better stuff (i.e. stuff that not everyone knows) by the time I reach the 100 post mark.

The Pareto Principle (also known by many names e.g. Law of the Vital Few, 80/20 Principle, etc.) is a widely observed phenomenon wherein 80% of the effects come from only 20% of the causes.

continue reading…

backhoe

No Silver Bullet tells us to be skeptical about claims of tools that can provide drastic improvements in productivity. What we can instead hope for from productivity tools are minor, yet still significant, improvements.

However, both lowering our expectations and going with proven technologies aren’t enough to receive productivity benefits when introducing a new tool. Many companies still fail because of a certain classic mistake: Lack of Training.

continue reading…

werewolf

Aside from Brooks’s Law, Fred Brooks is also famous for another so-called “law” in software engineering: the No Silver Bullet argument.

There is no single development, in either technology or management technique, which by itself promises even one order of magnitude [tenfold] improvement within a decade in productivity, in reliability, in simplicity.

continue reading…

It ought to be remembered that there is nothing more difficult to take in hand, more perilous to conduct, or more uncertain in its success, than to take the lead in the introduction of a new order of things. Because the innovator has for enemies all those who have done well under the old conditions, and lukewarm defenders in those who may do well under the new.

- Niccolò Machiavelli, “The Prince”

Anyone who has tried to institute change in an organization would eventually have to deal with the scenario mentioned in the above quote. It does, however, get worse than that.

continue reading…

  • Encapsulate what varies.
  • Favor composition over inheritance.
  • Program to interfaces, not implementations.
  • Strive for loosely couple designs between objects that interact.
  • Classes should be open for extension but closed for modification.
  • Depend on abstractions. Do not depend on concrete classes.
  • Only talk to your friends.
  • Don’t call us, we’ll call you.
  • A class should only have one reason to change.

Continuing from the basics of OO, we now move on to its principles. The list above is taken from the wonderful book Head First Design Patterns and it enumerates some of the most important principles in OO. I’ll explain briefly what each principle means below the cut.

continue reading…

laws
laws

Agile: In A Flash is a great source of software engineering tips regardless if you’re planning to go agile or not.

Out of the many flash cards in that site, I find the two cards above to be the most important to a novice software developer. It should make them feel less surprised when Brook’s Law or Hofstadter’s Law hits them from out of nowhere.