Introduction to Scala

I signed myself up to teach a Scala class through Girl Develop It Pittsburgh a few months ago and the class was supposed to be tomorrow. I say "supposed to" because we only had two people sign up, so we ended up canceling. However, I still made a presentation! And since I spent all that time on a presentation, I decided to make a set of screencasts to accompany that presentation. If you've ever been interested in trying out Scala, I hope this helps. If you need any help or want me to go through some other aspect of Scala, feel free to contact me.

Find the rest of the series here.

On Being An Abrasive Woman (In Tech)

It's story time, y'all! All the names have been changed.

One of my earlier jobs, I worked at a company that had the family vibe. Everyone hung out together, and we were all "friends." The company also really valued "niceness." I put that in quotes because the people who tended to get pinged for not being nice were women about 80-90% of the time. Heck, there was a guy who would regularly tell people they were "fucking stupid" and we'd laugh it off.   At this company, my team consisted of:

  • My manager (Peter)
  • A guy who had been on the team for a year (Keenan)
  • A guy who had been with the company for a long time but just joined the team (Erlich)
  • And me

For a while, I really liked my manager and my team. The one caveat was Erlich who, like his namesake, was a total creep. He could be funny, but he was distracting and disruptive and just generally skeeved me out. For about six months, Keenan, Erlich, and I shared an office. Then a new developer joined the team (Richard) and I moved into an office with him. It was a lot quieter, and I got so much done. After another six months, Richard was let go. I went to Peter and requested that I stay in an office with this other guy on a related team, instead of moving back into the office with Erlich. I told Peter that Erlich was distracting and he creeped me out, and I would be more comfortable not sharing an office with him for 6-8 hours every day.

I went on vacation a few days later, and while I was on vacation, Erlich was let go. I was a bit concerned about the timing, but he was also a shitty employee! So I didn't think it had anything to do with what I said. However, after I get back, Keenan starts treating me differently. I’m making a presentation to explain what we do to support, and I’m supposed to get feedback from him. I go back to Keenan at least five different times, and every time he tells me to make some other big change. Every time, I make the changes, but every time, it’s not enough.

Then Keenan reports me to Peter for being abrasive. I can't remember the exact content of the email I got from Peter (which had HR copied), but it made it sound like I had cussed out this other guy on our team (Nelson) and I had to wrack my brain for what I said. I kept wondering if I had blacked out and forgotten saying something horrible. When I finally remember, I realized all I said was a rather direct “no, you’re wrong.” I got reported to HR for telling a coworker they were wrong. I talked to Peter about it, and he apologized to me and said he should have spoken to me first, but at that point, I realized I would probably just have to switch jobs.

I've seen this double-standard exist in many places, but that was the most egregious. Maybe a month or so before this I had been eating lunch when Keenan decided to make the argument that "people with downs syndrome aren't people," and yet I was considered offensive for telling a man they were wrong.

I don't have a summary for this story. It's just one I need to tell in hopes that it will make others consider more carefully how they are treating their female colleagues.

Getting Started With Play After Working In Rails

I've now been using Scala since November (so a little over 4 months) and Play since January (exactly two months today). When I first started writing this application, I was brand new to Scala. My boss recommended Scalatra since he had some experience. Since I had none, I agreed and got started. I learn by example, so I first went through and found some projects that I could look at and base my project off. With Rails, this was easy. The Rails Guides are FANTASTIC (I miss them so much). With Scalatra, this was much more challenging. I made some progress, but then I came to a screeching halt, which caused my boss to post to Reddit asking for suggestions. Lemme pull out some of my favorite comments:

On stack overflow there are around ~250 questions tagged with scalatra. There are around 15k play framework related questions. You're pretty much on your own if you go scalatra.
Akka HTTP you pretty much have to have a PhD to understand.
Play lacks a coherent, functional API, documentation for a good 60% of it, and completely lacks the composability and ease of use of alternative frameworks like http4s. Most of these problems with Play are due to poor planning, and being a Lightbend technology which is contorted to work with Akka(and akka-http), yet another poor Lightbend tech. It's a pervasive rot in the community, just like Akka.

GREEEAAAAAAATTTTT. Anyway, we decided to try Play It has documentation (the bar, it is low), at least one book written about it, and some decent templates. I migrated my project over to Play and got going. One of the major differences I noticed between Play and Rails is that Play is not very opinionated. In general, if you look at a Rails project, everything is generally in the same place. Pretty much everyone uses ActiveRecord and the RDMS you choose doesn't really matter. With pretty much any Rails project, you can initialize the database with rake db:create. This is not the case for Play. As far as I can tell, you have to create the database and then Play will run evolutions (migrations). The real problem I have is that there also is no standard. Slick is very popular, but we decided to use the newer kid in class, Quill. And I couldn't find a single example of someone using Play 2.6, Quill, and PostgreSQL. And Play 2.6 is a breaking release from Play 2.5. I found one template that used Play 2.5, Quill, and PostgreSQL, but it broke when I upgraded to Play 2.6. Right now I'm having some database connectivity issues, but I'm hoping to resolve those soon. As soon as I get the app working, I'm going to create a template so hopefully, others won't have as hard of a time as I have.

Overall, I sorta wish I was still working in Rails? I love the simplicity of Ruby and how easy Rails makes it to get a decent CRUD app up and running. It definitely would have only taken me one week to make this app in Rails and it's taken four months (and counting) in Scala.

The Fuck: The CLI App You Didn't Know You Were Missing

Everyone has days where they constantly mistype things and their muscle memory is failing them. Enter fuck. It's a CLI app that allows devs to type out what they are actually thinking to get the command that they actually want. If you mistype a command (like chiwn instead of chown), all you need to do is type fuck next and it will correct your command and then run it. Here's an example gif:

out.gif

Option and Either in Scala

I'm used to Ruby. In Ruby, you can use nil with abandon and just do something like if variable to check if it exists. Below is valid Ruby code (though forgive me if I'm now out of practice):

1
2
3
4
5
6
7
def displayUser(user)
  if user
    user.name
  else
    "No name"
  end
end

When I started on this project, I started treating Scala the same way. However, I found out that apparently you want to avoid using null in Scala. My first iteration prior to discovering this was the following:

1
2
3
4
5
6
7
def displayUser(user: User = null): String = {
  if(user != null) {
    return user.name
  } else {
    return "No name"
  }
}

This is not proper Scala. Unlike Ruby, Scala has Option. Option allows you to have Some or None. As you might expect, Some has a value, while None is the equivalent of null. Here's an example of how to do that same function properly:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def displayUser(user: Option[User] = None): String = {
  if(user.isDefined) {
    return user.get.name
  } else {
    return "No name"
  }
}
// call it like this
user = User()
displayUser(Some[user]) //or
displayUser()

Either provides a similar function to Option but is better for returning error messages. The problem I was trying to solve was creating an organization user. For that to happen, there must be an organization and a user. Here's my inital way I did it, thinking as a rubyist:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def validateUserAndOrgExist(email: String, orgId: Long): (Organization, User, Boolean, String) = {
  val user = usersService.findByEmail(email).head
  val organization = organizationsService.find(orgId).head
  if (user == null) {
    return (null, null, false, "User does not exist. Please create user first.")
  } else if (organization == null) {
    return (null, null, false, "Organization does not exist. Please create organization first.")
  } else {
    return (organization, user, true, "both exist")
  }
}

However, the better option (hehe) is to use Either in this case. So here's the better way to do this same function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
trait ValidationError { val message: String}
case class IdentifierNotFound(message: String) extends ValidationError

def validateUserAndOrgExist(name: String, orgId: Long): Either[IdentifierNotFound, (Organization, User)] = {
  val user = usersService.findByEmail(name).headOption
  val organization = organizationsService.find(orgId).headOption
  if (user.isEmpty) {
    Left(IdentifierNotFound("User does not exist. Please create user first."))
  } else if (organization.isEmpty) {
    Left(IdentifierNotFound("Organization does not exist. Please create organization first."))
  } else {
    Right((organization.get, user.get))
  }
}
// then call it and use it like this:
val validationOfUserOrg = validateUserAndOrgExist("test", 123)
if(validationOfUserOrg.isRight){
  val (organization, user) = validationOfUserOrg.right.get
  print("User $user.name is in Organization $organization.id.")
} else {
  print(validationOfUserOrg.left.get.message)
}

And that's how you use Either and Option!

The TL;DR on tldr

There's a new package out that simplifies man pages and it's GREAT: tldr. Here's an example:

Screen Shot 2017-11-30 at 8.23.14 AM.png

tldr doesn't include every command, but it's growing with community support. Install it one of the following ways:

npm install -g tldr
brew install tldr
gem install tldrb
pip install tldr

There are many more ways to install, so if one of those doesn't work for you, go to the tldr github and find one that does.

Some Thoughts On That Sexist Memo

Yeah, just another hot take on that sexist Google memo. I could only read bits of it because it was just such garbage that I didn't want to waste my time on the whole thing. I also read a few other takes, but it overall seems like standard garbage and it doesn't really surprise me that a senior engineer at Google thinks this way. One of the bits that really stuck out to me was this:

We always ask why we don't see women in top leadership positions, but we never ask why we see so many men in these jobs. These positions often require long, stressful hours that may not be worth it if you want a balanced and fulfilling life.

This just sorta pissed me off because it's ignoring that most women don't opt for these jobs because sexism forces them to do almost all the household labor. Maybe it's also because, as a man, you can have what society deems as a "balanced" life while working long hours because your wife is taking care of the kids and a man isn't considered a bad dad if he's not super involved in the kid's life. This is total crap and bad for women and men that people think this way.

The real downside is that tech is the perfect industry to help even this out since it's pretty easy to work from home in most jobs. In one of my first dev jobs, one of the senior engineers that I worked with worked from home twice a week after his kid was born, alternating days with his wife, so she could go back to work too. I thought that was pretty cool and not a freedom most industries have! Maybe this is a faulty assumption that I'm making since I'm not a parent, but I'm assuming if you have kids you want to spend time with them?

Asking Questions

I've been thinking about this for a while, but keep not actually writing this post. One of the biggest mistakes I see juniors make is not to ask questions when needed for fear of looking like they don't know what they are doing. Granted, part of that is the way senior developers often react to questions. April Wensel wrote a fantastic article last August about the toxic tone that is prevalent in tech. So two points here:

  1. Senior devs should all read that article and consider more carefully how they talk to junior devs (or any other person for that matter). I'm not picking on anyone - I have definitely been guilty of this as well. However, being able to explain concepts plainly and empathetically shows your knowledge more than making someone feel dumb because they don't also have that knowledge.
  2. Junior devs need to make sure to timebox themselves. Give yourself a chance to do some googling, see if you can find an answer to your question on your own. However, after that first 30 minutes/hour, you should bring your question to someone else. Ideally, you have someone that you can approach who will answer your question compassionately. Make sure you give them all the information you have and the attempts you have already made. This will help avoid feeling like you are getting repetitive information.

Getting SQL Results That Are Distinct Across Two Columns

So this is a weird issue I just came across. Here's an example table schema:

mysql> describe queues;
+--------------+---------------+
| Field        | Type          |
+--------------+---------------+
| id           | int(11)       |
| customer_id  | mediumint(9)  |
| request_time | decimal(12,0) |
| item_id      | smallint(6)   |
+--------------+---------------+

mysql> select * from queues;
+------+--------------+--------------+--------+
| id   | customer_id | request_time | item_id |
+------+-------------+--------------+---------+
| 6829 |       15066 | 201704161118 |       1 |
| 6872 |       15066 | 201704161118 |       2 |
| 6875 |       15066 | 201704161118 |      26 |
| 6880 |       15066 | 201704161118 |       8 |
| 6881 |       15066 | 201704161118 |      15 |
| 6930 |       15077 | 201704161942 |       6 |
| 8683 |       14625 | 201704171412 |      10 |
+------+-------------+--------------+---------+

In my example, I might have the same customer requesting multiple items at the same time. I want to display all the items they have requested in the same line. That means I want to get a list of all the unique customers and request times combined. Yes, this isn't the *greatest* example because this table should probably be designed in a different way, but stick with me!

If I only want customer_id and request_time, that is pretty simple.

mysql> SELECT DISTINCT customer_id, request_time FROM queues;
+-------------+--------------+
| customer_id | request_time |
+-------------+--------------+
|       15066 | 201704161118 |
|       15077 | 201704161942 |
|       14625 | 201704171412 |
+-------------+--------------+

However, in my case, I need the queue id to do additional queries. That's where it gets just a smidge bit more complicated! Instead of just a simple DISTINCT, I've got to count the distinct records and then use HAVING to actually limit it.

mysql> SELECT *, 
COUNT(DISTINCT customer_id, request_time) as unique_orders 
FROM queues 
GROUP BY customer_id, request_time 
HAVING unique_orders >= 1;
+------+-------------+--------------+---------+
| id   | customer_id | request_time | item_id |
+------+-------------+--------------+---------+
| 6829 |       15066 | 201704161118 |       1 |
| 6930 |       15077 | 201704161942 |       6 |
| 8683 |       14625 | 201704171412 |      10 |
+------+-------------+--------------+---------+

Not too difficult, but I did go through a few different variations before getting to this result. I wanted it to work, but SELECT id, DISTINCT(customer_id, request_time) definitely does not!

Squashing Commits & Keeping Your History Clean

I'm a big fan of committing early and often. However, if you are anything like me, that means your commit history looks something like this:

added feature
fixed typo
oops another typo
added tests
fix failing test
fix another failing test
UGH TYPO

Fine for me alone, but not a great reference for the rest of the team when they try to figure out WTF I was doing a month or a year later. I've already written about how to rebase and squash commits before, so I won't cover that again. I do want to go a little more into why it's important to do so. Each commit message should reflect a distinct piece of work done. What I need to do now is rebase and change my commits to be more like this:

Added endpoint to return list of components
Added unit tests for component index endpoint

Now, if someone does a git blame, they can get the full context of what I was doing, not just a one character typo change. It's also worth expanding out your messaging and putting more context in the description. Every team has their own style and rules, but, personally, this is my normal git workflow and I'm a huge fan.

Finding Unseen Unicode/ASCII Characters in Ruby

This morning, I thought I was losing my mind. I'm writing a little web app (mostly Angular) that makes API calls. I know the API works, but for some reason, the calls from my app to the API were getting a 500 error in response. I tailed the API logs to see an "ArgumentError: argument out of range". However, the only thing that happened on this line was the date parsing. I open up the Rails console and start debugging. First I type out the date that isn't working. It works. Then I copy and paste from my browser. Failure.

irb(main):027:0> "2017-02-13T13:12:51Z".to_time(:utc)
=> 2017-02-13 13:12:51 UTC
irb(main):028:0> "2017‑02‑13T13:12:51Z".to_time(:utc)
ArgumentError: argument out of range

As you can see above, they look IDENTICAL. One of my coworkers suggested that I check the ASCII value of each character. Lucky for me, Ruby makes this easy.

"2017‑02‑13T13:12:51Z".each_byte do |c|
  puts c
end
==>
50
48
49
55
226
128
145
48
50
226
128
145
49
51
84
49
51
58
49
50
58
53
49
90

If you look at a chart of ASCII characters and values, you can see that 127 is the end of the standard characters. My fifth character starts with 226. I know that the pattern of 226, 128, 145 repeats twice and in the same spot as the dash. Looking at a UTF-8 encoding table, I can see that set of characters represents the non-breaking hyphen, which is definitely breaking my API call. Mystery #1 of the morning? Solved.

Building A Community For Beginners

Originally given as a talk at PyCaribbean on February 18, 2017. Modified slightly for the web.

I started programming in Python six years ago and have been doing Ruby development for the past five years. When I would go to user groups as a new developer, it was very intimidating. People seemed to know each other, and I wasn't sure who to ask for help. In the end, I stopped going and just created my own group. But many people get so discouraged that they decide programming isn’t for them.

That’s the reason I believe that building a community for beginners is so important. Let me explain why. We want to ensure that our communities are open to beginners because we need to expand and diversify. The more diverse our community is, the more diverse our teams will be. According to the Harvard Business Review, "working with people who are different from you may challenge your brain to overcome its stale ways of thinking and sharpen its performance."  I also think that everyone should be able to learn to program. Programming shouldn’t be limited only to people who were privileged enough to learn to code in grade school. No matter their age, gender, or background, if someone wants to join our community, we should be open to helping them learn. Having community to help learn should not only be open to people willing to pay thousands of dollars for a code school. I started PyLadies Boston almost four years ago with the express intention of bringing more women into the Python community. I am also involved with Boston Ruby Women, leading weekly study sessions where I answer any questions that people bring me. More on these and a few others as we move on…

How can you do your best to make sure your group is open to beginners? First, let's talk about new groups. As I mentioned, existing groups can still benefit from many of these ideas, so don't totally zone out if you already have a group that you run.

1. Make sure the way you describe your group and events is beginner inclusive

Ex. “no problem too big or small” “good for people of all levels”

2. Be clear about what knowledge and skills are required

Be clear about what level of knowledge is required. People will often underestimate themselves, so keep this is mind when describing what is needed. Ex. “basic Python required, should have mostly completed a tutorial like Learn Python The Hard Way”

3. Find out what your local community needs

This is important. Every community needs different things. With PyLadies, we have a large community of academics and scientists, so there's a huge desire for tutorials and code reviews. With Boston Ruby Women, we have a lot of recent boot camp grads, so we spend a lot of time talking about interviews and finding jobs.

4. Ask for feedback all the time.

Every year, I have an anniversary party and ask everyone who attends for feedback on the past year (what did you like, what did you not like) and for suggestions for the future. This regular evaluation of PyLadies has led us to have new types of events that I would never think of on my own and to get rid of ones that I thought would be successful that weren’t.

5. Try out different types of events for the whole group. Depending on your local community, some may work better for you than others. Here are some event types that I've had success with:

  1. Presentation Nights are the standard, but often there's an idea that you have to be an expert to give a presentation. Make it clear when asking for presentations that you are open to presentations about beginner projects.
  2. Lightning Talks are a great way to get people to do their first public talk. One of the ways that I have encouraged people is to say that, while it should be related, if you have a hobby that you want to share with everyone, we'd love to hear a lightning talk on it. One of the members of PyLadies ended up doing her first presentation on bird-watching, and it was a huge hit!
  3. Tutorials are always successful. They give experienced people a chance to share their knowledge in a meaningful way and beginners a chance to learn a new skill or toolset. However, with tutorials it's key to allow for extra time in the beginning, or before the event, to get set up. Even if you give clear instructions and ask people to set up prior, believe me, you will still likely need extra time.
  4. Mob Programming is where the whole group looks at the same problem and tries to solve it together. We started running events that were combination mob programming and code reviews, and they have been a blast. Everyone can participate: even with limited programming knowledge, you can get an idea of what kinds of problems other people are facing.
  5. Host separate beginner-focused events. These events will draw out people who are still too intimated to go to the main meetings. We regularly have women show up to our beginner events that almost never go to the main group because they don't feel they are ready, despite my encouragement.
    1. Study groups can help people teach each other. At PyLadies, we try to have study groups every week and have a mentor each time. However, we've also encouraged our members to start study groups in their neighborhoods as well and have had a ton of success with that. I've used these to target people who are just starting to learn to code. If you are trying to provide mentors at study groups, it can be a challenge. One way to sell it to your more experienced members is that it's a way to both share their knowledge and improve their understanding of fundamentals. I have one woman who comes every week who always challenges me and makes me go deeper into the language than I had before.
    2. Mentor sessions are similar to study groups but more focused on career growth. These target people who know how to code and are looking to enter the industry. Job hunting as a junior is often very discouraging, and it helps to have regular meetings with someone who tells you that you can do it. Also, by getting to know a larger amount of junior developers, it makes it easier for you to find great developers who just haven't been given a chance yet. Through these groups, I've gotten two people hired at both Akamai and a previous company. Frequently, it is harder to get to know people in a larger group setting. Having a smaller subset like a mentor session can help your more experienced members get to know the individuals who are just getting started.

So that's some of the basics for starting a beginner-focused group, but what if you are currently running a group? Here are some suggestions that have been successful at bringing more beginners into both Boston Python and Boston RB. I'll start with the simplest:

  1. Send an email to everyone who joins with a message that emphasizes that everyone is welcome, no matter their level of programming experience and let them know what they can expect to happen at your events. With Meetup, you can write a message once and automatically send it to every new member.
  2. If you can, have someone greet people as they walk in. Ideally, it will be one of the organizers, someone who is there regularly. This individual should do their best to get to know the people who have just joined. It will give all newcomers a friendly face each time they return and someone who is familiar with their level.
  3. For presentations nights, ensure that there are regular talks that are suitable for beginners. These talks do not have to be about ‘how to write a for loop,' but more ‘here's a problem, this is how I solved it,' with less emphasis on pure programming. Organizers I spoke to said they got large influxes of new sign-ups for nights when they had multiple speakers from a variety of fields.
  4. For project nights, a few suggestions:
    1. Have a couple of beginner tables and, if you can, have a few experienced programmers to staff them and help new people work through issues.
    2. Do introductions at the beginning. Have everyone introduce themselves and mention what they are working on. You can ask experienced people to raise their hands if they are willing to be available for help throughout the night. It can be time-consuming, but it will help build community and create opportunities for people to collaborate.
    3. Reassure people that it's ok if they are not working on a project. You can have people raise their hands at the beginning if they are looking to collaborate on a project.

Ok, last but not least: running workshops and finding the best way to teach people to code.

  1. Running workshops is, personally, one of the biggest challenges as an organizer. Here's a rundown of some the problems and some suggestions on how to deal with them.
    1. Space: given that a workshop is at least 6 hours long, you can't run one on weeknights. Therefore, most businesses won't want to host. However, you should try reaching out to local universities and community colleges - even better if you have someone in your group who works at one.
    2. Volunteers are a challenge at any time, but getting people to give away their Saturday (plus maybe their Friday night) is another problem entirely. Expect at least a couple of individuals to bail last minute, so have a backup plan. Make sure to have a few more volunteers than you think you need and be prepared to present if someone who is supposed to present doesn't show.
    3. Content is probably the easiest if you are doing a Django or Rails workshop since there are already full tutorials for both aimed at a weekend time frame. If you want to run a workshop for either of those, check out DjangoGirls, RailsGirls, and RailsBridge. If you want to do a workshop for a different language or framework, consider still looking at those for example of what you should include and adopt it for the framework that you want to cover. If considering a workshop on a language, review the material covered by the Boston Python Workshops. Though the materials are in Python, you could adapt them to fit other languages.
    4. Food - it's important to provide at least lunch when you have people stuck in a room for a full day. You can reach out to local companies who use the language or framework that you are teaching and get someone to provide food. Usually, they'll also want to send a volunteer for the workshop too so they can have someone to represent their company. 
    5. Continued engagement is probably the biggest challenge. When people come to a workshop, make sure they know what the next steps are. When a RailsBridge Boston workshop occurs, they always make sure there is a Boston RB project night the week after so people can keep learning. You could also have lightning talks soon after and encourage people to talk about problems that they want to solve or applications they want to build.
  2. There is no "one best way" for teaching people how to code. However, I have had more success with some methods than with others.
    1. Doesn’t work:
      1. Class style setting that builds on itself week after week potentially works if people are paying for it. However, if you are like me and just trying to provide a free service to your community, do not choose this option. I did this when I first started PyLadies because there was a demand for beginner classes. I held classes for just two hours every other weekend. I had a fantastic turnout the first week - 30 people showed up and were super engaged. The second week was still good - 20 people. Then it started dropping drastically. By the fifth week, it was just me and my co-organizer.
      2. Just giving a text tutorial (like Learn Code the Hard Way), with no support. With no support group or place to reach out for help, when people get to a tight spot, they can assume that they just aren't cut out for programming and quit. There's still a stigma that you have to be good at math to be a programmer, and some non-technical people think that only geniuses can program (have been told that I must be super smart because I'm a developer). Often it's just a matter of seeing the right example for a concept to make sense. Just because someone has trouble learning using one resource doesn't mean they couldn't learn using another.
    2. Does work:
      1. Short one-off tutorials on basic programming concepts that don't build on each other. You can't necessarily do a ton of these since most of programming does require knowing other concepts. But you can teach the idea of object-oriented programming without involving a significant amount of code. There are also other languages that you can learn the basics of in a two hour period - SQL being my favorite, but HTML also being a possibility. The goal is to share knowledge, so get creative!
      2. Having beginner focused events where people can bring questions from any tutorial they choose. As I mentioned above, this is an essential part of PyLadies Boston. I always suggest my two favorite tutorials, but if someone learns better another way (say a MOOC or videos), then they can use those and I will still be there to answer questions. I also try to make it clear in all communication that I am always available by email. Unless you have a group that is 5K plus people, this is not as big of a deal as you might think. I make myself available to about 1500 people through the groups I run and countless more through my website, yet I maybe get an email a week max. It will give people a lifeline if they need it, but it will not take up too much of your time.

These are my recommendations on how to build a community for beginners. However you involve yourself, being part of a space where everyone is welcome to learn is a valuable and rewarding experience that can really make a difference to someone just starting out.

On Building, Then Leaving, Community

When I moved up to Boston, I felt very lonely. I had my partner, sure, but that's never quite enough. I tried going to existing meetups but I found that they were too large and I still felt isolated. I had been part of a PyLadies group in Atlanta, so I decided to start one in Boston. From the very first meeting, I was energized by the women who came. They were all so excited about the group and the possibilities that it pushed me to spend more time organizing, where I might have otherwise said I was too busy. Every event we had, no matter how small or large, gave me energy and life. It was so gratifying to be able to give people who had never spoken in public before a platform to share their knowledge.

A few months after the founding of PyLadies Boston, I heard about a Ruby women's study group that had formed. Since I was by then working in Rails, I joined hoping to get to know more people in the Ruby community. That group moved from a mailing list to Meetup a few months after I joined and became Boston Ruby Women. That group has also been a source of good in my life. Every month, I'm able to help junior developers not lose confidence during tough job searches. Every month, I talk to brilliant women who routinely give wonderful advice on how to deal with all the bullshit that life throws. The group is always up for a table flipping conversation and I love it so much for that.

I am excited to be moving to Pittsburgh and to start a new chapter in my life. But I'm brokenhearted to leave these two communities. I have faith that I'll be able to meet rad and awesome women in my new home, but I know it will take time. Thank you to everyone who has helped me grow over the past four years. Y'all mean so much to me.

Creating Awesome Documentation With Yard

This semester I have been taking a computer architecture class. Overall, it's been pretty fun because I was given three projects and allowed to do them in the language of my choice. I chose Ruby. I'm pretty proud of these projects, so I decided to post them all to Github. If you are interested in the actual code, you can find it here. While I was doing this, I realized I needed to up my average documentation game. I needed the grader, who didn't know Ruby, to be able to easily understand what I was doing and why I was doing it. For the first two projects, I just wrote up documentation in a relatively reasonable way, and they were able to read through the code comments to see how it worked.

That's when I found YARD. YARD uses markup (I used markdown) and tags to create delightful HTML docs. What were just comments in my code turned into this, with almost no extra effort. I'd heard of it before, but I hadn't had a project that was worth massive documentation. YARD made the documentation a delight. You create the necessary documentation by using markdown, so your README functions as the homepage for your docs. Then, within each class, you use tags to explain params, return values, and add notes and examples. Here is an example from my MIPSDisassembler project:

class MipsDisassembler
  # Creates a new instance of MipsDisassembler
  # @param array_of_instructions [Array] the array of string instructions
  # @param starting_address [String] starting address for instructions, should be a string hexadecimal value
  # @param is_hex [Boolean] true if array of instructions is in hex, false if in binary
  # @note Each object in array_of_instructions should be a string representation of either binary or hexadecimal number
  # @return [MipsDisassembler] a new MipsDisassembler object
  # @example Create an object
  #    mips = MipsDisassembler.new(["0x022DA822", "0x8EF30018", "0x12A70004"], "7A060", true)
  def initialize(array_of_instructions, starting_address, is_hex)
    @instructions = array_of_instructions
    @starting_address = starting_address
    @is_hex = is_hex
  end

  # Takes binary/hex instructions and starting address and return an array of MIPs instructions.
  # @note Determines if r-format or i-format and parses accordingly.
  # @return [Array] an array of MIPs instructions, human-readable
  # @example Disassemble instructions
  #    mips.disassemble => ["7A060 sub $21 $17 $13", "7a064 lw $19, 24 ($23)", "7a068 beq $7, $21, address 0x7a07c"]
  def disassemble
    disassemble_instructions(@instructions, @starting_address, @is_hex)
  end

  # write MIPs instructions to file
  # @note File "mips_results.txt" will be created in same directory as code
  # @return [void]
  def output_to_file
    File.open("mips_results.txt", "w") do |f|
      in_file = ""
      disassemble.each { |instruction| in_file << instruction + "\n" }
      f.write(in_file)
    end
  end
 end

You can see the result of this code here as well as the image below. The result is easy to navigate documentation that you can share with anyone. It also gives the ability to see the source code of each method inline, so you don't have to go far to see the actual code behind public methods that you would want to use. I know I'm a bit of a dork, but I seriously loved putting this documentation together and I'm hoping it made my code just a bit more accessible.

Fun with Binary & Hex in Ruby!

While I haven't written a coding post in three months, I swear I do code every day. Recently, I started taking night classes again. This semester, I'm taking Computer Architecture and Data Structures with Java. My first project in Computer Architecture was to build a MIPS disassembler. I decided to use Ruby, which ended up bringing up some unique issues, mostly because Ruby does not have a short variable type within it's Numeric class. In Java, the short type is a 16-bit signed two's complement integer. Ruby does not use primitive types because everything has to be an object. No short object == no short type. Also, while binary and hexadecimal numbers can be converted easily to decimal in Ruby, they are initially strings. What does this mean? It means that in addition to the other parts of the translate, I also had to convert from hex to binary and from binary to signed decimal. I'll probably share all of my code in the future, but for now, here's a walkthrough of those two functions:

Translating to binary

This was pretty simple. I just had to use sprintf and it immediately converted the hexadecimal numbers into binary. Only one hitch! I needed the leading zeros (if there were any), so I had to use rjust to make sure it was a 32 bit binary by padding it to the left with 0s.

# takes an array of hex and returns an array of binary
# (32bit, including leading zeros)
def translate_to_binary(array_of_hex)
  array_of_binary = []
  array_of_hex.each do |num|
    array_of_binary << sprintf("%b", num).rjust(32, '0')
  end
  array_of_binary
end

Converting to a signed integer

Since I couldn't just cast as a short, I had to use two's complement. With two's complement, I knew that if the integer version of the binary was greater than 2^15, then it was actually a negative number. Otherwise, it was correct as is.

def convert_to_signed_binary(binary)
  binary_int = binary.to_i(2)
  if binary_int >= 2**15
    return binary_int - 2**16
  else
    return binary_int
  end
end

Boom! I hope this helps someone else who might've had the same trouble I did at first. I'll go into the program in full after my whole class has actually submitted theirs. 😛

SQL is the best!

I gave a SQL tutorial at PyLadies Boston last night and it was pretty fun. We used sqlite3 (which is definitely my least favorite DBMS, but it does come installed on pretty much every Linux/Unix machine by default and is the default for Django so I decided it was the best tool for this particular job. Giving a tutorial on something I used daily and have used consistently for 7 years was a bit weird because I did forget a few things because it didn't even cross my mind that people wouldn't know. For example: I initially neglected to mention that every statement needs a semicolon at the end and that you can't mix quotes (no " with '). Consider that was the bulk of all the issues, I'm feeling pretty successful right now! Take a look at the full tutorial below and let me know what you think.

The Mental Impact of Tech Interviews

I just watched this excellent talk by Zack Zlotnik (given at Code & Supply in Pittsburgh). I think every developer involved in the interview process should listen to this talk. Even if you aren't involved in the interview process, if you have interviewed anywhere, this is a great talk to watch.

Two slides in particular really struck with me:

In my experience as both an interviewee and an interviewer, all of these points are 100% true. Usually, about half way through my job search, I'll feel worthless and stupid, sure that no one will ever hire me. I've had an interviewer interrupt me midway through a white boarding problem and tell me that I wasn't quite the level they were looking for. Could I do the job they were asking? Definitely. I know I have routinely performed well in every job I've been given. However, white boarding routinely terrifies me and I've only gotten slightly more relaxed the more I've done it. I've always done better in a pairing session or, heck, just coding on a laptop in front of people. I've seen people hired through whiteboard interviews who are not good at their jobs. Zack has some good suggestions on how to improve the interview process that I think everyone should take into consideration.

Hey, I was interviewed!

What was it like to ramp up at that first job? Did you find you had some blind spots that your job filled in? Were certain things more or less important than you anticipated?
It was tough. I didn't get a lot of support from the other engineers, so I had to learn a lot on my own. If I ever ran into issues, usually they would just take the ticket themselves instead of helping me learn. At one point, I had almost no work, so I started taking online classes and working through programming books. I had never realized how important it was to have a team that supports you, which is definitely something I've looked for in every job since. Even as I move along in my career, I still want to be able to talk to my coworkers about issues that I am having without feeling like I'm wasting their time. However, I still feel like it wasn't a waste. It still enabled me to list myself as a software developer, have some actual production code that I could show, and really get my foot in the door. It's great to have a great job, but sometimes, especially if it's your first in a field, any job will do if you have limited choices.

Plotting Data From A CSV with Matplotlib

After I got all that data from the logs, my boss wanted it in a nice graph. First of the active user numbers, then the top 15 users. I knew that, despite having never used Matplotlib, it will still take me less time to learn it than any of my other options. I was able to get my script running and plotting correctly in less than two hours, so I felt pretty good about that. However, I had a few nested for loops and I wasn't a big fan. Enter the crowd-sourced code review! My friend Jenny was able to come up with a cool alternative to my solution that I ended up using. She utilized plot_date to sort the dates/data, which really helped (I was doing all sorts of crazy fun things).

So here's an example of what active_users.csv looked like:

system,au1,au30,date
jira,5,20,2016-06-09
confluence,16,23,2016-06-09
jira,8,22,2016-06-10
confluence,18,26,2016-06-10
jira,10,22,2016-06-11
confluence,18,26,2016-06-11
jira,11,23,2016-06-12
confluence,19,27,2016-06-12
jira,13,24,2016-06-13
confluence,19,28,2016-06-13
jira,8,24,2016-06-14
confluence,10,28,2016-06-14
jira,9,26,2016-06-15
confluence,15,30,2016-06-15
jira,15,26,2016-06-16
confluence,20,30,2016-06-16

he biggest problem was determining how to store the data in the program in a way that could be easily plotted. End solution? A dictionary of arrays. Or more precisely, a dictionary of a dictionary of arrays. With each line, we appended each data point to the matching array, which meant that a given date had the same index as it's data. And boom! It works!

import matplotlib.pyplot as plt
import csv
from datetime import datetime

active_users = {
  'jira': {
    'dates': [],
    'au1': [],
    'au30': []
  },
  'confluence': {
    'dates': [],
    'au1': [],
    'au30': []
  }
}

with open('active_users.csv') as csvfile:
  active_users_csv = csv.reader(csvfile)
  for system, au1, au30, date in active_users_csv:
    active_users[system]['dates'].append(datetime.strptime(date, '%Y-%m-%d'))
    active_users[system]['au1'].append(au1)
    active_users[system]['au30'].append(au30)

plt.plot_date(active_users['jira']['dates'], active_users['jira']['au1'], label='jira au1', color='orange', fmt='-')
plt.plot_date(active_users['jira']['dates'], active_users['jira']['au30'], label='jira au30', color='red', fmt='-')
plt.plot_date(active_users['confluence']['dates'], active_users['confluence']['au1'], label='confluence au1', color='green', fmt='-')
plt.plot_date(active_users['confluence']['dates'], active_users['confluence']['au30'], label='confluence au30', color='blue', fmt='-')
plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
           ncol=4, borderaxespad=0.)
plt.show()
 Resulting graph of AU1 and AU30 numbers

Resulting graph of AU1 and AU30 numbers

Ok, so now that graph #1 is done, I had to graph the top 15 users over the past week and their usage patterns. First off, here's an example of the data I was working with:

User,Date,Request Count
jsmith,2016-06-20,12
kthrace,2016-06-20,1
shastings,2016-06-20,11
sbristow,2016-06-20,3
jmccoy,2016-06-20,3
akoni,2016-06-20,9
gmorrison,2016-06-20,4
pfisher,2016-06-20,18
ndrake,2016-06-20,10
lbriscoe,2016-06-20,7
egreen,2016-06-20,13
crubirosa,2016-06-20,20
avanburen,2016-06-20,2
mlogan,2016-06-20,18
ckincaid,2016-06-20,11
rcurtis,2016-06-20,21
jfontana,2016-06-20,16
clupo,2016-06-20,5
kbernard,2016-06-20,7

Obviously, with our actual prod data, there were thousands of users... so a few more lines to loop through. The first problem was to put the data into a format I could use. Since even a top user might not use the system at all one day (say a Sunday), I couldn't use a simple dictionary; this time I had to utilize defaultdict. Defaultdict enabled me to create a dictionary of users where the value was (by default) an array of 7 zeros (representing usage for the past 7 days). After that, I was able to loop through the file for each day. To get the file names, I had to start with yesterday's date and go backwards. The date still gets appended to the 'dates' array, but the big change is in users: instead of appending the data to an array, I insert it into the index that matches that day.

So now that I have a dictionary of dates and users, I have all that I need to determine the top 15 users of the week. I create another dictionary that has the users as keys and sums up their total requests from the array and sets that as the value. Once I do that, I sort it, end up with a tuple, reverse it, then slice off the top 15. At that point, I just need to loop through my weekly_active_users list and then plot each user's data! Though I did have one, final (much smaller) problem: I had to find 15 matplotlib colors that I could use and distinguish. I created my array of colors and added a counter to each loop so I could add a unique color to each user. Success!

import matplotlib.pyplot as plt
import csv
from datetime import datetime, timedelta, date
from collections import defaultdict
import operator
from itertools import islice
import re

active_users = {
  'jira': {
    'dates': [],
    'users': defaultdict(lambda: [0] * 7)
  },
  'confluence': {
    'dates': [],
    'users': defaultdict(lambda: [0] * 7)
  }
}

active_users_weekly = {
  'jira': {},
  'confluence': {}
}
current_date = date.today()
day = timedelta(days=1)

for i in range(0,7):
  current_date = current_date - day
  current_date_txt = current_date.strftime('%Y-%m-%d')
  for system in ['jira', 'confluence']:
    active_users[system]['dates'].append(current_date)
    with open("active_users_{0}_{1}.csv".format(system,current_date_txt)) as csvfile:
      users = csv.reader(csvfile)
      for user, log_date, request_count in users:
        active_users[system]['users'][user][i] = int(request_count)

sorted_active = {'jira': {}, 'confluence': {}}
for system in ['jira', 'confluence']:
  for user, request_list in active_users[system]['users'].items():
    active_users_weekly[system][user] = sum(request_list)
  sorted_active[system] = sorted(active_users_weekly[system].items(), key=operator.itemgetter(1))
  sorted_active[system].reverse()
  sorted_active[system] = list(islice(sorted_active[system],15))

fig = plt.figure()
jira = fig.add_subplot(211)
jira.set_title('JIRA')
conf = fig.add_subplot(212)
conf.set_title('Confluence')
colors = ['red', 'gold', 'darkorange', 'green', 'turquoise', 'dodgerblue', 'navy', 'darkviolet', 'violet', 'pink', 'darkslategrey', 'silver', 'blue', 'lime', 'orange']

i = 0
for user, request_num in sorted_active['jira']:
  jira.plot_date(active_users['jira']['dates'], active_users['jira']['users'][user], label=user, fmt='-', color=colors[i])
  i += 1

i = 0
for user, request_num in sorted_active['confluence']:
  conf.plot_date(active_users['confluence']['dates'], active_users['confluence']['users'][user], label=user, fmt='-', color=colors[i])
  i += 1

jira.legend(bbox_to_anchor=(0., 1.1, 1., .102), loc='lower center',
           ncol=8, borderaxespad=0.)
conf.legend(loc='upper center', bbox_to_anchor=(0.5,-0.1), ncol=8)
plt.show()
 Oooh pretty colors! Also, fake data makes for a bad graph.

Oooh pretty colors! Also, fake data makes for a bad graph.