Categories
Developement

Pay or Stay: A Salary Intelligence Tool

Pay or Stay is an idea I came up with as a quick and easy app to help me brush up on my development skills after returning from a one-month backpacking trip across Europe.

The idea was to create a salary intelligence app to help empower those who are considering moving to another city. It will be a tool to find out what you need to earn in the city you want to live in to maintain the same standard of living + more.

I just recently moved from New York to San Francisco. Before my move, I have spent countless hours researching cost of living, average salary, taxes and other things in multiple cities when I was deciding where to move. So I thought, why not build something beautiful that does it all for me with one click and share it with others?

There are already salary calculators out there, but I wanted to do more than just spitting out a number. I wanted to provide related salary information that can be helpful as well. I wanted to create a beautiful and visual one-page “report” that is both informative and easy to understand (kind of like those credit score trackers or Mint.com reports); something people can use to do research on different cities or for their negotiations.

This app was originally called “Needle in a Haystack”. After sharing my initial idea with a few friends, they came up with the name “Pay or Stay”.

I spent three days working on this app, including research, backend development, frontend design, deployment, and bug fixes. The final outcome was not as feature-ful as I had envisioned due to the lack of public data available. I was discouraged by the lack of data at first, but I ended up letting go of some of my ideas and pivoted the app (multiple times).

With some creative workarounds, Pay or Stay ended up being pretty close to what I envisioned. Using the Cost of Living Index, Pay or Stay calculates what salary you need to earn in the city you want to live in to maintain the same standard of living you currently have. I’ve also implemented some additional features and laid it out in simple and beautiful mobile-responsive dashboard.

Check it out here: payorstay.tonymai.net

If I ever come back to this app in the future, some of my desired improvements will be:

  • Compare your salary to average salaries for specific job title and locations
  • Where you stand in the salary distribution for your job title and location
  • Historical salary data for specific job title and locations
  • How your salary compares to minimum wage for all locations
  • Refine calculations based on state and city taxes
  • More current Cost of Living index
  • More data points to cover more locations (both in the US and internationally)
  • Display sample pre-filled budgeting templates for both locations and calculate how much average disposable vs. discretionary income you will have
Categories
Dev Bootcamp

Wrapping up at DBC with “Bring Home To Mom”

It’s been an amazing 9 weeks at Dev Bootcamp. I’ve learn so much more than I thought I would in 9 weeks, and more importantly, made many new connections and friends. Each one of my cohortmates will do big things.

During the last week of DBC, we pitched ideas to the entire school and the best pitches were selected to become final projects. I couldn’t ask for a better team (Jonathan Berk, Sofie Garden, Kevin Ceballos, and me). We were all motivated, self-driven, and always the last to leave the building. I knew I could rely on each one of my teammates to push the project forward. In just 7 days, we’ve packed SO many features into our app while still keeping it simple and easy to use on the frontend.

Some of the technologies/frameworks we used include:

  • Ruby on Rails
  • PostgreSQL
  • Javascript
  • JQuery
  • AJAX
  • handlebars.js
  • Faye messaging system
  • HTML5
  • CSS3
  • Responsive Grid System
  • Stripe API
  • Twilio API
  • Cloudinary API
  • Rotten Tomatoes API
  • OMDB API

Some of the features include:

  • Create child profiles
  • Smart matching system based on filters and interests
  • Autocomplete
  • Dates dashboard
  • Design a date page
  • Choose a date experience
  • Real-time messaging system
  • Pre-fund dates
  • Text notifications
  • Responsive design
  • Asynchronous updates for best user experience and minimal page reloads

And finally, here is Bring Home To Mom (51min-104min):

I will miss you guys!

Before:

2015-04-16 18.10.32

After:

2015-04-23 04.10.08

Team Bring Home To Mom:

2015-04-24 12.19.35

Categories
Dev Bootcamp

Introducing: Nearby Meetups

I just finished Phase 2 of Dev Bootcamp! It’s crazy how much I learned in the past 6 weeks. Git, Ruby, Sinatra, Javascript, AJAX, OAuth… all these terms were foreign to much just a few months ago.

I’m just writing here to share a simple Sinatra app that I built for my personal project during Phase 2.

“Nearby Meetups” started out as a fun project that would help me solidify EVERYTHING that I’ve learned during my first 6 weeks of DBC as well as learning more technologies.

I like Meetup.com, but the user interface didn’t appeal to me, so I rarely used it. I like to see things visually – where the events are located, how popular they are, when they are taking place, etc. – all at one glance.

Enter “Nearby Meetups” (www.nearbymeetups.com), a web app that utilizes the data from Meetup.com and visually displays them in a way that I would like them to. This was originally just a project that I did to solidify my learning, but after presenting it to everyone at DBC, I’ve received a lot of positive feedback and request to open it up to the public so that they can use it, too.

I am open to all kinds of feedback, issues, suggestions, and feature requests – anything that will help improve this app and make it easier for you to use.

Anyway, I’m ready to go onto Phase 3 and finally learn Rails on my last few weeks here!

Categories
Dev Bootcamp

From Ruby Hashes to JavaScript Object Literals

From the perspective of someone who has a primer on Ruby and jumping onto JavaScript, I noticed something used very often in Ruby that is missing from JavaScript: Ruby Hashes. How can such a powerful data type not exist in other object-oriented languages? If you are also completely new to JavaScript and have the same question, fear not! There is something in JavaScript we can use to achieve the same features provided by Ruby Hashes: JavaScript Object Literals.

MDN defines an object literal as “a list of zero or more pairs of property names and associated values of an object.” As you can see from the definition, this is very similar to Ruby Hash‘s pairs of keys and associated values.

Here is a side-by-side comparison of creating, reading, changing, adding, and deleting a new JavaScript object literal versus a new Ruby hash literal:

JavaScript Object Literal:

//creating new JS object literal
var capitals = { spain: "Madrid",
  france: "Paris",
  italy: "Rome",
  hungary: "Budapest",
  germany: "Berlin"
};

//accessing JavaScript object value
capitals["france"]; //returns "Paris"
capitals["belgium"]; //returns undefined

//changing values
capitals["france"] = "Nice";

//adding a new property/value pair
capitals["russia"] = "Moscow";

//deleting a property/value pair
delete capitals["italy"];

//final result
console.log(capitals);
/*
prints:
{ spain: 'Madrid',
  france: 'Nice',
  hungary: 'Budapest',
  germany: 'Berlin',
  russia: 'Moscow' }
*/
Ruby Hash Literal:

#creating new Ruby Hash literal
capitals = { spain: "Madrid",
  france: "Paris",
  italy: "Rome",
  hungary: "Budapest",
  germany: "Berlin"
}

#accessing Ruby hash value
capitals[:france] #returns "Paris"
capitals[:belgium] # returns nil

#changing values
capitals[:france] = "Nice"

#adding a new key/value pair
capitals[:russia] = "Moscow"

#deleting a key/value pair
capitals.delete(:italy)

#final result
p capitals
=begin
prints:
{:spain=>"Madrid", :france=>"Nice", :hungary=>"Budapest", :germany=>"Berlin", :russia=>"Moscow"}
=end

See how similar they both are? Creating a JavaScript object literal is almost the same as creating a Ruby hash literal. It is important to note that while Ruby hash keys can be any data type (i.e. symbols, strings, integers, hashes, etc.), JavaScript object properties can only be variables. But they can point to any data type value, just like in Ruby hashes.

You can call a JavaScript object’s properties in a similar fashion as you would a Ruby hash‘s keys. Same with creating and deleting key/value and property/value pairs. Calling a non-existent key or property will return nil or undefined.

Note that while I used the bracket notation here to access and modify a JavaScript object’s properties, you can also use a dot notation. For a more in-depth explanation of the differences between the two types of notation, take a look at this medium article.

The next time you find yourself working with JavaScript and are looking to implement something similar to Ruby Hashes into your script, JavaScript object literals will fit the bill perfectly.

This blog has been initially published on tonymai.github.io.

Categories
Dev Bootcamp

Improperly-Used Variable Scopes are No Vacation

What Is Scope?

Scope refers to the reach or visibility of variables. In the object-oriented world, scope is very important. There are five types of variables/constant, each with varying levels of scope.

The different variable scopes are (in order of highest to lowest level of scope):

  • global variables
  • constants
  • class variables
  • instance variables
  • local variables

In objected-oriented design, you want classes and methods to have only single responsibilities. We don’t want to expose everything to everything. It would be a tangled mess to have all variables and methods available to all objects. This also creates a lot of dependencies. When you change one part of the code, you may need to change ten other parts of the code if they are all depending on the code that you are changing, creating a rippling effect. Using correct variable scopes to only expose what is needed helps reduce this problem.

Besides restricting access to other components of the code, scopes also keep the name space open. Since the variable is limited to its scope and is non-existent outside of it, you don’t have to worry about creating a variable with the same name and accidentally overwriting the previous assignment.

Let’s talk about each variable scope in more detail

Global Variables

Global variables have a global scope. They are available anywhere in the program. It is defined and called with a $ in front of the name (i.e. $global_variable = "I am a global variable").

Try not to use global variables unless it is absolutely necessary. There is almost always a way to substitute using global variables with something else. It is used often in functional programming, but is counter-intuitive to object-oriented programming (OOP) because it is doing exactly what OOP is designed to get rid of. Relying on global variables causes the program to become less flexible and harder to make changes to in the future. In OOP, each object should only expose what is needed; nothing more and nothing less (only expose what it does, not how it does it).

Constants

Constants also have a global scope. They start with a capital letter. The Ruby convention is to write it with in all caps and underscore (i.e. CONSTANT = "I am a constant"). If they are called from self, you only need to write the name of the constant, like local variables and methods. If you are calling from outside of self, you can still access it if you know the path of the block that defined the constant and :: (i.e. Math::PI).

Constants are not meant to be changed, but Ruby will allow it. If you choose to change a constant, Ruby will give you a warning and then make the change right afterwards.

Local Variables

Let’s jump to local variables before we talk about class and instance variables. If you’ve played with Ruby, then you’re probably already familiar with it. Local variables have a local scope and they start with a lowercase letter (i.e. local_variable = "I am a local variable"). Local variables are the most often used variables and are limited to the specific block it’s in and the blocks inside that block. They can’t be access from anywhere outside of the block.

For example:

class Destination
  def dest_1
    x = "Barcelona"
    puts x
  end
  def dest_2
    puts x
  end
end

trip = Destination.new 
trip.dest_1 # => "Barcelona"
trip.dest_2 # => undefined local variable or method `x' for #<Destination:0x007fe284058ae8> (NameError)

Or:

trip = ["Barcelona","Rome","Amsterdam"]
trip.each { |city| x = city; print x } # => BarcelonaRomeAmsterdam
print x # => undefined local variable or method `x' for main:Object (NameError)

As you can see, when the local variable is called outside of its block (in the first example, the Destination#dest_1 method block, and in the second example, the .each iterator block), it will create an error. Since the variable is out of scope, it does not exist in the block from which it is called upon.

Now, lets look at this example:

trip = ["Barcelona","Rome","Amsterdam"]
x = []
trip.each { |city| x = city; print x } # => "BarcelonaRomeAmsterdam"
p x # => "Amsterdam"

Something interested happens here. Notice how the last line now prints "Amsterdam", even though that was assigned inside the .each iterator block. Since x was first defined outside of the .each iterator block, the scope of the variable has changed. Remember what I said earlier: the scope of a local variable is limited to its block and the blocks within that block.

Instance Variables

Instance variables are only accessible to each specific instance. They begin with a @ symbol in front of the name. They are written inside instance methods and can be shared by all instance methods in that class. Since the scope of instance variables are restricted to each instance, different instances can have different values assigned to these variables.

Take this, for example:

class Destination
  def initialize(city)
    @city = city
  end
  def print_city
    puts @city
  end
end

trip_1 = Destination.new("Barcelona") 
trip_2 = Destination.new("Rome")
trip_1.print_city # => "Barcelona"
trip_2.print_city # => "Rome"

There are two things to note here. First, notice how @city is assigned in the Destination#initialize method and the assignment is still available in a different method, Destination#print_city (as evidenced by what the last 2 lines printed). The second thing to note is that @city for trip_1 is different from the @city for trip_2. Instance variables are the second most used variables in Ruby.

Class Variables

Class variables are accessible by the class and all instances of that class, so they have a wider scope than instance variables, but not as much as global variables. These variables have a @@ symbol in front of its name. They are often used if the class or any instance of the class will need to use it.

For example:

class Destination
  @@total_avail_cities = 0
  def initialize(city)
    @city = city
    @@total_avail_cities += 1
  end
  def print_total
    puts @@total_avail_cities
  end
end

trip_1 = Destination.new("Barcelona")
trip_1.print_total # => 1

trip_2 = Destination.new("Rome")
trip_2.print_total # => 2

Every time a new destination is initialized, it adds a count to @@total_avail_cities. Notice that even though trip_2 is a separate instance from trip_1, it still print 2.

Class variables are also avoided unless it is necessary. Similarly to global variables, not realizing its scope can be detrimental to your problem.

Here is an example:

class Destination
  def initialize(city)
    @@city = city
  end
  def print_city
    puts @@city
  end
end

trip_1 = Destination.new("Barcelona")
trip_2 = Destination.new("Rome")
trip_1.print_city # => "Rome"
trip_2.print_city# => "Rome"

Notice how both calls to print @@city returned "Rome". That is because the second instance changed the value of @@city when it was initialized, which carries over to all instances in that class. Be careful when using class variables and only use them when absolutely necessary.

Summary

Ruby has different types of variables that have varying levels of scope. The bigger the scope, the more careful you should be when using it. In object-oriented design, you only want what is absolutely needed to be accessible by others to make your program work, so don’t expose anything in an object that isn’t needed by others. Keep the scope in mind and choose which variables to use accordingly.

This blog has been initially published on tonymai.github.io.