Monday, December 30, 2019

My Thought Process For Creating an Exercise Problem

In order to help others in the process of coming up with practice problems with the intention of having people exercise the principles that they've read in a chapter, I've put together an outline of the thought process that I used when coming up with the practice problem for Chapter 1 of Effective Python.

After having read the complete chapter, I looked back through the sub topics of the chapter and made the following mental thoughts and notes:
  • Item 1: Know Which Version of Python You're Using
    • This section covers python versions and making sure that you're on version 3.
    • Nothing to practice here. This section can be skipped.
  • Item 2: Follow the PEP 8 Style Guide
    • There's a lot of little things in this section. I won't be able to cover everything here.
    • Though the whitespace and naming will undoubtedly be covered no matter what problem I come up with.
    • It might be good to try to cover inline negation or empty container checks.
  • Item 3: Know the Differences Between bytes and str
    • While the information here is useful to know about under the right circumstances, it is not something that I expect my group of developers to be running into often, and as such I am fine with skipping this point in the practice problem.
  • Item 4: Prefer Interpolated F-Strings Over C-style Format Strings and str.format
    • It would be very worthwhile to cover f-strings, potentially something that allows for a complex f-string
    • With f-string being recommended as the best practice, there is no need to cover any of the older string formatting variants.
  • Item 5: Write Helper Functions Instead of Complex Expressions
    • Covering this point is a maybe, if I can get it to fit into the problem.
    • That being said, this is a principle that should be universal to programming in general, and not unique to python, so I don't believe that it is something that the developers will be unfamiliar with.
  • Item 6: Prefer Multiple Assignment Unpacking Over Indexing
    • This could potentially be good to cover. While this feature isn't unique to Python, the number of languages that have this feature are limited, and as such it could be good to practice.
  • Item 7: Prefer enumerate Over range
    • This is a maybe. It might fit well with f-strings.
    • It could also tie in nicely Item 6 from above.
  • Item 8: Use zip to Process Iterators in Parallel
    • This is another maybe, but I could likely pass on it. Of the developers that I'm presenting to, a large number of them are very familiar with rxJava, and have used its zip function, which works in a very similar way.
  • Item 9: Avoid else Blocks After for and while Loops
    • This covers a Python specific feature that I've not seen in other languages that the author explicitly recommends avoiding. Easy enough to do. We can skip it for the practice problem.
  • Item 10: Prevent Repetition with Assignment Expressions
    • This covers the walrus operator, which would be worthwhile to cover.
    • It might be difficult to come up with a good case, though.

So with these points in mind, I started thinking through what might make for a good exercise. My thought process went somewhat as follows:

In order to use the f-string I'll probably want to take some data and format it to print prettily on the screen, and most likely I'll want this data to be a list of some sort to allow for different variations of the string to be formatted. So I imagine that I'll want something similar to the grocery list example from the book. Allowing for an empty list case and having a requirement to handle it differently would also pull in another one of the points that I'm trying to cover.

With these thoughts in mind, I looked into how to perhaps pull in some of my other points, and by looking over enumerate I figured that it would be simple enough to pull it in by simply making the list an ordered list of rankings. I would also get the added bonus of pulling in multiple assignment in that way. So with that emerged the idea to have a score board display.

With that, I started considering how I might be able to pull an assignment expression into the problem, and I had to think on that one for a while. Ultimately I figured that what would lead to its likely use would be to have a complex object for each item in my list, where certain fields may or may not be there.

This then led to the idea of displaying a competition score board where you would be given a list of users where a user would have a user name and a score, and may or may not have a team name.

After coming up with the problem, I went through and coded up a basic solution to the problem, and as I coded up the solution, it made me aware of holes in my problem definition that needed to be specified, such as a max length for the user name and the team name.

In the end, I had a simple problem definition put together, which can be found here, and an example solution put together that I could reference as needed as I took my group of developers through the practice problem, which I've shared below. Note that the code that I came up with here and the code that came out of the mob programming exercise with the group (found here) is slightly different. Also note that the code from the mob programming in addition to completing the exercise also to the exercise a step further. This is the result of the experimentation phase that I recommend following the mob programming practice problem, which can be read about in the Presenter section in this post.

With that, here's the example solution that I had come up with while putting the problem together:

def format_score_board(users: List[dict]) -> str:
    if not users:
        return "Awaiting Final Ranking"
    result = ""
    for i, user in enumerate(users):
        if team_name := user.get('team_name', ''):
            team_name = f" ({team_name})"
        line = f"{i+1} {(user['user_name'] + team_name):<43} {user['score']:8.2f}"
        result += "\n" + line
    return result

Thursday, December 19, 2019

Answer: Super Epic Competition Score Board

Answer to Effective Python Chapter 1 Exercise

This is the answer to the exercise defined here.

To begin with, let's throw together some basic scaffolding to help us test and build out our solution. We can take the input examples from the exercise and put them into python as follows:
example_1 = []

example_2 = [
    {
        "user_name": "hamster dance",
        "score": 1337
    },
    {
        "user_name": "success kid",
        "team_name": "nerf herders",
        "score": 1200.333333
    },
    {
        "user_name": "rickroll",
        "team_name": "the fellowship",
        "score": 1051.4
    },
    {
        "user_name": "ArrowToTheKnee",
        "team_name": "nerf herders",
        "score": 999.99
    },
    {
        "user_name": "grumpy_cat",
        "team_name": "the fellowship",
        "score": 999.98
    },
    {
        "user_name": "anonymous",
        "score": 561.12
    },
    {
        "user_name": "lol cat",
        "team_name": "allz te lolz",
        "score": 98.0432
    },
    {
        "user_name": "awkward seal",
        "score": -20
    }
]
And we can set up a basic way to test it by doing this:
print(format_score_board(example_1),
      format_score_board(example_2),
      sep="\n\n")
After that, we just need to define our format_score_board function. We can solve the exercise by defining the following code:
def format_score_board(users: List[dict]) -> str:
    if not users:
        return "Awaiting Final Ranking"
    result = ""
    for rank, user in enumerate(users, 1):
        if team_name := user.get('team_name', ''):
            team_name = f" ({team_name})"
        line = f"{rank} {(user['user_name'] + team_name):<43} {user['score']:8.2f}"
        result += "\n" + line
    return result
Now for a little bonus extra credit. What if we wanted to make this just a little bit nicer? What if we wanted to add some leader dots to the blank space between the left and right sides, and perhaps add commas to the scores to make them more readable? How could we change this to do that? With a couple of simple changes, we can get this code:
def format_score_board(users: List[dict]) -> str:
    if not users:
        return "Awaiting Final Ranking"
    result = ""
    for rank, user in enumerate(users, 1):
        user_name = user['user_name']
        if team_name := user.get('team_name', ''):
            team_name = f" ({team_name})"
        score = user['score']
        line = f"{rank} {(user_name + team_name):{'.'}<43}.{score:{'.'}>9,.2f}"
        result += "\n" + line
    return result

Exercise: Super Epic Competition Score Board

Effective Python Chapter 1 Exercise

We have been tasked with creating a score board for the Super Epic Competition. All the work for scoring the competition is already done, and we will be given a list of users that are ordered by the place they took in the competition. We need to take that list and format and print out a score board according to the following spec:

The score board will print out all participants ordered by their place in the competition. There are a max of 8 participants per competition. Each line will have a single participant. On the left side we start with their rank, followed by their user name. If the user is part of a team (which can be determined by whether or not the user object has a team name field), then the team name should follow in parentheses. Both user name and team name have a max limit of 20 characters. On the right their score will be displayed. In this competition the score is a decimal number that can have any number of decimal places. On the score board this number will be formatted to two decimal places. Also note that is is possible for the list of users to be returned as empty, in which case the message "Awaiting Final Ranking" should be displayed. Here are a few examples of input and expected output:

Example 1

Input
[]
Expected Output
Awaiting Final Ranking

Example 2

Input
[
  {
    "user_name": "hamster dance",
    "score": 1337
  },
  {
    "user_name": "success kid",
    "team_name": "nerf herders",
    "score": 1200.333333
  },
  {
    "user_name": "rickroll",
    "team_name": "the fellowship",
    "score": 1051.4
  },
  {
    "user_name": "ArrowToTheKnee",
    "team_name": "nerf herders",
    "score": 999.99
  },
  {
    "user_name": "grumpy_cat",
    "team_name": "the fellowship",
    "score": 999.98
  },
  {
    "user_name": "anonymous",
    "score": 561.12
  },
  {
    "user_name": "lol cat",
    "team_name": "allz te lolz",
    "score": 98.0432
  },
  {
    "user_name": "awkward seal",
    "score": -20
  }
]
Expected Output
1 hamster dance                                   1337.00
2 success kid (nerf herders)                      1200.33
3 rickroll (the fellowship)                       1051.40
4 ArrowToTheKnee (nerf herders)                    999.99
5 grumpy_cat (the fellowship)                      999.98
6 anonymous                                        561.12
7 lol cat (allz te lolz)                            98.04
8 awkward seal                                     -20.00
The answer to this exercise can be found here.

Wednesday, December 11, 2019

The Developer Book Club System

Over the last year I've experimented with what it takes to make a successful book club experience for software developers, and while I imagine that there's still plenty to learn and improve upon, I've found that the following system and roles work fairly well when tackling a technical book.

The System

When reading a technical book as a group, a good general rule of thumb is to cover a chapter a week. These kinds of books tend to be fairly dense, and trying to cover any more than that can overwhelm members of the group. But note that this can vary on a case by case basis, where some chapters in a book can be very short and could be combined, and other chapters can be overly long, and need to be further broken down.

Additionally reading speeds will very from group to group and from topic to topic. So during the first few weeks of a new book, be sure to gauge the how well the group is keeping up with the pace, and either slow down or speed up accordingly. With this being the case, it will typically take 2 to 3 months to go through a book, varying from book to book.

Meeting regularly to discuss the book is important and valuable, and meeting weekly for about an hour is a good cadence. During this time it's useful have people discuss any points they found interesting from the book, share example code, have a presenter present a practice problem, which the group can then solve, mob programming style, and generally give opportunities for the group to experiment with what they read about. In addition, a facilitator may need a few minutes to address points with keeping the book club running smoothly, such as meeting times, reading schedules, next book, etc. We'll further discuss the facilitator and present roles in the following sections.

The Facilitator

The facilitator is there to keep things running smoothly. This includes a number of responsibilities, such as:

  • Determining what book to read. This involves first determining a topic, which can come from polling the group about interests or from determining business needs, and then from there researching what books are available on the topic. Note that while some technical books age well, many do not simply because of the rapid pace of change in the industry.
  • Setting a reading schedule. Again, a good rule of thumb is a chapter a week, but be sure to look through the book and take into consideration the people in your group when determining this. And this doesn't need to be set in stone. If after a week or two, you find that the current pace isn't working for people, change it. Also note that it can sometimes be worthwhile to schedule in some break time, such as around holidays or in between books.
  • Arranging a time and place to meet. One hour once a week should suffice. Ideally in a setting that would encourage round table discussion instead of a lecture or presentation. As such, a room with a large table and many chairs surrounding it works better than a lecture hall with all seats facing a front stage. Additionally, it is useful to have a large TV or screen in the room and a method to allow anyone in the group to easily cast their laptop screen to it, such as using a Chromecast or similar device.
  • Sending reminders about the meetup. People get busy and even with the best of intentions will forget about the meeting. Sending out a simple reminder the day of or the day before drastically improves turnout.
  • Arranging presenters for each meetup. When first getting things up and running, it may make sense for the facilitator to also be the sole presenter, but over time it is worthwhile for the facilitator to encourage members of the group to volunteer taking turns being the presenter because it puts less of a load on the facilitator, gives the group the opportunity to more fully learn the material (those who learn the material best are those who teach it), and ensures the long term success of the meetup because it doesn't heavily depend on any one person. Note that it's still worthwhile for the facilitator to take his or her turn as the presenter, as well. You should make yourself available to the presenters to help them come up with ideas for their presentations, as needed. Additionally, as the facilitator it is worthwhile to have at least a few thoughts put together of what could be presented at each meetup so that you could step in and present if the scheduled presenter is unable to make it.
  • Coordinate the hand off with the next facilitator. When first getting things up and running, it may make sense to have a single person be the facilitator over the course of many books, but over time it is worthwhile to encourage other members of the group to take a turn at being the facilitator. This ensures stability of the group, since it doesn't heavily rely on any one single person. The ideal time to switch facilitators is as you're finishing one book and preparing to start another.
  • Get feedback from the group. Regularly check in with the group and see how things are going. Get feedback and make changes and adjustments based off of their suggestions. Ultimately every group is different, and it is always best to tailor the experience accordingly.

The Presenter

The presenter's job is to help the group get the most out of what they're learning by coming up with a practice problem for the group to tackle.

  • Come up with a practice problem. As you're doing the reading for the upcoming meeting, take note of the points being taught and which of those points would make for good candidates to cover in a practice problem. Think of a problem that could cover the use of multiple points from the reading. Note that you don't need to exhaustively cover all points brought up in the reading. Just a handful will do. If the points that you would like to cover don't fit together nicely into a problem, then trying making two smaller problems. It's better to have two smaller practice problems than to try to shoehorn multiple unrelated elements into the same problem.
  • Solve the practice problem once yourself before the meetup. This allows you to give some guidance on good ways to approach the problem as needed.
  • Lead the discussion at the meetup. My suggested format is to start out with letting the group share points they found interesting from the reading, and/or share example code, then move in to tackling the practice problem via mob programming, followed by allowing the group to make suggestions of other things to test or experiment with in the code, and end with a few minutes for the facilitator to take care of any necessary points that need to be addressed.
  • Present the practice problem in the meetup. I've found that taking a mob programming approach works well, where the presenter is at the keyboard and lets the group tell him or her what to type. In general, let the group guide the code, but feel free to give suggestions here and there.
  • Invite further experimentation on the code. After the group has finished solving the practice problem, it is a perfect time to invite the group to give any suggestions of anything that they'd like to test out on the code that you now have up on screen. This give the group an opportunity to further experiment and play with the code and discover things that they didn't know.
  • Publish a write up for the group to reference later. At minimum take the practice problem definition and the code generated from the mob programming session and publish the two in an article that the group can go back to and reference as need be. That being said, by all means feel free to take it further than that. Add explanations about how the code works or why to write the code the way that it is. Expand further on the problem. Show different ways that it could be solved. If you feel like it would be useful to the group, feel free to add it. And then publish it. While you could put it on an internal company wiki, I'd recommend against this unless it happens to contain private company information. Instead I'd recommend that the article be published as either a github gist, a medium.com article, a dev.to article, a blog post on your own personal blog, or any other public facing option. Why? Because it can prove useful in your future as a way to show a potential employer that you have knowledge of a topic.

Tuesday, December 3, 2019

Accelerate Review and Book Club Experience

The book Accelerate is a solid book on DevOps culture, with many valuable insights resulting from a careful study of its principles and thoughtful consideration of how those principles could be applied to your current job or situation. It is undoubtedly a book that I will return to again and again over the years.

With this book having a greater focus on culture over any specific technology or skill, the book club experience needed to be different from how I've handled previous books. Whereas with a technical book, the how is very clearly spelled out in the book, and what was most beneficial to the developers in the book club meeting was to provide them with a practice problem that would allow them to exercise what they've learned.

But in the case of a cultural book, like this, you are mainly supplied with guidelines and ideas, and the how for your particular company and situation has to be figured out. As such, the book club meeting time was best utilized by discussing the principles and determining how to apply them.

With this being the case, something that I was able to do to help these meetings to be more effective was to create bullet point summaries of the chapters that were to be discussed in the meetup, which then allowed for easy lookup and reference of these points for the discussion. Here are links to each of those summaries:

Chapter 1
Chapter 2
Chapter 3
Chapter 4
Chapter 5
Chapter 6
Chapter 7
Chapter 8
Chapter 9
Chapter 10
Chapter 11
Chapter 16

In addition to these summaries, I also had an ebook copy of the book that I had pulled up on a large display during the meeting that would then allow me to turn to any reference that the group asked for at a moment's notice.

All in all, I do feel that this went well, but I think there may have been a missed opportunity. Because culture takes time to implement and change, over the weeks that we were reading the book we came up with potential ideas at a far faster rate than they could be applied, and as such we've (rightly) put our focus on just a few key ideas, but with the detrimental side affect that a number of the ideas that were either small or of less immediate importance have potentially been forgotten.

Something that I would like to experiment with the next time I take a group through a book on culture would be to maintain and update a list of ideas that have come out of each meetup, which would be kept roughly in what people deem to be the priority order. The idea would be that it would still allow you to first focus on a small subset of ideas that seem to be the most important, while also maintaining the list of ideas so that good ideas don't get forgotten.