So, many folks have asked me how I’m feeling after my work anniversary of three years has passed. Honestly, my initial reaction is, “well, it’s only three years!”. But it has come to my attention that for a lot of folks nowadays, three years is probably the longest they have been at a company.
A lot. That is a good thing; technology is an ever-changing field and if you want to stay relevant, you want to be consistently learning.
I was new to the information retrieval space, so learning about indexing and search ranking was such a joy. This may probably warrant its own section, but A/B testing is something I learned quite a bit about since my team tests just about everything.
I learned Elixir, which was my first functional language. I learned quite a bit about frontend technologies like React and NodeJS. I learned to be okay with pairing; I can’t say that I love it, but I don’t hate it.
Chef, Kubernetes, Docker were all new to me. Maybe these are a bit rudimentary for some folks, especially if you do not work on infrastructure and only do product work. But, if you like autonomy and work on just about anything, understanding the infrastructure that your code runs on is key for optimizing things.
This sounds cliche, but it’s true so I’m going to say it anyway; the people here are what makes it awesome. When you work at larger organizations, it’s easier to fade into the background. But in a smaller sized company, you’ll be able to find yourself making connections with everyone and knowing what they like, what they dislike, when they’re having a rough day, when they’re thriving and excited to push out new features.
The landscape has changed quite a bit. Well actually, a whole lot; we moved offices! I’ve honestly lost count on how many seats I’ve had along the years. But looking at our tech stack and our processes, it’s an entirely different place. I like to bring up the old ways of “deploy days” when someone new complains about our current deploy process pains. Yes, I said, “deploy days”; we didn’t do continuous deployment, we deployed code once a week with an assigned engineer to do the deployment. Things are nicer now, we have pretty decent processes in place and are constantly sending out surveys to find any pain points.
I think I’ve mentioned that three years is a pretty short time for me. But since folks asked if I was going to write up something, I could not disappoint. I have goals to give more talks and contribute more to the open source community. I also have a goal to write more often and not just focus on code. Crazy right? We’ll see if I can hold myself to that. Onward, cheers!
I recently had a conversation about Elixir since I have been using it more and it was not a language this person was familiar with. As curious engineers, one basic question that arose was, "what does Fibonacci look like?". I was happy to comply and provide some code.
As a quick refresher, we want to write a function that takes in an integer that represents the
nth number in the Fibonacci sequence. For this implementation, we're assuming that the input is a non-negative integer. Okay, let's go!
So the typical recursive solution has a function
fib(n) and we return an integer of 1 if
n is equal to 0 or 1 and otherwise, we want to recursively call
fib with the last two previous indexes.
def fib(0), do: 1 def fib(1), do: 1 def fib(n), do: fib(n-1) + fib(n-2)
Happy days! We just need three lines to implement this! Now, if you recall my previous post on Elixir function conditionals, that is the same thing we're doing here. We're returning 1 if we pass in a 0 or 1 index, otherwise we'll just do the recursive logic that we want. That's it!
"So what about an iterative solution?" you ask? Yes, that's actually what was discussed next anyhow. So, the typical solution for an iterative solution is to have a loop and have two variables track the
current values. So, that's fine, but something just felt wrong with that not being quite Elixir-y. So, I thought about it for a bit and came up with the following solution.
def iter_fib(0), do: 1 def iter_fib(1), do: 1 def iter_fib(index) do Enum.reduce(2..index, [1, 1], fn(_i, acc) -> # Calculate the Fibonacci value fib_val = # Take the accumulator acc # Flatten the list since we're appending fib_val by a new list |> List.flatten() # Sum those values |> Enum.sum() [Enum.take(acc, -1), fib_val] end) # This is now the Fibonacci value for the index and its previous value, so just take the last value |> List.last() endSo, what I've done here is create a list that represents the Fibonacci sequence. We have the same overloaded function signatures for index values of 0 and 1, and otherwise, the bulk of our code goes into our
Enum.reduce/3. What we are doing is constantly keeping the list length at 2 so we can easily just sum the values and compute the next Fibonacci value. My first implementation actually was a bit memory hungry because I was just appending my list continuously and then taking a sum of the last two values. Why keep the list long if you only want to compute that last value right?
That's it! Plain. Simple. Memory smart. Anyhow, you can checkout the full source here in this gist. Cheers!
So, I've been learning and doing a bit more Elixir lately. I'm only a couple months in, but Elixir has been the primary language I have been coding in at work. Happy days!
This is not an introductory write-up nor a tutorial, but rather a quick look at how conditionals and guards are done in Elixir. Onward.
So, yes, FizzBuzz; the classic programming problem and still a favourite interview question. As a quick refresher, this game is played by counting from one through n, but for multiples of three, we'll have "Fizz", multiples of five, "Buzz", and multiples of both, "FizzBuzz". I think that is the simplest I can word it.
Let's have a look at an example in Python first.
def fizz_buzz(n): if 0 == (n % 3) and 0 == (n % 5): return "FizzBuzz" elif 0 == (n % 3): return "Fizz" elif 0 == (n % 5): return "Buzz" else: return str(n)There is nothing crazy going on here, the logic is simple and it does exactly what we need it to. It uses the usual
if/elselogic that you would expect.
So, now let's look at a solution in Elixir.
def fizz_buzz(n) when 0 === rem(n, 3) and 0 === rem(n, 5) do "FizzBuzz" end def fizz_buzz(n) when 0 === rem(n, 3), do: "Fizz" def fizz_buzz(n) when 0 === rem(n, 5), do: "Buzz" def fizz_buzz(n), do: nIf you've never done any Elixir before, I'm sure you may be a bit confused.
So, let me first say that, yes,
if/else does exist in Elixir. "Then, why isn't it used here at all?", you ask? Well, Elixir has a good foundation of having their functions be explicit in what they do and being able to pipe your code is very useful. I won't write much about the pipe operator here, but if you don't know much about it in Elixir, I highly recommend learning about it.
So what we see in the Elixir FizzBuzz is an overloaded
fizz_buzz/1 function. As I'm sure you've looked at it and studied it a bit by now, yes, that is being done in lieu of
if/else. The important piece is the
when part of the function signature which is called a guard. Using guards, we now have logic for which function we want to match on when we pass in the variable
n. So now we see that each function signature matches up exactly to what we have done in Python with
if/elif/else logic. Pretty neat eh?