• Response to We’ve all been there: on boolean environment variables.

    Environment values are strings. True becomes "True" and False becomes "False".

    And, well, what does "False" evaluate to? True. True.
    I think the best way to handle settings with Django is to use django-environ.Β  Not only does it handle .env files. It also has a lot of utility methods for converting values to native python types ( bool, list etc..) and using database urls. It's great.

    My airbot settings.py uses it. My airbot settings also lets you specify the path for your .env with the ENV_FILE environment variable, so you can create different files for different environments.
  • Launched a fun feature in Tanzawa today: Search. There isn't a direct link to a search page, but clicking the place name in a post will search for all posts within 2km of that post.

    Search results
  • Build Open Systems And Maintain The Promise For Future Generations

    Growing up in the 90's, tech and the internet promised us open-data and open-systems. With a good idea and a bit of know-how could do most anything. And for a while that was true. But over time the systems have been slowly closed off.

    Even if you put your data into their systems you can only retrieve it under their terms. If you can even retrieve it. Formats are opaque or undocumented. API access could be revoked at any time for any reason with little or no recourse on your part.

    In other words: your data isn't yours. And you're certainly not free to do with it what you please.Β 

    Why do people subject themselves to this unfair and unequal status-quo? I'd argue that it's because how people view tech, including within the tech circle, has changed.Β 

    You can draw a line: Hackers vs The Social Network.

    If you watched Hackers, Sneakers, or Wargames in high school, you likely remember that promise of open-systems and open-data. You also see that promise being reneged one company after another. You may not feel it's as important as it once was, because, let's be real, goofing around on "free" services is easy and fun.

    However if your high school movie was The Social Network, you likely see the current state of tech as normal. Like a fish in water. Those VC companies neglected to mention the promise of the internet. In fact, the idea that your data is yours may not even be something that crosses your mind. Why should it? Nobody talks about it, so it must not be important. But it is.

    One of my major motivations for building Tanzawa is to help us regain control of our data and help uphold the promise back.Β  Want to visualize your Tanzawa data for a new project? Point your project to your Tanzawa db (or make a copy of it) and you can do whatever you want.

    The promise of open-systems and open-data isn't a given.Β  The default is closed. Or at least open until you're big enough consolidate and centralize. It's up to each of us to be stewards of an open internet. It's up to each of us support an open and free internet.

    Build open systems and maintain the promise for future generations.
  • Response to Changes at Basecamp

    1. No more societal and political discussions at Basecamp.
    2. No more paternalistic benefits.
    3. No more committees.
    4. No more lingering or dwelling on past decisions.
    5. No more 360 reviews.
    6. No forgetting what we do here.
    I don't work for and don't use Basecamp/Hey, but this was a difficult and disappointing read.Β 

    Not allowing societal and political discussions at work is a tough call, depending on the internal state at Basecamp. With so much injustice in society finallyΒ  coming to a head, people are going to want to talk about it with other members of society (their co-workers). If the company chat (though this is Basecamp, maybe they don't have one?) is a dumpster-fire 9 - 5 with non-stop political discussions, it speaks to a larger issue with the company culture and individual impulse control.

    Blanket disallowing political discussion removes the opportunity to teach employees a valuable life skill on the internet: learning to not argue on the internet and ignoring the trolls because they will always have more time than you. It seems to me that you'd be better served by taking the instigators aside and having a frank conversation about time management. Learning to turn on the blinders and focus on the task at hand is an important skill.

    Removing the "paternalistic benefits" was also disappointing to see. We know without a doubt that exercise is good for us. Getting food from the farmer's market not only gets you quality product, but also strengthens your local community. These are things we should want to encourage.Β 

    Saying that we're giving you a profit share and you can spend your money how you'd like ignores the psychological aspect of these kinds of benefits. Having that little bit of "extra" or "free" makes it mentally much easier for employees to make better choices that benefit everyone.
  • Seeing that Basecamp is shutting down their famous Signal vs Noise blog, I can’t help but wonder how much was the faff of dealing with Wordpress.
  • First Days with Tanzawa

    This was my first week using Tanzawa to power my actual blog and not just the dev blog. So far it's been great. I love how easy it is to post. I love that my site is IndieWeb native. I love that my site's stability has improved because I no longer require a database server. And I love that it's using fewer resources. It's great.

    This said, there's been a few rough edges that need polishing. Approving 50 some-odd webmentions after OwnYourSwarm started importing un-sent checkins required 50 some-odd page loads. Ouch.Β 

    I'd also like to improve site performance more in respect to images. Currently Tanzawa automatically requests the most efficient image format that your browser supports. Image format selection is all handled by the browser automatically (no Javascript). This alone usually cuts transfer size in half.

    While cutting the transfer size in half with a format change is a good start, I still don't need to be serving (at times) 4000px wide images. This is noticeable in streams where posts usually have images ( Checkins etc..) where the text loads instantly, but the progress bar lingers while images load.

    Rather, I'm going to change it to serve a resized (max 800px wide? ) image unless the original is specifically requested.

    Lastly, I want to start building a list of things that must (not should) be done before I can feel comfortable releasing Tanzawa for others to use and then start working on that list bit-by-bit.
  • Response to https://twitter.com/simonw/status/1384383772255084546?s=20

    I still think it's rude to return MBs of data if your client device might be an inexpensive mobile phone, but for things like server-to-server API responses I May have been being way too early 2000s in my thinking Turns out returning 10+ MB of JSON works fine these days!
    I used to think similarly until I started thinking about compute in terms of carbon emissions (all data transfer/parsing/sending/storage requires electricity and thus likely carbon emissions for now). Since then I try to minimize all compute wherever possible.
  • Protocols Not Platforms

    The magic of web 2.0 were the open apis. Developers could use these apis to mashup services how they wanted. Sometimes these developer's tools and mashups became so popular that they would come to define the entire service of which they were building atop. Both hashtags and the term "tweet" originated outside of Twitter, Inc.

    But when these services grew they morphed into platforms. Their apis were closed off and the developers that helped these companies find their success either kicked off or severely limited in what they could do. This became a pattern, not just with Twitter, but many services that found success in thanks part to their open api followed the same playbook.

    Existing players making unpopular changes to their policies is usually a boon for the upstart. Each time this happens a vocal group of users becomes dissatisfied with the platform who then attempt to migrate to an alternative. However each migration causes some kind of loss. Data doesn't transfer or communities fracture because not everybody moves. Not to mention the energy that could have been spent doing something else.

    Contrast this with something like email. You can email anyone you'd like, even if they don't use the same provider as you. If your mail provider changes a policy you don't like, you're free to change providers without losing your identity on the internet. People can still contact you the way they always had and you can still contact them. Your data can move from platform-to-platform seamlessly. There's nothing re-organizing or hiding emails from your inbox unless you setup the rules (or use gmail).

    The difference in experience between twitter and email is night and day. One keeps you locked in and subject to their whims, while the other gives you the choice to use it however you see fit. The difference is that twitter is a platform and email is a protocol. Pick protocols.

  • Aggregating Nested Values with JSONFields

    Note: I originally wrote this for the Kwoosh Workshop blog. Since it's no longer around and I'm posting it here.


    Integrating with 3rd party APIs you'll often need to implement a webhook for your application to respond to external events. It's useful to take the event data and store it in your Database for future reference.

    As Kwoosh is run out of Texas, users in Texas need to pay an 8.25% sales tax. To my surprise Stripe's
    dashboard doesn't seem to offer an answer to a simple question: How much did I collect that was taxable
    and how much do I need to remit to the state for last quarter's sales.

    Armed with our event log data and Python we can quickly get that the numbers we're looking for.

    Our data looks something like this. Naturally a real event would have a lot more data, but for our purposes
    today this should suffice.

    {
    "data": {
    "object": {
    "tax": 25
    ...
    }
    }
    }

    This data is sent with each invoice.payment_successful event and it's saved in aa JSONField in our database. Using the KeyTransform we can extract values from our JSONField and annotate them
    to our QuerySet. Even better, as of Django 1.11 we can nest our KeyTransform so we can extract values
    that are multiple levels deep.

    Our plan of attack is to annotate the value, sum them together, and return them with the period.
    Unfortunately we have to sum them in Python until bug #29139
    is fixed. We're not summing millions of rows so it's still quick enough.

    from functools import reduce

    from django.contrib.postgres.fields.jsonb import KeyTransform

    from accounts.models import StripeEvent

    def accumulate_tax(start_date, end_date):
    """
    Can't aggregate KeyTransformed objects directly, so summing manually
    Reference: https://code.djangoproject.com/ticket/29139
    """
    events = StripeEvent.objects.filter(
    created__range=(start_date, end_date),
    type='invoice.payment_succeeded'
    ).annotate(
    tax=KeyTransform('tax', KeyTransform('object', KeyTransform('data', 'data'))),
    ).values('tax')

    if events:
    tax_total = reduce(lambda x, y: dict((k, (v or 0) + (y[k] or 0),)
    for k, v in x.items()), events)
    else:
    tax_total = {'tax': 0}

    for key, value in tax_total.items():
    tax_total[key] = '${:,.2f}'.format(value / 100)

    return {'start': start_date, 'end': end_date, 'totals': tax_total}

    And just like that we can aggregate values from our JSONFields. If you want to sum other fields
    you can simply add another line like this, but replace "tax" with the field you want to sum.

    To make it a bit more useful, I built a second function that uses this function to give me quarterly sums.

    import datetime

    QUARTERS = (
    ((1, 1), (3, 31)),
    ((4, 1), (6, 30)),
    ((7, 1), (9, 30)),
    ((10, 1), (12, 31)),
    )

    def calculate_quarters():
    today = datetime.date.today()
    last_year = today.year - 1

    for start, end in QUARTERS:
    quarter_start = datetime.date(year=today.year, month=start[0], day=start[1])
    year = today.year
    if quarter_start > today:
    year = last_year

    yield accumulate_tax(datetime.datetime(year=year, month=start[0],
    day=start[1], hour=0, minute=0,
    second=0),
    datetime.datetime(year=year, month=end[0],
    day=end[1], hour=23, minute=59,
    second=59))

    We can simply iterate over this function and generate a simple report that shows us a quarterly breakdown
    of our sales and taxes collected.

  • A short list of things cooler than Clubhouse

    Inspired by Seth's Chasing the cool kids, I've made a short list of things that are cooler than Clubhouse.


    • Not caring what the "cool" kids are doing and doing your own thing.

    • Building and learning about the systems that make the world go around.

    • Not uploading your entire contact list to some random company so you can eavesdrop on the "cool" kids.

    • Fighting for an open web so that you and future generations can access the world without gatekeepers.

    • Owning your content.



    The urgent advice usually ends with β€œblogs are dead"

    If you always have to mention that "blogs are dead", perhaps they aren't actually dead. They never were dead. They're just not "cool" anymore. The people who made blogging cool and fun? They're mostly still blogging.


    Publish. Consistently. With patience. Own your assets. Don’t let a middleman be your landlord. Yell at Google for blocking your emails and hope it’ll work eventually. Continually push for RSS and an open web. With patience.

    Yes.

Previous 5 of 10 Next