Made some cream cheese kolaches for a taste of Texas. Shouldn’t have quartered the recipe. Will have to try again soon with deeper wells or less filling.

How millions of French shoppers are rejecting cut-price capitalism

How millions of French shoppers are rejecting cut-price capitalism

I’ve said it before, I love the French.

Seeing this awakening of consumers is such a breath of fresh air. For an extra 5 bucks a year, your farmer isn’t going bust and is able to make a living. Totally worth it. No brainer.

He pictures the brand’s archetypal target customer as “perhaps the couple in their mid-30s, working parents, young kids, highly conscious of the climate crisis, the need to eat healthily, of animal welfare, single-use plastics in packaging, the plight of the farmer … but maybe unable to afford full organic. Well, we’re the answer.”

Guilty on all counts. Great customer analysis.

Back when Macs came with modems built in, the one feature that I thought was super cool but never used was the Print to Remote Fax feature. It was one of those features like “Duh, of course. We can create PDFs. Naturally we can send them over the modem for printing.”

Things I’m Thankful For

Each year around thanksgiving I like to reflect on the year and think of all of the things I’m thankful for. From there I keep a mental note of the “but if only” thoughts I have and use them a base for the next year’s goals.

Family

My family is generally healthy. We’re exhausted chasing a toddler around all the time, but healthy. Before being a Dad, I couldn’t imagine the amount of joy this little guy would bring into our lives.

Even though I’m halfway around the world in Japan, I still keep in pretty regular contact with my family. I’m not on Facebook proper, so most of it is actual text messages and phone calls.

I’m also thankful my older in about a month. It’s been about 3 years since I last saw him.

Health

I’m still young-ish and have my health and I’m thankful for that. But I know that my habits aren’t entirely healthy and that will eventually catch up with me as I get older.

Work

I’m thankful to have a job that pays well enough, is forward thinking, and flexible. I have about as much freedom as when I was freelancing / contracting without any of the stress of doing sales and riding the feast or famine rollercoaster.

While I still really want to have a successful product and “do it all myself” one day, one of the main motivators for wanting that was to have flexibility in how I work. With those nerds met, putting out my own shingle lost some of its luster. Even Johnny Ive has (or had) a job.

Sense of Place

This year is the first year in my life where I have a sense of place. I moved every couple years as a kid, so I learned to never get too attached to any one place.

This year I got my permanent residence in Japan, which has allowed us to buy a house in Yokohama - in a neighborhood where I feel relaxed when I go home at night. It’s super quiet at night and still less than an hour to Shinjuku.

It’s the first time in my life I’m actually planning to be in the same physical location longer than 2 years. I’m thankful to be in the position to be able to buy a home and make a place that Leo can “come back to” when he’s older.

2019 has been a good year for us and has given me a lot to be thankful for. I hope that 2020 is as nice to us as 2019 has been.

How to Disable Slack WYSIWYG Interface

A simple method for disabling that horrid new Slack WYSIWYG interface.

export SLACK_DEVELOPER_MENU=true
open -a /Applications/Slack.app

Open the console CMD+OPT+i

javascript:(_ => {
  const redux = slackDebug[slackDebug.activeTeamId].redux;
  const {wysiwyg_composer, wysiwyg_composer_ios, wysiwyg_composer_webapp, ...payload} = redux.getState().experiments;
  redux.dispatch({ type: '[19] Bulk add experiment assignments to redux', payload });
})();

Needs to be run in each team that you’re a part of.

An Overview of PDF Libraries in Python

The PDF file format is a ubiquitous file format and the only real way to guarantee document layout and display, no matter the device or operating system used to view it . Python, being a language that excels at data processing and manipulation, naturally has a lot of tools for working with PDF files to generate reports. This post is a brief introduction to the tools that are available and the tasks they work best for.

Wand

Wand is a set of Python bindings for do-it-all ImageMagick library. As such it really a Swiss-army knife for PDF (and image) manipulation and generation. In the context of PDF, ImageMagick (and therefore Wand) is mostly a frontend for GhostScript.

Its API is quite Pythonic and can help you split, convert, and even draw on PDF files. Wand is perfect for manipulating existing PDFs and doing light editing on them.

ReportLab

ReportLab is a commercial/open-source PDF generation library. If you’re making complex PDFs from scratch this is the library you should pick. Period.

PikePDF

PikePDF is a PDF manipulation library based on qpdf. As its underpinnings are written in C++ it’s super fast. Unlike other python pdf libraries, PikePDF supports unlocking encrypted / password protected PDFs.

PikePDF also lets you explore the internal structure of a PDF document, which make it a perfect tool for debugging problem PDFs and extracting content/images.

The APIs are very Pythonic, and let you work with manipulate pages / page order like a regular list. PikePDF is also great for repairing and prepping PDF to be manipulated by Wand.

Pillow

Pillow is a PDF library, but it supports exporting images to PDF, making it a powerful tool in your Python PDF toolbox.

While there’s some overlap of functionality Wand in terms of image editing capabilities, it’s more focused on editing images, rather than transforming and converting images. Pillow is an indispensable tool when working with any user-supplied images in your PDF workflow.

Conclusion

There is no single PDF tool in Python that fits all needs, all the time. These libraries can, and are, often used in conjunction with one another to quickly and easily generate PDFs on demand. However, depending on how you combine them, there can be some issues resulting in large file sizes and slow generation times. I’ll cover these gotchas in future posts.

Checked in at Starbucks (Starbucks Coffee 戸塚店). Used to come to this Starbucks almost everyday when I was an exchange student. Old haunts.

Unit Testing django-graphene GraphQL endpoints with pytest

On a project at work I’ve been learning GraphQL. I’m in charge of both developing the backend ( using the wonderful graphene-django package) and the frontend ( using Typescript / Vue.js / axios ) for this specific feature.

After wrapping my head around GraphQL and getting a basic endpoint working I wanted to write some tests to ensure that filtering and other requirements are working as expected.

For a proper End-to-end test I’d usually setup a client and post a json dictionary or such. With End-to-end GraphQL tests you need to send actual GraphQL queries, which makes sense but it feels a bit like SQL Injection.

Below is how I’ve settled organizing and writing my GraphQL tests.

tests/
├── __init__.py
├── conftest.py
├── test_myapp/
│   └── test_schema.py

Because the graphql client will be reused across the django site, I added a global fixture that will automatically load mty project’s schema.

# tests/conftest.py
@pytest.fixture
def graphql_client():
    from myproject.schema import schema
    from graphene.test import Client
    return Client(schema)

In this example I’m testing that I’m filtering data as expected when passing a search parameter.

For setup, first I write a query as its own fixture so I can re-use it throughout the test and it’s clear exactly what is going to be run. Second, I make sure the query uses variables instead of hard-coded values when querying so I can change the input depending on the test. Third, setup a model_bakery fixture for data that I expect to find.

import pytest
from model_bakery import baker

@pytest.mark.django_db
class TestMyModelData:
    @pytest.fixture
    def query(self):
        return """
query testGetMyModel($searchParam: String!){
  myModelData(searchParam: $searchParam) {
    totalCount
  }
}"""

    @pytest.fixture
    def my_model(self):
        baker.make(
            "myapp.MyModel",
            total_count="20", # Decimal field    
            )

    def test_none_response(self, graphql_client, query, my_model):
        executed = graphql_client.execute(query, variables={"searchParam": "skittles"})
        assert executed == {"data": {"myModelData": None}}

    def test_filters_usage(self, graphql_client, query, my_model):
        params = {"searchParam": "skittles"}
        executed = graphql_client.execute(query, variables=params)
        assert executed == {
            "data": {
                "myModelData": {
                    "totalCount": 20
                }
            }
        }

Executing each test I simply pass my query and required variables for the test/query. In this I’m testing the same query twice: once with and one without a searchParameter. My expectation is that I get no results without a search term and data when to my graphql_client fixture.

As the return value from our client is a dictionary, I can simply assert my expecte results with the actual results. If something changes I’ll know immediately.

Using the techniques above I can easily add new tests for my GraphQL endpoint as the available changes or bugs are found.

Did a presentation at work today about editing PDFs with Python. Mixing and matching libraries is fast, but you’ll run into a bunch of inefficiencies that result in slow processing and huge files. I should write a book. For serious.

Always Solve for X

Reflecting back on the products I’ve released over the years I noticed a key difference between the successful products and the non-successful products. The difference wasn’t in market or craftsmanship. The difference started before I wrote a single line of code.

With ImageXY we were focused on designing a solution to real estate agents uploading photos that were the wrong size or too large into a crm. When building it we concentrated on that single use-case and kept our solution focused. The result was a batch image resizing app that didn’t have all the complexities of its competitors. And it turned out a lot of non-real estate agents also had the same problem and our solution worked for them as well.

Other products, like Byoyomi, a timer application that let you save and run multiple timers on your Mac, were flops. The application was stable and worked as advertised, but it was more of a solution in search of a problem.

As developers its easy to dive straight into writing code or designing interfaces the moment we have an idea that we think might work. And as a developer taking those random ideas and turning them into a reality is fun. But the chances of those inspiration-turned-hacking sessions turning into a successful product are slim.

Instead of diving into code the moment we have an idea, it’s critical that you do the hard work before your hacking sessions. The work that isn’t necessarily fun and feels like work. Take a step-back form Sketch and define, with words, the problem you’re trying to solve.

If you can’t clearly articulate the problem and who’s having that problem, any solution you build will be equally muddled.

When designing anything, you first need to define the problem that you’re trying to solve.

The major difference between my successful products and those that were just that. The successful products had a clear problem that they were solving for a specific niche while the unsuccessful ones did not. It’s much easier to solve for X when you’ve looked at the rest of the equation.

Listening to the Rework Podcast and @mijustin’s idea of wanting to build calm technology company with @transistorFM completely resonates with me. His interview starts halfway-ish through.overcast.fm

More great things coming out of Helsinki (besides my favorite Marimekko, iitara, Aalto, and Linux). Maybe not as high up on the list, but Yotto is pretty great.