It's Not a Waste of Time to Learn a Few Languages / Frameworks
Over the years I've learned a few languages / web frameworks and recently picked up Elixir / Phoenix. Here's what I've learned.
Before we get into this, let me just quickly mention something about Flask.
I’ve gotten a few emails lately asking me if I’m abandoning Flask because I put up a few Youtube videos over the last month talking about building a custom course hosting platform which I’m currently writing in Elixir / Phoenix.
The reason these emails are popping up is because I happen to have a Flask course. So it’s no surprise that folks who are taking that course see me using something different for my own projects. I would probably be weirded out if I saw that too.
That reminds me of a quote which is something like “Do as I do, not as I say” or maybe it was “Do as I say, not as I do”. In either case, don’t worry about it.
I’m not throwing Flask in the trash can, and I’m for sure still adding free updates to the course. I added 3 pretty big updates recently and I have ideas to add even more content / features to an already massive course (it’s 190+ lessons and has 16+ hours of videos).
It’s also still very much worth learning Flask today. Just last week I finished up an ~80 hour contract where someone specifically asked me to build them a Flask API service. Not only does the service work well but I had a lot of fun developing it.
I would say about 50% of the freelance work I do is related to Flask. I currently have 2 contracts going on as we speak, and both of them involve Flask in a very big way. The other 50% is mostly “devops” work and a microscopic amount of Rails.
What I’m trying to say is, there is no shortage of Flask work to be had and me learning Phoenix has nothing to do with Flask being bad or limited.
With that out of the way, let’s talk about why you might consider learning a new stack.
# Why Learn a New Language / Web Framework?
I don’t know about you but I don’t just wake up saying to myself “hey, today’s a fantastic day to drop everything I’m doing and learn a completely new language and web framework over the next couple of weeks”.
Typically as I’m developing projects and working with frameworks I am already using, I’m constantly asking myself questions about how things are going.
Basically I’m asking myself things like “am I having fun?” or “how nice or annoying is it to do XYZ?”. I’ll keep these answers in the back of my head and then I’ll eventually run into an article about how another tech stack solves the problems I’m having in a nicer way.
That’s really all there is to it. Learning something new for me is almost always driven by some type of personal struggle and then getting “lucky” by reading up on something new.
Now, I understand that’s not the case for everyone. A lot of folks are interested in finding employment and making a living (with good reason), so sometimes you have to make decisions based on what’s financially best. In my opinion learning Python / Flask is a much safer bet for finding employment than learning Elixir / Phoenix as of today.
In any case, learning the new technology will likely improve your skills with existing technologies you already know. Even if you decide not to embrace the thing you’re learning, you’ll still likely walk away with a few nuggets of wisdom that applies elsewhere.
That’s why I think learning a new language isn’t a waste of time. I’m totally fine with putting in a few years with some language and even if I decide to ditch it for something new, I get to take everything I learned in those few years and apply it to the new language.
But with that said, it’s very rare that I’ll immediately ditch the old thing after learning the new thing. I’ve been working with Flask for over half a decade and I still really like it and I don’t see myself throwing it away any time soon.
And on that note, only you can decide when and why to learn something new. We all have our own motivations. It’ll be different for everyone.
What caused me to learn Elixir / Phoenix?
When it came to picking and learning Elixir / Phoenix to build this course platform instead of using Flask it was a combination of websockets being kind of annoying in Flask and developing a project where I plan to do a lot of things with websockets.
But it was also the fact that I’ve been using Flask for a really long time. I’ll be completely honest with you here. I’m a human being, and like everyone else I get bored. I still have fun developing Flask projects but at the same time I wanted to learn something new.
That’s just how my personality is. I like to dabble in many different things.
It just felt like the timing was right to learn something new even though from a technical standpoint I could have definitely written the platform in Flask and it would have been solid. Actually, it would have been a much safer bet to use Flask, and it certainly would have gotten developed faster since I have so much well tested Flask code already written.
But when you have a personal itch to scratch by building a real project, that’s a really good time to learn something new. It’s the ultimate motivator. Just about every tech I’ve learned was due to building a decently sized personal project.
# Here’s What I’ve Learned from Previous Languages
I’ve been a software developer for about 20 years now and here’s a few things I remember learning from each language I picked up. None of these are really revolutionary or unique things only I can think of. But, they are concepts I still remember 20 years later.
Also, I’m sure some of the things I’ve learned with the languages listed below are things you’ve learned with other languages. That’s the interesting part. The language itself isn’t that important. The real takeaway is that you’re out there trying out new things and allowing your brain to work in different ways.
Keep in mind I’m self taught in the sense that I never went to University. Everything I learned came from self driven research on the internet or from people I’ve met along the way.
Visual Basic 6
This was the first language I learned. For the longest time I kept all of my code in each form’s file. Basically putting everything in each event handler. I had no idea about separating functionality from presentation. This would be almost like putting HTML, CSS, JS and your back-end programming logic all in 1 file.
Then I remember some guy on Yahoo chat in the mid / late 1990s explaining the concept of modules to me and I was blown away. This guy had a single module file that I could drop into my project and now suddenly I could use it in my project.
Modules were just a collection of functions. He had a module that allowed you to pass in input text and it would transform it so the text came out in rainbow colors. Hardcore 1990s script kiddie 101 stuff. It was glorious.
You have no idea how big of a mind shift that was for me at the time. It meant I could tuck away functionality in a different file and then use it somewhere else. It also meant avoiding duplication because I could call the function in 2 different areas of the code base.
ASP Classic
I’ve written about this in the past but a friend and I put together a Quake 3 gaming ladder in the early 2000s. He did a vast majority of the coding and I did the design work.
But working on that project eventually kick started me into developing dynamic web pages that were backed by a database. In fact, I would say this project was what got me into freelancing.
What I really took away here was much more than just technical knowledge. It was understanding that you don’t have to do what the world expects you to do. You don’t need to be another cog in the machine if you don’t want to. You can make your own destiny.
Sounds cheesy as hell, but that’s what I wanted. It just so happens ASP Classic was the tech that lead me to that. It basically comes down to timing. If that happened today, it would have been some other tech – whatever my first web technology would have been.
I only bring that up because sometimes the non-technical perks of learning a new language or web framework have the biggest impact on your life. Who knows what could happen. You might enjoy a new language, go-to a conference, meet someone there and now 2 years later you have a successful startup together.
Anyways, after working with ASP for a while I even wrote my own text editor with Visual Basic 6 and made an ASP site to host it. Here’s a feature list which I wrote back in 2002:
<TR>
<TD BGCOLOR="#FFFFFF" WIDTH="750">
<% =fontGroup %>
Just a few of the features:
<UL>
<LI>Unlimited fully customizable template files</LI>
<LI>Fully customizable syntax highlighting</LI>
<LI>Very customizable user interface</LI>
<LI>Color coded printing (optional)</LI>
<LI>Column selection abilities</LI>
<LI>Find / Replace by regular expressions</LI>
<LI>Block indent / outdent</LI>
<LI>Convert normal text to Ascii, Hex, and Binary</LI>
<LI>Repeat a string n amount of times</LI>
<LI>Windows Explorer-like file view (docked window)</LI>
<LI>Unlimited file history</LI>
<LI>Favorite groups and files</LI>
<LI>Unlimited private clipboard for each open document</LI>
<LI>Associate file types to be opened with this editor</LI>
<LI>Split the view of a document up to 4 ways</LI>
<LI>Code Complete (ie. IntelliSense)</LI>
<LI>Windows XP theme support</LI>
</UL>
Still unsure about trying it? Visit the <A HREF="screenshots.asp">screenshots</A> section.
</FONT>
</TD>
</TR>
Good times. Apparently I liked the word customizable back then!
.NET / CSharp
I really learned the value of having a good code editor. My custom code editor was fun to build but Visual Studio was in a world of its own. This was shortly after C# came out.
The main app I built with C# was a desktop app. It had to be very small but display a ton of information as well as allow me to input precise information into it very quickly. I really learned a lot about UI design here.
Ultimately it involved help figuring out what’s essential and what’s not. It also showed me the value in having strict constraints. You can’t just implement everything you want when you’re dealing with a finite area of the screen.
This is also where I learned how little I actually knew and how overly complicated you can make things if you try to create abstractions without knowing what the word even means.
PHP / LAMP / WordPress
Having learned how bad I was at abstractions I spent a lot time creating hand rolled PHP / MySQL / Apache driven websites without using any web frameworks or libraries. Everything was using PHP’s standard library.
I knew the mess I got myself into with C# so I went back to putting things into 1 file and that’s how I ended up with ~7,000 line PHP files with HTML, CSS, JS and MySQL queries:
if ($totalRows > 0) {
$r = $db->Select("SELECT id, uid, timestamp, title, link, description FROM schedule ORDER BY timestamp DESC LIMIT " . $limitMin . "," . $pageLimit);
if ($r) {
?>
<h2>Warning</h2>
<p>If you delete an event it will be gone forever.</p>
<table style="margin-bottom: 24px; margin-top: 24px;" id="view-events" class="dataView" cellspacing="0" cellpadding="0" border="0">
// ...
<?php
}
}
The scary thing is, ~12 years later this code is still successfully running in production. One nice thing about creating your own mess is, it’s your mess. Although fortunately I haven’t had to touch the app in close to 10 years.
Eventually I figured out about WordPress and learned that it’s possible to have a decent looking site with custom functionality without it being super difficult to reason about for the end user (ie., me, the developer).
This took me back to the VB6 days of modules where I can just drop in some code written by someone else and things just worked for the most part.
The main takeaway here is the community collective is strong. Even if it’s not the highest quality work ever, it got me to realize that there are other people out there in this world who are solving the same problems as I was.
Ruby on Rails
I got into Rails pretty late. I started with 4.0 so by this time the community was very mature.
The community as a whole really drove home the importance of automated tests and the idea of developer happiness. It was a huge step forward from WordPress where everyone just cobbled shit together until it worked.
Seeing a Rails project also taught me a lot more about abstractions and code separation. I realized it’s possible to keep things organized in a way that works on day 1 and even a year+ into a project without wanting to hate life (most of the time).
I could talk a lot about Rails but I don’t want to write a whole novel. But I learned a ton. Also a decent amount of non-technical lessons too. For instance, following DHH (the author of Rails) and seeing how passionate other developers can be to develop good software.
Even though I don’t write too much Rails code nowadays, I still look up to DHH and very much appreciate what he has done for web development as a whole.
Flask
Flask is almost the polar opposite of Rails. Rails is a big framework with lots of opinions and it imposes quite a bit on your project. Flask is a micro-framework with very few opinions and pretty much lets you do whatever you want.
This is great in some ways. You get to have more control over the end result at the cost of having to make more decisions, but these decisions might be worth having to make if it helps you build an app that’s easier to maintain in the future.
Flask taught me that it’s possible to build large applications in a way that scales, and by scaling I mean you can continue building on top of your app without it becoming hard to maintain.
The reason it taught me that is, with Rails you kind of just default to doing
things the Rails way because that’s what you’re told. This is how you end up
with a models/
folder that has 115 models in it and it’s really hard to see
how they all relate to each other unless you know the ins and out of everything
about the application.
With Flask, you can organize your project however you see fit. In theBuild a SAAS App with Flask course instead of organizing things like Rails, I went for a more component based approach using Flask blueprints.
That lead to organizing the application by what it does, not what it has. For example, here’s the directory structure for the main web app:
admin/
bet/
billing/
contact/
page/
user/
Those are all directories that have models, forms, views and whatever else each component needs to make it work. In my opinion, it’s much easier to glance at this code base and know where you need to go to edit something. It groups things up in a way that makes sense.
Like if you want to deal with Stripe payments or invoices, you would check out
the billing/
directory. You know where to go just by looking at directory
names and once you get there, you’re not overloaded with a million unrelated
files.
Some of the biggest applications I’ve ever built were with Flask and even today years later when I have to maintain them I know exactly where I need to go to make changes.
The main takeaway is I learned to trust myself. At this point I had ~15ish years worth of development experience before even touching Flask. Now, I’m not saying Flask is better than Rails. In all honesty, if I knew what I know now about application design I would have prevented the 115 models in a single directory problem with Rails.
And this is really a side topic, but it’s also why I think those articles that say things like “I rewrote my app in X from Y and now it’s way better” are kind of silly.
Of course it’s going to be better! You were able to start with years worth of experience about your domain that you didn’t have before. You can make way better decisions. In all but the extreme cases, the language is only a very small reason why your v2 app is better.
# How Did Elixir and Phoenix Make Me A Better Developer?
It’s no different than every other technology in that after I learned the basics with it and had a chance to write a somewhat decent amount of code with it, I walked away with things that I can apply to my Flask apps or anything else. I still consider myself an Elixir beginner too.
Phoenix really hammered home the importance of thinking about how to organize your application. Not so much the file structure, but the business logic / rules.
In Phoenix, they have this concept of a “context”, which is really just a way to organize your application’s business logic, or the things that make your app what it is but without introducing the web UI or web related bits.
You don’t have to use contexts since it’s not a feature. It’s more like a suggested way to organize your code. But I’m glad I am using them in the course hosting platform I’m building because understanding your domain is really important.
For example I have directories like this:
accounts/
affiliates/
enrollments/
gateways/
lms/
ordering/
promotions/
And inside of each of those directories have nothing but database schemas, input validation rules and things I would consider “internal implementation details”.
There’s not a single trace of web related code in there.
Then 1 directory back I have an accounts.ex
, affiliates.ex
,
enrollments.ex
and so on files that have functions which let me interact with
the underlying data model and anything else I need to create the business rules
of my application.
These files are what I would consider “public implementation details”. It’s what the web component of the app will access.
And then in a completely separate area of my app, I can focus on the web parts such as dealing with routes, controllers, templates and so on. It wouldn’t take much effort to create a CLI tool out of the app since all of the business logic is nicely tucked away in 1 spot.
This style of organization is what Phoenix suggests by default and I really dig it. At first I thought contexts were going to be a waste of time and add more boilerplate but now that I’ve embraced them, I see their real value.
Not only does it help organize your code but it forces you to think about your code in a very non-technical / deep way. Like, it took me hours to come up with the word promotions which deals with organizing things like discount codes, applying discounts and banners.
I could talk about this for hours, so I’ll save more details for a future post, but the takeaway here is Phoenix really taught me to focus more on my application’s logic and business rules than worry about underlying database relations and file organization.
And the cool thing is, you can totally apply this concept to other web frameworks too.
As for Elixir, well… having a functional programming language with pattern matching and immutable variables really makes you think about conditions in a different way.
It really helps you determine the potential states of what your code can be in, but in a way that feels natural and you can really apply this to Python / Flask or anything else.
Even if the language you’re using doesn’t support pattern matching, you can still approach the problem by breaking down the potential states, and then convert them into whatever conditional logic constructs your language supports.
For example, here’s a function that checks whether or not a user can enroll into a course:
def check_enrollable(nil, _package) do
# No user supplied? We have to assume they are enrollable.
{:ok, :able_to_enroll}
end
def check_enrollable("", _package) do
# No email supplied? We have to assume they are enrollable.
{:ok, :able_to_enroll}
end
def check_enrollable(email, package) when is_binary(email) do
case Accounts.get_by(email: email) do
nil ->
{:ok, :able_to_enroll}
user ->
check_enrollable(user, package)
end
end
def check_enrollable(user, package) do
enrollment = get_enrollment(user.id, package.course.id, [:package])
case enrollment do
%Enrollment{} ->
cond do
enrollment.package.id == package.id ->
{:error, :already_enrolled}
enrollment.package.tier > package.tier ->
{:error, :already_in_better_package}
true ->
package_price = package.discounted_price || package.price
enrollment_price =
enrollment.package.discounted_price || enrollment.package.price
upgrade_discount_amount = package_price - enrollment_price
{:ok, enrollment, upgrade_discount_amount}
end
_ ->
{:ok, :able_to_enroll}
end
end
I don’t want to get too deep into this, but those functions all have the same name and different “versions” of that function get executed based on what you pass in as arguments. This is pattern matching based on function arguments.
But ultimately these are just conditions or potential states of what the code
can be. For instance, if you don’t pass in an email address (the case where the
first argument is ""
) then we assume they can be enrolled because we know
nothing about the user account.
I’m hardly a pro with Elixir but breaking down the logic like that feels very very natural to me. It allowed me to understand my business rules in more detail.
I can do the same thing in Python by breaking down each input variation and what I want to do for each state. The implementation would look a lot different but that doesn’t matter too much in the end. It’s the process that’s important, and that carries over anywhere.
I could literally write 10,000 more words in this section but I think I’m going to call it a day for this post since that would delve too deep into Elixir specifics.
On that note, I will be writing more about Elixir in the future, and I will continue writing about and doing freelance Flask work too (along with everything else I usually post about).
You know, I could have never released those Youtube videos or even mentioned open sourcing the course platform (which I will be doing once it’s in MVP form and live) but then I think this blog would suffer a lot because I would feel like I have to hide that aspect of my development activity which is something I never want to do.
Almost every post on this site came from experience based on what I was currently doing at the time or in the past. If I didn’t write about Elixir, the upcoming course platform or things like that then I wouldn’t have anything too interesting to post about.
What are some things you’ve learned from prior languages? Let me know below!