API > CLI > Space Exploration 
Tags: ruby, oop, cli, api
Published: 2020-09-15 23:44:46

I could not be more excited for my first capstone project at Flatiron School. Eight weeks flew by in the blink of an eye!

My husband and I recently watched the 2014 science documentary [Cosmos: A Spacetime Odyssey](https://en.wikipedia.org/wiki/Cosmos:_A_Spacetime_Odyssey), presented by astrophysicist Neil deGrasse Tyson. I am amazed by Tyson's storytelling approach through this so-called "Ship of the Imagination", where he travels beyond space and time to explore and explain the cosmos. The documentary series contributed to my CLI (Command-Line Interface) project domain modeling, **Space Exploration**.

![Screen_Shot_2020-09-13_at_10.26.09_AM](https://dev-to-uploads.s3.amazonaws.com/i/aww5l98dys0g5nj736ol.png) 
  
  
####**RESTful API search**

The next fun exercise would be finding the appropriate data either scraping from HTML, or fetching remote data sources from RESTful API. I discovered two APIs that I really like. One provided me with Planetary data, and the other provided Spacecraft data (powered by SpaceX). My first approach was to retrieve these remote data sources, and manipulate the data within my domain modeling.

```ruby
class API 
    
    def self.space_data
        url = 'https://...'
        uri = URI.parse(url)
        response = Net::HTTP.get_response(uri)
        response.body
                
        space_data = JSON.parse(response.body)["bodies"]
    end 
	# => 'json' module returns Ruby hashes with key and value pairs

    def self.planets
        planets = []

        space_data.each do |data|
            if data["isPlanet"] == true
                planets << data["englishName"]
            end 
        end 

        planets 
    end 
	# => ["1 Ceres", "136199 Eris", "Uranus", "Pluto", "Neptune",...
    
    def self.planet_info(name)
        space_data.detect do |data|
            if data["englishName"] == name 
                puts "Name: " + data["englishName"].to_s
                puts "  Mean Radius: " + data["meanRadius"].to_s + " kilometres"
                puts "  Density: " + data["density"].to_s + " g.cm3"
                puts "  Gravity: " + data["gravity"].to_s + " m.s-2"
                puts "  Perihelion: " + data["perihelion"].to_s + " kilometres"
                puts "  Aphelion: " + data["aphelion"].to_s + " kilometres"
                if data["discoveredBy"] != ""
                    puts "  Discovered by: " + data["discoveredBy"].to_s
                end 
                if data["discoveryDate"] != ""
                    puts "  Discovery Date: " + data["discoveryDate"].to_s
                end 
            end 
        end 
    end 
	# => self.planet_info("Uranus")
	# => Name: Uranus
  	# => Mean Radius: 25362.0 kilometres
  	# => Density: 1.27 g.cm3
  	# => Gravity: 8.87 m.s-2
  	# => Perihelion: 2734998229 kilometres
  	# => Aphelion: 3006318143 kilometres
  	# => Discovered by: William Herschel
  	# => Discovery Date: 13/03/1781

    def self.spacecraft
        url = 'https://...'
        uri = URI.parse(url)
        response = Net::HTTP.get_response(uri)
        response.body

        spacecraft = JSON.parse(response.body)
    end
	# => 'json' module returns Ruby hashes with key and value pairs
    
    def self.spacecraft_info 
        spacecraft.each do |ship|
            puts ship["rocket_name"].to_s 
            puts ship["description"].to_s
            puts "  Height: " + ship["height"]["feet"].to_s + " feet"
            puts "  Mass: " + ship["mass"]["lb"].to_s + " lbs"
            puts "  Success Rate: " + ship["success_rate_pct"].to_s + "%"
        end 
        nil 
    end 
	# => Falcon 1
	# => The Falcon 1 was an expendable launch system privately developed and...
	# =>   Height: 73 feet
	# =>   Mass: 66460 lbs
	# =>   Success Rate: 40%
	# => Falcon 9
	# => Falcon 9 is a two-stage rocket designed and manufactured by SpaceX...
	# => ..

end
```

####**Domain Modeling Design**

There are 3 main model (or classes). They are Astronaut, Spacecraft and Planet. The three main object relationships between one another are as follows:

  Astronaut *has many* Spacecraft 
  Astronaut visits many Planets *via* Spacecraft

  Spacecraft *belongs-to* Astronaut, or *has-many* Astronauts
  Spacecraft lands on Planet(s)

  Planet *belongs to* Spacecraft 
  Planet *has-many* Astronauts *via* Spacecraft 

The SpaceExploration::CLI class allows the user to interface within the domain modeling, while the API class is responsible for providing responses to the user. I created a diagram of the overall control flow where it displays each class' responsibility. The *belongs-to* and *has-many* relationships are mimicking real world space exploration.

![Space-Exp Diagram](https://dev-to-uploads.s3.amazonaws.com/i/b48dymaem67gh9skuyh3.jpg)

The journey begins at the International Space Station. The user, an **Astronaut**, will enter his/her name and years of space traveling experience. The user has an additional option to add another astronaut forming a crew. There will be 3 readily-available **Spacecraft** selections. They are SpaceX spacecraft, and the data is provided by SpaceX RESTful API. The user will have the option to select **[Planet](https://en.wikipedia.org/wiki/Planet), [Dwarf Planet or Asteroid](https://en.wikipedia.org/wiki/Dwarf_planet#:~:text=The%20upper%20and%20lower%20size,classified%20as%20a%20dwarf%20planet.)** as a destination. Individual planetary attributes are limited to [our Solar System](https://api.le-systeme-solaire.net/en/) in the Milky Way galaxy. The spacecraft will not be able to make its landing when the planet's gravity is equivalent to 0.0. The journey does not stop as the astronaut and/or the space crew arrive at their first destination. It will be a continuous loop of traveling options to other destinations, starting with the closest planet based on the user's current position. There are a total of 13 planets, and 273 dwarf planets and/or asteroids. If the spacecraft success rate is less than 50%, the space crew need to re-route back to the International Space Station, and select a different spacecraft. The user will also have another additional option to add another astronaut. Once the user completes his/her space travel, the whole space crew will return to the International Space Station with a summary record of astronauts list involved in this mission, spacecraft selected, and planets visited. 

####**Setting up Ruby environment**

I have to admit that setting up Ruby `gemspec` and `config/environment.rb` took me a while. I decided to watch a few video tutorials, learned simple bash commands, and found [this tutorial video](https://www.youtube.com/watch?v=KwBMwZ89Hj8&list=PLc6AmvC5Zybybc-NjUUwQwTtUEXH4iB2s&index=2&t=0s) highly useful in setting up a basic Ruby environment. I set up `./bin/console` as my immediate IRB session, which has been very useful in testing every single class and instance method, along with `binding.pry` especially when manipulating remote data sources. They became my Ruby's best friends. The `./bin/space_exploration` would be the user starting point, triggering `SpaceExploration::CLI.new`.

There are a few fun Ruby gems that I explored. `require_all` is useful in lieu of repetitively utilizing `require_relative`. Few gems for fetching remote data sources include `open-uri`, `net/http`, and `json`. I am an architect, and design plays a huge role in what I do. I believe the better user interface I provide, the better the user experience in interacting with my application. `colorize` and `lolize` are amazing Ruby gems to add more colors. I plan to explore more Ruby gems post submission.

On a side note, learning `git` was another personal milestone achievement. I am now more comfortable with submitting my repo to GitHub manually, and understanding git in general. I was advised to keep my GitHub repo organized early as there will be more repo submissions as time progresses. 

####**Command-Line Interface, Class and Module**

The main challenge when developing the API, CLI, and other Classes was assigning responsibilities. There were a few times where I assigned class and instance methods incorrectly as it became more complex. Each model or class has its own sets of behaviors and attributes, and it is prudent to understand where each set belongs to which class. Re-factoring codes became an essential daily routine in order to maintain DRY (Don't-Repeat-Yourself) codes. The module was created to absorb any repetitive code occurring in each Class. It was another re-factoring exercise worth re-visiting once object relationships were defined. 

After a week of ferociously coding my way through project completion, I went back and re-assessed my overall object relationships. I found myself spending a tremendous amount of time on my CLI class. This is where most of my code resides. One example is setting up `if` / `else` or `case` / `when` conditions for various user inputs. It forced me to create additional instance methods in order to loop-back to the original instance method when receiving *invalid* user inputs. This is useful in order to avoid jeopardizing the logic of the other methods that perceive *valid* feedback. 

Overall, I am happy to be able to immerse myself in greater depths of understanding *Ruby: Object-Oriented Programming (OOP)*. I recall last month that I only grasped basic Ruby procedural programming concepts. Ruby OOP is robust in its practical application from object relationships and architecture to meta-programming. I cannot wait to learn what Flatiron School has to offer next. 

{% youtube Yz5csbK1sdc %}

{% github fentyhall/mod1_cli_space_exploration %}

***

Post Scriptum:
This is my Module 1 capstone project with Flatiron School. I believe one of the catalyst to becoming a good programmer is to welcome constructive criticism. Feel free to drop a message. 🙂

Keep Calm, and Code On. 

External Sources:
[Wikipedia](https://www.wikipedia.org/)
[ASCII Art Archive](https://www.asciiart.eu/)
[CLI Live Project Build: Part 1](https://www.youtube.com/watch?v=KwBMwZ89Hj8&list=PLc6AmvC5Zybybc-NjUUwQwTtUEXH4iB2s&index=2&t=0s)

***
<center>[**fentybit**](https://fentybit.me/) | [GitHub](https://github.com/fentybit) | [Twitter](https://twitter.com/fentybit) | [LinkedIn](https://www.linkedin.com/in/fentybit/)</center>