• One of my projects, Unbreach, has a database of more than 600 breaches. These come from haveibeenpwned and they are composed of some metadata, a one-paragraph description, and an image. I wanted to improve these with more content, links to articles, tweets, videos, and some content of my own.

    I decided that a good way to do it would be to move them from the app, which resides at app.unbrea.ch, to the marketing website, which is at unbrea.ch, essentially creating them as blog posts. That way after the blog post is automatically created (when haveibeenpwned ads the breach), I can go in and manually edit it in all the WordPress glory. I thought this was going to take me a few hours, not days.

    Hopefully, with this blog post, it’ll only take you hours. I’ll be using Ruby but it should be trivial to translate it to Python, JavaScript, or any other programming language. Writing the code wasn’t the hard part, understanding the WordPress.com world was.

    WordPress has two different APIs that should be able to accomplish this task, one is the XML-RPC API and the other is the REST API. The XML-RCP API depends on a file called xmlrpc.php and it’s strongly recommended you leave this deactivated because it had a lot of security issues. It’s also old, cumbersome, and possibly on the way out. I didn’t want to use it and I don’t think you should either.

    From what I can gather the REST API is what the admin tool uses, so using it sounds like a safe bet. If you are going to be creating blog posts from an unattended background process, as I do, you’ll find your first obstacle when you read about authentication because it just assumes there’s a browser sending cookies.

    Fear not! There are plug-ins that implement other authentication methods and one of those is the Application Passwords plug-in. Which is now discontinued because it’s been merged into WordPress itself in version 5.6. This sounds promising until you realize the feature seems to be missing in WordPress.com.

    If you search how to create an Application Password on WordPress.com you’ll land in the wrong place. WordPress.com users have an Application Password that’s hidden behind the Two-Step Authentication in Security. This is what it looks like:

    If you are here you are in the wrong place

    What’s going on here? Well, WordPress.com has its own API, which is a REST API, and if you talk to support and WordPress.com they’ll point you to that. I wasn’t a fan of that solution because although I want to use WordPress.com, I don’t want to be tied to it. I want to be able to move to WP Engine or something like that whenever I want.

    That API, similar to the REST API, assumes there’s a human interacting through a third-party application, so it’s not great for unattended processes. Authentication works using OAuth2 which for a background job that just needs an API key I find very annoying. It’s doable but annoying. Well… it’s doable until you enable 2FA and then it’s not doable anymore, and that’s why that specific Application Password exists.

    WordPress.com support also told me that the WordPress REST API is enabled only if you are on a business plan or above.

    So… where’s the Application Password for the REST API then? I don’t know if there’s a link to it anywhere, but you get to it by going to https://example.com/wp-admin/profile.php where example.com is the URL of your blog. That is, add /wp-admin/profile.php to it. On WordPress.com’s defense, it was their support that finally pointed me to it. When you go there you’ll see an old-style profile page:

    The correct place to set up an application password to use the WordPress REST API

    The previous Application Password was tied to the user, this one is tied to the user and the site, so if you have more than one site you’ll need to create one per site.

    And that was the hard part. Once I got that application password things just worked. It’s a straightforward and mostly well-documented API. I’ll share my messy code here anyway (sorry, didn’t have time to clean it up).

    In Ruby I’m using a library called Faraday to talk to APIs. The first thing is creating the Farady object that has the metadata that will be used in all the requests:

    auth_token = "#{Rails.application.credentials.wordpress&.username}:#{Rails.application.credentials.wordpress&.app_pass}"
    auth_token = Base64.strict_encode64(auth_token)
    conn = Faraday.new(url: ENV["WORDPRESS_URL"],
      headers: { "Authorization" => "Basic #{auth_token}" }) do |conn|
     conn.request :json
     conn.response :json
    end
    

    According to Faraday’s documentation, this should have worked as a better way of setting up the authentication details:

    conn.request :authorization,
                 :basic,
                 Rails.application.credentials.wordpress&.username,
                 Rails.application.credentials.wordpress&.app_pass
    

    but for me it didn’t. It was completely ignored. About those two values, Rails.application.credentials.wordpress&.username is the username of the user that will be creating the posts and Rails.application.credentials.wordpress&.app_pass is the corresponding application password. ENV["WORDPRESS_URL"] is the URL of the WordPress site, like https://unbrea.ch/.

    The first thing I need is the id of the category in which these posts will end up. This is very important because they appear on a separate page about breaches and not on the blog and that’s achieved with categories:

    response = conn.get("/wp-json/wp/v2/categories", {search: "Breach", _fields: %w[id name]})
    if response.status != 200
      raise "Unexpected response #{response.status}: #{response.body}"
    end
    category = response.body.find { |category| category["name"] == "Breach" }
    

    Now, if the category doesn’t exist, I want to create it:

    if category.nil?
      response = conn.post("/wp-json/wp/v2/categories") do |req|
        req.body = {name: "Breach"}
      end
      if response.status != 201
        raise "Unexpected response #{response.status}: #{response.body}"
      end
      category = response.body
    end
    

    Then I needed to do the same with tags. In my case, the tags were in a field called data_classes and the code for getting the id of the tag and creating it if it doesn’t exist is very similar:

    tags = data_classes.map do |data_class|
      response = conn.get("/wp-json/wp/v2/tags", {search: data_class, _fields: %w[id name]})
      if response.status != 200
        raise "Unexpected response #{response.status}: #{response.body}"
      end
      tag = response.body.find { |tag| tag["name"] == data_class }
    
      if tag.nil?
        response = conn.post("/wp-json/wp/v2/tags") do |req|
          req.body = {name: data_class}
        end
        if response.status != 201
          raise "Unexpected response #{response.status}: #{response.body}"
        end
        tag = response.body
      end
    
      tag
    end
    

    And finally, we can create the post. I create the content as an HTML snippet which causes WordPress to interpret it as classic content, not as blocks. But that’s fine because it renders well and the first time I edit one of those posts converting them to blocks is two clicks and works perfectly for this simple content.

    content = <<~CONTENT
      <p>#{description}</p>
      <p><!--more--></p>
      <p>Accounts breached: #{pwn_count}</p>
      <p>Breached on: #{breach_date&.strftime("%B %d, %Y")}
      <p>Exposed data: #{data_classes.to_sentence}</p>
      <p>Domain: #{domain}</p>
      <p>Added on: #{added_date.strftime("%B %d, %Y")}</p>
    CONTENT
    
    response = conn.post("/wp-json/wp/v2/posts", {
      title: title,
      content: content,
      excerpt: description,
      status: "publish",
      categories: [category["id"]],
      tags: tags.map { |tag| tag["id"] },
      date_gmt: (breach_date.to_time(:utc) + 12.hours).iso8601.to_s,
      template: "breach-template",
      ping_status: "closed"
    })
    if response.status != 201
      raise "Unexpected response #{response.status}: #{response.body}"
    end
    post = response.body
    

    At this point, I wasn’t done. I wanted these posts to have the image associated with the breach (the logo of the company breached). The first step was downloading it which was a trivial one-liner:

    logo_request = Faraday.new(url: logo_path).get("")
    

    In that code, logo_path is actually a full URL of the file.

    To create media items in WordPress, I needed to encode the post as multi-part, so I ended up creating a separate Faraday object for that:

    multipart_conn = Faraday.new(url: ENV["WORDPRESS_URL"],
      headers: {"Authorization" => "Basic #{auth_token}"}) do |conn|
      conn.request :multipart
      conn.response :json
    end
    

    It should have been possible to use a single Faraday object for all requests, but when you specify multipart, you need to take care of encoding the JSON requests yourself and adding them as one of the parts. This is where I got lazy and just moved on with my work.

    The code for creating the image in WordPress is this:

    extension = File.extname(logo_path)
    file_name = "#{name.underscore.tr("_", "-")}#{extension}"
    content_type = if extension == ".png"
      "image/png"
    else
      raise "Unexpected extension #{extension}"
    end
    media = multipart_conn.post("/wp-json/wp/v2/media", {
      date_gmt: (breach_date.to_time(:utc) + 12.hours).iso8601.to_s,
      status: "publish",
      title: title,
      comment_status: "closed",
      ping_status: "closed",
      alt_text: "Logo for #{title}",
      caption: "Logo for #{title}",
      description: "Logo for #{title}",
      post: post["id"],
      file: Faraday::Multipart::FilePart.new(StringIO.new(logo_request.body), content_type, file_name)
    })
    

    In reality, 100% of the images are PNG so I was ok with such a simplistic approach. When creating the FilePart I wrapped logo_request.body in a StringIO because it already contained the binary data of the image. If you have a local file you can just pass the path to FilePart.new and it just works.

    And now that I had the image, I could set it as the featured image for the post I created earlier:

    response = conn.post("/wp-json/wp/v2/posts/#{post["id"]}", {
      featured_media: media.body["id"]
    })
    if response.status != 200
      raise "Unexpected response #{response.status}: #{response.body}"
    end
    

    The reason why I didn’t create the image before creating the post was so that I could pass the post id to the image and thus the image would be connected to the post. I’m not sure how useful that is.

    And that’s all.

    I wonder if this code should be put in a gem and made reusable. WordPress points to the wp-api-client gem as the Ruby solution, which is read-only and abandoned. There’s also wordpress_v2_api, but I wasn’t a fan of the API (it’s almost like using HTTP directly), it hasn’t been touched in 6 years and I don’t believe it supports writing. I’m half tempted to fork wp-api-client, but does anybody else care, or is it just me? Please leave a comment if this is something you want to use.




  • people sitting on chairs beside their desks in an office

    Is the CTO title tainted? I think so

    by

    ,

    Warning: this is a rant.

    What a CTO does varies from company to company. One way in which the role changes dramatically is with the size of the department. When the tech department is:

    • 1 person, the CTO is mostly a developer.
    • 2 to 10 people, the CTO becomes a manager. They stablish what developers do and executes it.
    • 10 to 50, the CTO becomes a manager of managers. They stablish what developers do and what managers do to execute it.
    • Above 50 the role goes from tactical to strategic. At some point one or more VPs appear that and the CTO is purely strategic.

    There are other ways in which the CTO may vary from company to company. In some the role is purely internal, in others it’s customer facing, or community facing. That depends on what the company does.

    The problem with the CTO role is that the C part of it is not taking seriously

    My experience has been managing up to 20 people so I can’t comment on what the industry is like beyond that. I’m pretty sure some of the things I’m going to be ranting about here are not a problem for the CTOs of 100 people or more. That just can’t be true.

    The problem with the CTO role is that the C part of it is often not taking seriously. Let’s refresh our memory: it stands for Chief. Like the CEO, COO, CFO, being a CTO puts you in the executive team. Even if you are CTO of 1, that means you have (or should have) the authority and the responsibility to execute. That’s the difference between being a coder in a company of 2 and being a CTO in a company of 2.

    An example might help here. Let’s say to develop something needs to be bought: a computer, some software, a development unit of some hardware. Let’s imagine two companies, both which have a CEO but company A has a developer and company B has a CTO.

    The CTO present a decision that is in the best interest to the company based on cash position, cashflow, budget, etc.

    In company A the coder makes the request to the CEO and the CEO decides. In company B, the CTO would instead look at how much cash is in the bank, what the budget for the next quarter/year looks like, take a quick look at the P&L to make sure everything is marching well, make the decision and buy it. Even if there is still an approval process for the acquisition, the CTO doesn’t blindly make a request to the CEO. The CTO present a decision that is in the best interest to the company based on cash position, cashflow, budget, etc. That means the CTO needs access to that information.

    Equally, the CTO has the responsibility to do all that. The CTO leads the technical department, but acts on the best interest of the whole company and failing to do that means failure as a CTO. A CTO cannot hide behind “But that isn’t tech!” as an excuse. The same way that CEOs tend not to take CTOs seriously, and just consider them a cost center that produces code, CTOs tend not to act seriously when they need to step up to the challenge.

    I think a lot of this happens because the CTO title is given to technical co-founders and coders that are excited about building something, but not about all the other tasks CTOing imply. I was a bit like that 12 years ago or so when co-founded Watu, but I had to grow quickly to fill in the shoes of the title.

    Nowadays when I take the role of CTO, these are the responsibilities I take:

    • Producing the product that is core to the company.
    • Running all the technical infrastructure of the company, this includes what sometimes is referred to as IT.
    • Cybersecurity for the whole company.
    • The personal cybersecurity for the CEO and possibly other members of the executive team. This is an odd one, but I’ve seen how disruptive it can be for a company when the CEO is distracted because their email got hacked.
    • Keeping an eye on cash, cashflow, P&L and making sure my department is aligned. If I have a CFO, that’s great, but I can do it myself if it’s simple enough.
    • Work with the other departments to find how technology can enable them to execute their goals faster. This mean generally assisting customer support, marketing, and sales with technology to increase their efficiency.
    • Business continuity: I might not be as good as my CEO as many of their tasks, but if the CEO can’t perform them for whatever reason and there’s nobody else more qualified than me, I’ll jump, whatever it is: selling, raising money, anything and everything.

    […] what I want to do is go around the company and make it awesome by using tech to enhance the efficiency and efficacy of all departments

    My ultimate goal is the success of the company. A good friend of mine has been telling me for years: “You should go for COO roles, that’s why you’ve been doing for years now”. I resisted the idea but I’m started to be onboard. When I join a company as CTO, it’s like I’m told “Go sit in that box and produce code whenever we tell you, try not to make too much noise.” but what I want to do is go around the company and make it awesome by using tech to enhance the efficiency and efficacy of all departments. I want to make the company awesome. I worked at Google, I know what awesome looks like and I want to replicate it.




  • Originally my book was called “Building and Managing Distributed Teams“. I loved that title and people in my social circle loved it too. A friend of mine even told me something along the lines of “I’m so envious I wish I had that title”. And for the two years or so that it took me to write, abandon, restart, abandon again, restart and finally finish the book, I was happy about the title.

    I had three different people ask me what I meant by “distributed”. The first time I ignored it, the third time I panicked.

    As I finished writing the book and it went into proof reading phase, I thought I should try to market it a bit. I’m self publishing, doing everything, including promotion and marketing (hint: I can use your help in getting the word out). During conversations I had three different people ask me what I meant by “distributed”. The first time I ignored it, the third time I panicked.

    I’ve been working from home since the early 2000s. I’ve been building remote/distributed teams and companies since 2011 or so. At the beginning we were called and we called ourselves remote workers. But that soon started to carry a stigma. Companies would have in-office workers and remote workers and remote workers were second class citizens.

    This created a division between being a remote worker and working for a distributed company. The latter was much better.

    The companies that wanted everybody to be remote, the companies that were remote-first, the companies were being remote didn’t mean second class citizen started calling themselves distributed. This created a division between being a remote worker and working for a distributed company. The latter was much better. The movement of distributed work was growing, Automattic, Github, and many other companies were charging ahead… and then the pandemic happened.

    I don’t think the amount of people using the term “distributed” changed during the Covid pandemic, but the amount of people using the term “remote” did and might have turned “distributed” into a rounding error. The natural change of title for my book would have been from:

    Building and Managing Distributed Teams

    to

    Building and Managing Remote Teams

    I wanted to measure this, but I couldn’t find any way to do it. I tried Google Ads but I couldn’t make it work and no other method seemed to even be feasible. One of the problems I had is that I believe polls would be useless, because once you give context to “distributed”, I think everybody understands it, and it might sound better. I wanted to see how they behave in isolation. At any rate, “remote” won in polls, but not overwhelmingly.

    Since I was going to change the title, I may as well consider any and all possible titles, not just a single word change, right? My friend, Justin Megawarne, came up with a very important point: the title doesn’t contain the value proposition. Think of the book “The Four Hour Work Week” by Tim Ferris. If it would have had a descriptive title, like “How to Delegate Work”, he would not have been a bestseller author.

    I tried to find a value proposition name for my book and I gave up

    I tried to find a value proposition title for my book. Companies struggle to hire, grow and manage in-office teams. This is a pain that exists. My friend and advisor works with many companies like that, he wants to recommend them my book, but he knows they don’t believe a book by that title has the solution to their problems. I tried to find a value proposition name for my book and I gave up.

    If I remember correctly it took Tim Ferris weeks of research to come up with the title and cover of his book. I don’t have weeks to dedicate to this, in part because even with the perfect title and cover, without an editor and publisher, with just my own ability to market, it’s not going to have a positive return on investment. And thus, the new title was selected:

    How to Hire and Manage Remote Work

    I did introduce some extra changes. From the conversation with Justin I switched “Building” for “Hiring”, to have the keyword of the pain point a lot of companies are going through. I also asked Ana Bibikova for her opinion since she’s both a marketer and an author. She advised me to switch from imperative phrasing to “How to”. I’m not sure what the effect will be, I don’t have a strong opinion and I trust hers.

    And now, the list of explored and abandoned titles:

    • Building and Managing Distributed Teams (current)
    • Building and Managing Remote Teams
    • Hiring and Managing Remote Teams
    • Find the Best Talent Everywhere
    • Hire the Best and Keep Them
    • Stop Struggling to Hire and Managing Remote Teams
    • Hire Remote: Manage Remote: Stay Remote
    • Hire Remote, Manage Remote, Stay Remote
    • Doing It Better Remotely
    • Hire, Manage, Stay: Remote Working and What It Should Look Like
    • Do Better: Hiring and Managing your Remote Team
    • Remote Teams Done Really Badly (A How Not To)

    I think some of those might come back as titles of blog posts.




  • I’ve hired about 20 developers in my career so far (and I’m looking forward to hire more). When job applications arrive I separate them in three piles: Yes, No, and Maybe. It’s better to do Yes and No piles, but it’s a luxury that I haven’t had (if curious, drop a comment and I’ll write another blog post about it).

    In the No-pile I put all those people that are obviously not a match, people that explicitly tell me they never wrote code before, people outside the time zone target, applications with grammar so bad I can’t understand them, etc.

    […] the most important bit: I find some evidence that they have written code before.

    In the Yes-pile I put all those that show promise. Their application looks good, their profile match and this is the most important bit: I find some evidence that they have written code before.

    Continue Reading




  • I started coding when I was 7 years old and until I was 29 or so, my whole professional life was coding. Then, the startup I co-founded had to hire some people because it was doing well and I became a manager. I discovered I love managing as much as coding, but there was an ongoing issue: at the end of a day coding, I could look back at my code and feel productive, whereas at the end of a day managing, mostly meetings, I felt exhausted and with nothing to show for.

    I highly recommend it to all managers: write down notes.

    I’ve been managing for 10 years, taking over and building teams from scratch, being hands on and hands off and that feeling of not being productive is rarely there and I think there’s one habit that I have that helps a lot and I highly recommend it to all managers: write down notes.

    I go into every meeting with some note taking tool. If the meeting is face to face, I prefer to stick to pen and paper, because a computer can stablish a divide. The other person doesn’t know what I’m typing, I may be chatting with a friend. With pen and paper it’s immediately obvious I’m taking notes and there’s no wall (the screen) between me and the other person.

    But now we are all remote, and the notes are digital. This is so much better because it cuts down (but doesn’t completely remove) the need to process notes post-meeting. Depending on the type of meeting, I even share my screen so the other person can look at the notes I’m writing. You have no idea how many misunderstandings were caught this way. They said something, I misunderstood them, wrote it down in front of them and they corrected me. If you are not sharing notes, repeat what you wrote to the other person to have the same effect. This is similar to active listening.

    There are a few more things that I do with my notes that I highly recommend.

    I try to make all my meetings 50 minutes long, with 10 minutes to review and action notes. If we reach the 50 minute mark, ideally, I want to just book another one to continue. Having meetings overrun and everybody being late to the next meeting is very bad to the morale of a company but being the only person enforcing the strict end of meetings can be hard.

    When I review the notes, if the meeting was just the two of us or sensitive, I write them down on an email and I send them to the other people in the meeting. This helps have a shared record of what happened. Otherwise I write them down on a public record in a centralized documentation system, like Confluence or Notion.

    Looking at my written notes gives me the same feeling of accomplishment than looking at my written code. I’ve done something.

    Once a week I go through my week worth of notes to see if I have missed something. If they are written on paper this is when I digitize them for permanent record. This also informs the report to my boss about what happened that week. Looking at my written notes gives me the same feeling of accomplishment than looking at my written code. I’ve done something.

    If you found this valuable, you may be interested in my book: Building and Managing Distributed Teams.




  • All of them, of course, depending on what you are reading. Here’s a short overview of when to use each of them inspired by a Twitter conversation with Tania Dsouza.

    If the book is amazing and you need to highlight stuff, buy the Kindle version.

    If it’s a book that you lend or give away, buy paper versions

    Here’s my workflow for choosing:

    1. Use Audible whenever possible, because going through audiobooks is much easier than going through any other format.
    2. If the book has code or diagrams, most likely the audiobook won’t exist, but if you need to chose between Kindle and paper, choose paper. Big pages, diagrams, code, thumbing through pages are things that paper beats Kindle any day.
    3. If the book is amazing and you need to highlight stuff, buy the Kindle version. If it’s amazing, re-reading it is probably a good idea and Kindle is really good at highlighting sections. If you need to write notes, the Kindle device is not that good, but the Kindle app on your phone is and they do synchronize, so you can switch back and forth. If you are a non-linear note-taker, the paper version might be better.
    4. If it’s a book that you lend or give away, buy paper versions. Digital can’t be given away (not easily).
    5. If it’s fiction or something you’ll read very linearly and you won’t listen to the audiobook, buy the Kindle version. This is where Kindle is the best.
    6. If you want it signed by the author, or on your shelf, buy the paper version. A few times I listened to a book and it was amazing and I bought the paper version just because I want it sitting on my shelf. This is more book collecting than book reading and there’s nothing wrong with it.
    7. If you are in front of it at a shop and want it, just buy it. Don’t be dogmatic about using a single format for everything, be a multi-format reader.

    And now, the background story…

    I’m a book lover, I grew up in a house that didn’t have a library, it was a library. When I was a kid my mom told me “We always have money for books”. I actually found the limit of that statement, but that’s another story. By the time I moved out of my parent’s house, my own collection was about 200 or 300 books. I’m not sure, I didn’t keep it. I gave most of it away to a friend that was setting up a used book store during the 2001 Argentina financial crisis and the only reason it didn’t break my heart was because helping my friend came first. I like paper books, their feel, their smell. I have a small collection of signed books that a prize possessions.

    For a while I tried switching to one format to rule them all, but it doesn’t work.

    But I also love tech, I’ve been coding since I was 7 years old, and always playing with the latest technologies. Reading from an electronic device where I can access all books and all information gets me excited. I bought some of the earlier ebook readers, made by Sony, before Amazon dominated the industry with the Kindle. And like most of us, I’m very busy, and sitting down to read a book is not something that comes easy. When I started to use Goodreads I realized how little I was actually reading and I didn’t like it. Audiobooks came to the rescue. They allow me to read a book while doing mindless but necessary activities, like chores, working out, commuting (not a lot of that happening lately).

    For a while I tried switching to one format to rule them all, but it doesn’t work. Books are not all equal. Some work very well as audiobooks, some work very well in Kindle, and some require paper to be consumed. My method of reading books might seem a bit inefficient in that if I want to write notes, I end up reading a book twice. But if the end result is that I read more books, that lower inefficiency doesn’t matter because I increased my efficacy.

    If you are reading this blog post, I expect you are very familiar with paper books but considering Kindle and Audible, so I’ll just talk a bit more about them.

    With Kindle, you can have apps on your computer, phone and tablet as well as dedicated Kindle e-readers. They all connect to your Amazon account and they all get the same books and synchronize in which page you are. That means you may do most of your reading on a Kindle device, but open the app in your phone when you find yourself with some time to kill (better than doom-scrolling). You can start to experience Kindle with just your phone or tablet and buy a Kindle e-reader only if it’s working for you, but let me tell you, the screens on those e-readers are so much better for reading than your phone, they are much closer to paper.

    Kindle Paperwhite: to me this feels like the Kindle. It has some very important features: waterproofing and warm light. This is the one I recommend to most people.

    Understanding Kindle

    Amazon offers several Kindle e-readers:

    • Kindle: the most basic e-reader. If you want to save money, if you want to try, maybe this is a good starting point.
    • Kindle Paperwhite: to me this feels like the Kindle. It has some very important features: waterproofing and warm light. This is the one I recommend to most people.
    • Kindle Paperwhite Signature Edition: ok Amazon, you need to get better at naming things. What happened here? I don’t see why anyone would get this one to be honest. Auto-adjusting light? meh, I will adjust it anyway. Wireless charging? I plug my Kindle every other week. 32GB instead of 8GB makes no difference, books are tiny (unless you are storing audiobooks, which I don’t think you should).
    • Kindle Oasis: this is the top of the line, the most expensive, the luxury version. This is the one I have and it was a present. What used to be its killer feature, warm light, is not present in the Paperwhite version. It has some nice features, like the auto rotate page, the buttons, the mobile connectivity, but those only add value if you actually use them. Auto-rotate and buttons may be useful depending on how you hold the book. They are useful to me, but it’s hard to predict if they’ll be useful to someone else.

    Some extra things to keep in mind when buying a Kindle:

    You can store audiobooks in them, but then you need to pair your headphones to your Kindle. I have enough trouble with my headphones being paired to my phone and computer, I don’t need another device. When I’m listening to audiobooks I’m on the go, working out, doing chores. I have my phone on me, but not my Kindle on me. I don’t think this is a very valuable feature.

    All Kindles come in two versions, with and without ads. I don’t know if you can upgrade to not have ads, I always bought mine without ads. Make sure you choose what’s appropriate for you. They also tend to have deals with Kindle Unlimited. Kindle Unlimited is like the Netflix of books, where you don’t pay for each individual book. The catalog is hit or miss and I never got it. My partner reads way more books than me and she got it for a while. If you start a free trial, make sure to set a task to stop it to allow paying for a subscription you don’t want.

    Screenshot of amazon.com showing the options to buy a Kindle.

    When purchasing a Kindle, you can choose to have it tied to your account already. It’s a sort of pre-setup that they do. If it’s a present don’t chose this option. If it’s for you, it’s convenient.

    Kindles have two ways of connection to the Internet: wi-fi and mobile. Mobile now is only available in the Oasis, the most expensive one. I never got a Kindle with mobile connectivity but I had friends that did. If you are a person that’s on the go a lot, that might be convenient, because it’ll keep your page synchronized even when wi-fi is not present. If I’m on the go and I want to buy a book, what I do is make my phone into a hotspot, connect my Kindle to it, and then buy and download the book. This is very rare.

    I can’t comment on the Kindle for Kids since I never tried. Amazon lets you form a family and then everybody in the family can see the books of others. Unfortunately an Amazon family can only have two adults, which I find frustrating.

    Understanding Audible

    Amazon bought Audible, but it’s not completely integrated into the Amazon ecosystem yet. There’s a separate app from Kindle called Audible that you use to listen to audiobooks although the Kindle e-readers can also play the same audiobooks and I believe the Kindle app can do it as well. I still recommend you just use the Audible app on your phone, because you already have your headphones connected to your phone and your phone on you, what you need to listen to books.

    You can buy audio books one by one, but they are quite expensive. Audible offers several memberships that are much cheaper per book. There are four offerings:

    • Audible Premium Plus: 1 credit per month.
    • Audible Premium Plus—2 Credits: 2 credits per month.
    • Audible Premium Plus Annual—12 Credits: 12 credits per year.
    • Audible Premium Plus Annual—24 Credits: 24 credits per year.

    Who named these plans? This names are terrible, but that’s for another blog post.

    These plans give you credits. Once upon a time, books could cost 1 or 2 credits, depending on the length. I haven’t seen a book costing more than 1 credit in ages, so when you see “credit” you can read “book”.

    The higher you go in plan, the cheaper per credit they become, as you would expect. But the annual ones have an extra benefit. Credits accumulate so if you don’t use them, they’ll just pile up (at some point I think they expire, but that’s not a problem I had). If you find yourself with 0 credits and you are in a monthly plan and you want a book, you’ll have to buy the book, at its cash price, which can be as bad as double or more what a credit costs. If you have an annual plan, you can renew early. For example, I have the 24 credits per year, but if I run out of credits, and this has happened, I just click the renew button and start another year of subscription on that day.

    If you have an annual plan, you can renew early. For example, I have the 24 credits per year, but if I run out of credits, and this has happened, I just click the renew button and start another year of subscription on that day.

    My recommendation is that you get the 1 credit per month plan to give Audible a try, and if it’s working well for you after 3 to 6 months, switch to the 12 credits per year. If you run out of credits, then consider renewing early or switching to 24 credits per year.

    Some books in Amazon have a feature called whispersync. This allows to synchronize the page in Kindle with the position in Audible. You can be listening to a book in the car, get home, pick up your e-reader and continue reading. When a book has whispersync and you own one of the two mediums, generally the other one is much cheaper. I think buying audiobooks on deal through whispersync after you bought the Kindle version is cheaper than a credit (but Kindle + audiobook is way more than a credit). If you only use Audible with whispersync-ed books, a membership might not make sense at all. I can’t comment beyond that because I have never used whispersync.

    And that’s all. I hope this post helps you become a multi-format reader and that allows you to read more. It certainly help me:

    Picture showing my reading challenges since 2011 until 2022, all completed, where I read a total of 362 books.

    Happy reading!




  • This blog post is a sample chapter from my book:

    How to Hire and Manage Remote Teams

    The term one-on-one evolved to refer to a specific type of meeting and does not mean any general meeting that has two people on it. One-on-ones are the regular meetings between a manager and each of their reportees. One-on-ones are always important but in a distributed team they become critical – mainly because you are not going to be able to run into your reportees on the hallways and have a quick meaningful conversation opportunistically.

    A one-on-one has several goals and I recommend the relevant chapters on The Hard Thing About Hard Things (Ben horowitz) and High Output Management (Andrew Grove) in order to understand more about how to conduct them and their importance.

    The main and most critical role of the one-on-one is to identify problems, or potential problems, as early as possible. By the time one of your employees tells you they have another job offer, more often than not, it’s way too late to do anything about it. The issues leading to their moving posts will have started long before, perhaps months, and the opportunity to address them will have been when it first arose. If you’re not aware, and not providing the opportunity for your worker to make you aware, a problem can fester beyond the point of salvation. The one-on-one aims to reduce this possibility.

    A one-on-one is the time when an employee can bring up small issues:

    • I’m not happy with our project.
    • Work is boring.
    • I feel my ideas are ignored.
    • This person is being rude to me.
    • The way we work just sucks.

    And from that information it is your job to start fixing it. 

    However, it is unlikely your employee will feel empowered to say any of this unless they already trust you. For this reason, one-on-ones should not be reserved for only dealing with critical issues, or when you suspect there could be a problem. Routinely meeting is an exercise in building the rapport that will be required for the worker to bring up any real problem.

    For those uneventful one-on-ones, it is important that you keep a balance between listening and sharing. If you don’t share anything at all, you’ll end up coming across as an interrogator. It is through sharing that you show them that you are listening and empathizing with what they are saying.

    The opposite tends to be a bigger problem. If you as the manager go into long monologues during the one on ones most of your employees will respectfully listen and hate every minute of it. Many of us tend to have a bias that means that if we feel we spoke for 50% of the time, we actually spoke 70% of the time, so you might need to rein it in.

    Since you are doing this remotely, you could get a stopwatch and during a couple one-on-ones measure how much you talk or how much they talk. Don’t worry about getting too precise (for example, when switching back and forth quickly during clarifying questions). This is just a rough approximation. Your performance during those one-on-ones will be distracted, so this isn’t something to do regularly, but it can be a useful self-test to show yourself your baseline.

    To achieve a good balance, here’s a recipe you can follow:

    1. Start with the pleasantries: How are you? Fine, you? Fine. This is neither sincere nor useless. It’s a protocol to start communicating, it establishes cadence, tone of voice. Don’t ignore it, but also don’t take it at face value.
    2. Ask one or two questions to let the worker become comfortable talking. “How was this week?” or “That was a good release, wasn’t it?”
    3. Re-ask them how they are doing: “Now, really, how are you doing? All good in your life?”. Now is when you need to start practicing silence.
    4. Ask them if they have any questions for you. Continue practicing silence.
    5. Ask them what was the best or worst part of the week. Again… silence.

    When I say practice silence, what I mean is that you ask the question and then shut up. Different people take different amounts of time to start talking. Especially if they need to bring up a difficult subject, which can require mustering some courage. Give them time and space. This will feel uncomfortable, but it’s a skill you need to master. There are some stereotypes that introverts are more comfortable with silence than extroverts, but I’m not sure how true it is. If you are a manager, you are probably more comfortable talking than the worker (if they are developers for example), so you might need to put up with more discomfort.

    The initial “How are you?” question is part of the protocol of starting a conversation. There are some studies that show that it establishes speed cadence, tone of voice and other aspects of communication. What it’s not is a sincere question of how someone is doing. Don’t expect people to answer it truthfully; if they do, great! But most people need to be asked twice. But… avoid asking twice in a row. When we are asked the same question twice in quick succession, it engenders the feeling of being accused, as though we are lying or are being unreliable – so most of us will dig in our heels and avoid changing our answer. Most of us need to warm up to a conversation before we can answer truthfully. So ask some other benign questions, and then circle back round to it. 

    If at any point during that recipe your worker takes off on a tangent that is useful, as in it’s providing you with the information you need about their wellbeing, drop the recipe and follow their lead. The recipe is there for the cases where a worker is being more passive, which is likely to be true when you are just starting to work together.

    I recommend taking copious notes during the ones-on-ones and following up on things that were happening. These notes should be strictly private.

    I tend to run one-on-ones in two different schedules:

    • Weekly but optional.
    • Every other week but mandatory.

    Every other week but mandatory is the default way I use to schedule one-on-ones. Weekly but optional is a scheme that I use under many special circumstances:

    • The employee and I don’t know each other well.
    • The employee is new to the team.
    • I am new to the team.
    • There’s an ongoing issue or conflict.
    • They are a junior employee needing more guidance.

    The optionality has limitations: we can skip one, if they are being productive and have no pending issues to discuss in the one-on-one. Once it’s skipped one week, the next week it becomes mandatory.

    Normally I book one-on-ones to last 25 minutes with five minutes for me to finalize my notes. If someone reaches the end of the one-on-one and there are pending issues to resolve, book another meeting straight away to continue working on it (this rarely happens).

    It’s very easy for one on ones to become status reports. It’s something easy for the worker to say, and it’s something easy for the manager to consume, but the one on ones are not about performance or what got done. To drive that point: imagine the situation in which the line manager and the project manager are different people, the line manager does the one-on-one but the project manager cares about the status reports of what has been done. 

    Instead, I suggest you just say something along the lines of: “This is not about a progress report, but was there anything you enjoyed or that annoyed you this week?”

    That last part of the question allows the worker to do a retrospective and instead of talking about having achieved tasks A, B and C, they can talk about how whilst doing C they had a conflict with another worker; or how they loved doing B and wished they were doing more of that. Those are important signals for you.

    The one-on-ones cannot be extremely transactional. It takes time for someone to be comfortable to tell you about a problem they have. This is normal: people literally go to the doctor, where their confidentiality is protected by law, and still procrastinate on sharing something because it’s uncomfortable. So don’t expect that a worker will just show up and tell you there’s a problem because you have an “open door” policy. You need more than that. You really need to prove yourself approachable proactively, and that happens through repeated positive small interactions.

    If, like me, you have a terrible memory, write down the names of their spouses, children, pets, birthdays, what’s going on with their lives and ask them about it the next time (“how was your holiday to Mallorca?” or “How was [daughter’s name] school play?”). These are notes that I consider extremely private; not to be shared with employers or other managers. I don’t even write them on a medium they could gain access to (normally I use paper). For me, it’s the same as with any other friend: I have a calendar with their birthdays, because it’s important that I don’t miss them.

    In Summary: one-on-ones are often neglected or perceived as only necessary when something is already wrong. In fact they are a vital means of establishing rapport with your team and keeping on top of what’s going on with your employers. This is really the only way you’re going to be able to identify minor issues before they become big problems, and has knock-on effects on employee retention, team morale, and productivity.

    This blog post is a sample chapter from my book:

    How to Hire and Manage Remote Teams




  • Now that a lot of the world is trying to go back to normal post-pandemic I see hybrid work being proposed as the solution and I strongly disagree that it is the future. The problem with hybrid work is one of real estate. To understand that, let’s go back in time to 2019, before we knew what a Coronavirus is.

    Companies would open offices in cities like New York and London despite the fact that their real estate was among the most expensive in the world and the salaries were among the highest in the country. Why is that? Why not open an office in Alaska? Or Scotland? Well, it’s because you need to hire talented people and hiring in Alaska or Scotland is hard because you lack the density of the workforce that you can find in the likes of London and New York..

    But why not open the office and have people move to those places? Well, for the workers it’s the same equation. They want the density of opportunities. They want to be able to quit the job and have another one. They want a career. That’s why the workers are willing to live in tiny dark flats in New York and London while spending half their salary on rent. They could move to Scotland and Alaska and find better and cheaper houses, but they wouldn’t have the jobs.

    Those tiny dark shared flats of the Londons and New Yorks of the world are not suitable for working from home. There’s not enough space for them to have a comfortable office in them. This is not a problem for your average office worker and it’s not a problem for your average distributed/remote worker, because the latter will not live in those cities. But this is a problem with hybrid work.

    The problem with hybrid work is that out of the revenue of the company you need to pay for an office in a central location, like London or New York, the salaries of high density cities, and the reals estate of a big enough flat or house in those locations for people to have space at home to work comfortable. Pretty much no company has that amount of revenue, and no company should destroy their own profits with such a decision. This is why hybrid work doesn’t work.

    I think hybrid work is a reaction to the challenges and fears of running a fully distributed company. For many managers, bosses, and owners it’s been very hard. They still want to see their workers, but the workers want to stay at home. My recommendation is to learn to live without workers at the office. This doesn’t mean no face to face interaction. Instead face to face interaction should be crafted to maximise what they are good at, which is forming bonds among people and working on big ideas.

    Instead of meeting every other day at the office and spending half of that day on video conferences anyway, it would be much better to meet once a quarter or every 6 months at a retreat somewhere, a hotel for a couple of days or a week of very intense work. If you want to learn from the masters of this, read The Year Without Pants. If you are wondering where the budget comes for such an extravagant expense:

    • Not paying for an office.
    • Lower salaries due to people not being in London or New York.

    There are exceptions to this rule. There are some companies that have a fixed location, such as universities and hospitals. Those companies might want to have hybrid work to emulate and  get some of the advantages of remote work. These exceptions should be rare in my opinion.

    If you want to learn more about building and managing distributed teams, I am still writing my book on the subject.




  • I just figured out how to use Font Awesome 6 in a Rails 7 project that uses importmaps. I’m not entirely sure why this works and why some of the workarounds are needed, but my googling yielded no results when I was searching so hopefully here I’ll be saving the next person some time.

    If you search Rubygems for gems with the name “font awesome” you’ll find quite a few but I didn’t like any of them. They all use the font version of the icons, instead of the SVG, or they are very outdated, or they expect you to use SCSS, which I’m not using at the moment. But ultimately, the team at Font Awesome maintains the NPM packages and we should use those directly, not re-wrap packages that will always be out of date.

    For me, using NPM packages directly was higher priority than using importmaps. That’s how strongly I feel about it. I would have installed Webpacker to use Font Awesome’s main package.

    I managed to make this work, but if I’m frank, I’m not 100% sure why the workarounds are needed, so if you have any insights about it or how to improve this, please drop a comment.

    Font Awesome’s documentation says you should install the fontawesome-free package:

    npm install --save @fortawesome/fontawesome-free
    

    Instead we are going to pin that package, but also some of the dependencies we need later:

    ./bin/importmap pin @fortawesome/fontawesome-free \
                        @fortawesome/fontawesome-svg-core \
                        @fortawesome/free-brands-svg-icons \
                        @fortawesome/free-regular-svg-icons \
                        @fortawesome/free-solid-svg-icons
    

    This adds the following lines to your importmap.rb:

    pin "@fortawesome/fontawesome-free", to: "https://ga.jspm.io/npm:@fortawesome/fontawesome-free@6.0.0/js/fontawesome.js"
    pin "@fortawesome/fontawesome-svg-core", to: "https://ga.jspm.io/npm:@fortawesome/fontawesome-svg-core@1.3.0/index.es.js"
    pin "@fortawesome/free-brands-svg-icons", to: "https://ga.jspm.io/npm:@fortawesome/free-brands-svg-icons@6.0.0/index.es.js"
    pin "@fortawesome/free-regular-svg-icons", to: "https://ga.jspm.io/npm:@fortawesome/free-regular-svg-icons@6.0.0/index.es.js"
    pin "@fortawesome/free-solid-svg-icons", to: "https://ga.jspm.io/npm:@fortawesome/free-solid-svg-icons@6.0.0/index.es.js"
    

    Then Font Awesome’s documentation says you should add these lines to your code:

    <script defer src="/your-path-to-fontawesome/js/brands.js"></script>
    <script defer src="/your-path-to-fontawesome/js/solid.js"></script>
    <script defer src="/your-path-to-fontawesome/js/fontawesome.js"></script>
    

    Which might make you think this is a good idea:

    <script defer src="https://ga.jspm.io/npm:@fortawesome/fontawesome-free@6.0.0/js/brands.js"></script>
    <script defer src="https://ga.jspm.io/npm:@fortawesome/fontawesome-free@6.0.0/js/solid.js"></script>
    <script defer src="https://ga.jspm.io/npm:@fortawesome/fontawesome-free@6.0.0/js/fontawesome.js"></script>
    

    But it doesn’t work. It fails with this error:

    Here I’m a bit confused. How come it fails with that error? Any ideas?

    What did work was editing app/javascript/application.js and adding::

    import {far} from "@fortawesome/free-regular-svg-icons"
    import {fas} from "@fortawesome/free-solid-svg-icons"
    import {fab} from "@fortawesome/free-brands-svg-icons"
    import {library} from "@fortawesome/fontawesome-svg-core"
    import "@fortawesome/fontawesome-free"
    library.add(far, fas, fab)
    

    I can’t help but feel that there’s a function or method in fontawesome-free that I could call that would do all the setup automatically with less imports and less library building, but I couldn’t find it yet.




  • light inside library

    I have a problem: 3 or 5 stars?

    by

    I’m an avid reader and I review every single book I read. I force myself to write at least two paragraphs. This is useful to me because sometimes I forget I have read something; seeing and reading back my own reviews answers the ‘did I already read that’ question but also refreshes my memory on what I thought of it. I do this in Goodreads, where I’m asked to provide a star quality rating of the book, and that’s where the problem starts.

    Normally, I rate them for myself and my rating is this:

    • 5: Amazing book, humanity is better off because this book exists and everyone should read it.
    • 4: Great book, will recommend it to most people.
    • 3: Good book, I enjoyed reading it.
    • 2: Bad book, I didn’t enjoy reading it.
    • 1: Terrible book, this is actively harmful for humanity and should not have been written.

    This naturally means most of my books get 3 stars, some 4 and 2 and even less 5 and 1. It’s a bell curve! Which should surprise no one. Actually, I think there are way more books in the 1-star category out there for consumption, it’s just very rare I accidentally read one. 

    But this is not how most people use star ratings. And it is also not how we are encouraged to use them either. Take Uber: in the event you did not give five stars, it specifically requests you to answer what was wrong with the trip. If the trip was perfectly adequate, it is expected that this be rated five stars. The upshot of this is that there is no way to reflect service that went above and beyond, or was otherwise better than ‘fine.’

    So most people give 5 stars unless there’s something wrong, in which case they start removing stars. 1 thing wrong? 4 stars. 2 things wrong? 3 stars. I think this is a bad way of rating things because, as mentioned above, it means you have no way of differentiating good, great and amazing: they all get the same 5 stars. For a service like Uber this is not such a problem, but for artistic works and for books it doesn’t fit. 

    I used to just do the rating for myself so I didn’t care I was using a different system to the rest. But when publishing on Goodreads and interacting with other people it became rather controversial: I have received both praise and criticism for this. Some people caught on and they know that when I give 4 and 5 stars, it’s a rarity and worth taking a look. Some people asked me why a book that I enjoyed, and recommended to them, is getting only 3 stars.

    What’s really bothering me with my discrepant system is that an author gets a (small) penalty for me being interested in them. Granted, this is tiny and unlikely to be noticed in the grand scheme of readers, but it still bothers me. Their average will go down, which negatively affects public perception, even though it really shouldn’t be perceived that way (to my mind). It also bothers me that an author might see 3 or 4 stars and be hurt and then confused by my positive review.

    Should I give up and remap my review system to what everyone else is doing? I dislike losing a way to signal “This book is amazing” By all means send your suggestions.




Hi, I’m Pablo, this is my web site. You can follow me or connect with me:

Or get new content delivered directly to your inbox.

Join 4,044 other subscribers

I’m writing a book

Stack of copies of How to Hire and Manage Remote Teams

How to Hire and Manage Remote Teams, where I distill all the techniques I’ve been using to build and manage distributed teams for the past 10 years.

I write about:

announcement blogging book book review book reviews books building Sano Business C# Clojure ClojureScript Common Lisp database Debian Esperanto Git ham radio history idea Java Keep on Posting Kubuntu Lisp Non-Fiction OpenID programming Python Radio Society of Great Britain Rails rant re-frame release Ruby Ruby on Rails Sano science science fiction security self-help Star Trek startups technology Ubuntu web WordPress

I’ve been writing for a while: