It has been a busy several weeks and I’ve written just as lengthy of a blog post as last time from all of it. After deploying my Rails app, I switched gears to refocus on Sun Finder (through an indirect route). I signed up to present the app at SheCodes Conference on August 9th (yesterday) and I wanted to spiff it up a bit.
Flask Mega Tutorial (detour)
Before going back to Sun Finder, I spent a week finally going through the Flask Mega Tutorial which I had wanted to do since March. I highly recommend it because it goes from setting up a virtual environment through full stack development to a variety of deployment options. Going through that after the Rails tutorial was valuable because it solidified common concepts around web application structure (e.g. configuration, app instance setup, db setup and integration, where to delineate between view and controller). And of course it was helpful to contrast the differences to better understand how much Rails does for you behind the scenes.
The tutorial was great to help me work through a full Flask implementation on Heroku. I wanted to go through this so I would be able to better navigate how to finally deploy Sun Finder. Additionally, Flask Mega covered a couple concepts that I hadn’t seen yet and I was pretty excited to learn:
OpenId allows using one username and password to login to multiple websites. This is also known as decentralized authentication standard. Flask provides a package for easy integration, and the benefits of course are to simplify the number of logins that users need for all these websites. To note, OpenId is not OAuth which is another login concept that sometimes gets confused with OpenId. They can be used together or separately. OAuth authorizes one website to have access to another website’s data about a user (e.g. Facebook and Spotify) while OpenId is just a single login sans data sharing. Some key benefits of logging in with these applications are you don’t have to deal with password storage security, validation and resets. Its basically outsourcing your site’s login.
FlaskBabel is a package that determines the primary language (e.g. Spanish) set in the client’s browser and then displays the site in that language. Granted there is some setup including translation efforts to get this to work, but once it is setup, the web application becomes multi-lingual.
Moment.js is a more user-friendly date time rendering library that uses the client’s browser to track and display time based on her/his time settings. This is a better way to display time because it will adjust to user preferences from zone to whether to use a 24 hour clock and/or the order of month, day, & year. The server-side can store events based on utc timestamp, but when displaying date time on the client’s browser, the utc timestamp will be converted by Moment.js.
Coverage.py measures code coverage by providing an easy to use report that notes which parts of the code have been tested. This is such a great package to use because figuring out the balance of how much to test is tough and this really gives a good understanding of where there are gaps to help pinpoint what tests to add. It’s also really easy to add in this package.
Last on my list, the tutorial went over how to set up your own server. I actually skipped this section for now because I needed to get back to Sun Finder and Miguel warned it would be a long chapter for the uninitiated. I’m definitely going to complete that chapter because as always I want to learn about everything and I think setting up a personal server sounds fun.
On the whole the tutorial was great to reinforce concepts I’ve learned so far as well as expand my exposure to new ways to work. I’m a big believer in practice makes perfect in this space and going through this process as much as possible will hone skills over time.
Return to Sun Finder
So I finally opened up Sun Finder again and I really hated it when I got back to it. I could see how much I didn’t know when I had written it. I felt like there were so many obvious flaws that it’s a wonder I got any interviews at all after career day.
After hating on it for a bit and having a hard time reviewing where I left off, I talked with a few people who have been in the industry for a while about the fact that this is typical. We write code, we learn and we see all the flaws in what we wrote before (we also wonder what we were thinking when we wrote it) because we are always learning and growing. So my focus needs to be on how far I’ve come. I mean really, I did start coding in late Feb. Building a full stack app in 4 weeks between April and May was and is impressive no matter how noobie it its. And the fact that I saw so many ways to improve it reinforced how much I have learned.
Standard App Structure
I did find that I wasn’t afraid to completely rip up what I had started with and rework the whole thing. That used to be a problem for me back in May because changes completely threw me since I didn’t have as solid grasp on site structure and functionality. This time I literally overhauled my project to align the Flask Mega structure so it would function like other apps and be setup for deployment.
Reworking the structure was a challenge because Flask Mega recommended using an extension package that preconfigured SQLAlchemy vs. direct interaction (my setup back in May). The main difference is that the extension takes care of some of the configuration especially running and maintaining the database session (accessing and storing data). A little more specifically, the package generates a SQLAlchemy object when the application is passed into it. Using the package vs. working directly with SQLAlchemy gives access to all the same functions, a preconfigured scoped session, the engine and a declarative base that is a configured Model baseclass with a query attribute. To note, the session still needs to be committed when working with a database, but it doesn’t need to be removed at the end of a request.
Additional tricky bits included the fact that Flask Mega focused on applying SQLite throughout the tutorial and I already had Postgres setup with my project. SQLite is directly integrated into the web application for local storage while Postgres works separately and requires an adapter (e.g. psycopg) to integrate with the web app. The main change I needed in my code from Flask Mega was that instead of writing the database reference to a file in my web app folder like below:
- SQLALCHEMY_DATABASE_URI = ‘sqlite:///’ + os.path.join(basedir, ‘app.db’)
I needed to write it the code to point to the location of my separate postgres database as noted:
- SQLALCHEMY_DATABASE_URI = ‘postgresql://localhost/sun_finder_db’
A couple clarifying points, the os.path.join is just pulling the directory path for where the application is stored using basedir variable and app.db is the SQLite db file which is the equivalent to the Postgres db file named sun_finder_db. I left the SQLite code the same as what you would see in Flask Meg in case you reference that setup.
The real improvement came from the fact that I no longer passed the full contents of the database into the view and then looped through it to create and display the list of predictive text in my search bar. In May, I had been really proud when I first built that functionality out because it was what I understood at the time and it worked. This time, I understood how to pass the request from the view through the Ajax call and build a targeted list on the server-side that would feed back directly to the Ajax request and then post to the view. This is a much more optimized solution especially when I grow out the list of database location names so I only pass a small amount of data vs. everything.
I actually started getting obsessed with Ajax to the point where I wanted to load everything on one page. This is a bit complex and unfortunately, I hit a couple of walls that were too difficult to get past in time for the SheCodes conference. So in the interest of time, I ended up rolling back my one page concept to loading separate views for each request. Basically its a full page load based on most of the links that are pushed. It’s not as elegant or efficient but it works. I also get that I have to try lots of things and sometimes go back to square one before making progress. Its part of the learning process.
Sunrise & Sunset Data:
I pulled out the Forecast.io API because I have known for a while I wanted to focus on WeatherUnder Ground results. In so doing, I managed to lose my data points on sunrise and sunset which I used to help determine whether to show a sun or moon image for the results. Now it seems the easiest thing would be to leave the use of the Forecast.io API, but I wanted to pull it out. I thought it would be easy data to find. However, not as easy as I would expect.
I tried the PyEphem package to calculate the times based on given coordinates. The results unfortunately were not accurate; thus, I switched gears to apply the Earthtools API. In so doing, I had to learn how to parse XML data which is good to learn, but it just was one of those moments of, “there has got to be an easier way to do this.” And fyi, Json is definitely easier to manage.
I applied the BeautifulSoup package to help parse XML. There are many parsers out there. I just picked BeautifulSoup because I was familiar with the name. Still this proved tricky to do and it took some time to realize that the XML response was an object and it needed to be converted to a string in order for BeautifulSoup to process it. Note, I use the requests HTTP library vs. urllib2 to pull API data. So when I run request.get on the earthtools url, I get back a response object. In order to get to the XML content, I actually have to pass the content attribute on the response object instance. So if I assign what earthtools sends back to a variable name earth_response then I have to pass that variable into the BeautifulSoup object as BeautifulSoup(earth_response.content) to get it to parse the response.
I added the Bootstrap modal plugin (after unsuccessfully loading the pop-up plugin) to show a Google map when the map icon is clicked. I have further plans for this feature mentioned below. What I was able to accomplish for now is that I’ve added the HTML5 Geolocation API to pull the coordinates from the client’s browser. These coordinates are used to build the initial map which can be seen when clicking the map icon. It was easy to setup and cool to see in action.
Some additional changes that I made were to stop passing all content to all pages now that I have a better handle on the view setup and what data I needed where. I also started to update the user login information based on what I learned from Flask Mega, but I tabled the further adjustments till after the conference. I fixed view content, improved page and variable names for clarity and added Coverage.py in anticipation of applying tests.
There were a number of changes that I made and what was funny is that despite all that work, the front-end view actually hasn’t changed that much.
Presenting the app at SheCodes was good practice in technical demonstrations, and in general, I really enjoyed the conference with the type of speakers and content covered. I created a couple slides that diagram the high-level MVC (model view controller) setup for my application and the difference technologies and resources that I’ve used so far. Those slides can be found on Speakerdeck. And if you want to see visual samples of the site, they can be found at nyghtowl.github.io.
I am pseudo proud of it again. I say pseudo because I will always have things I want to improve and it will never be perfect but apparently that is fairly standard with coding. My appreciation for the web app is in the fact that it has shown me how far I’ve come and gives me a space to continue to experiment and grow.
What I haven’t Finished Yet
Deployment is the Devil
So deployment is hard and I kinda hate it. I actually am still working on that as we speak because my deployment involves S3 and there is something special you have to do with static assets that Flask Mega didn’t cover. Lets just say that Rails is so much easier for this and I’ve heard the same about Django. Plus, my previous deployments didn’t require the kind of configuration I’m dealing with. My app is such a simple solution that it makes me laugh at the complexity of what I have to do to get it to work. Still I will deploy. Its going to happen come hell or high water, and I will post up what I learned from that experience once I get there.