# Serge Nevsky: blog posts, full text > Software engineer at Meta practicing agent-native engineering: running fleets of AI agents that ship production software. This file contains every post from https://snevsky.com/blog/ in full. Index: https://snevsky.com/llms.txt --- ## Checking the Weather with Phillips Hue Light Bulbs Date: 2021-06-16 URL: https://snevsky.com/blog/weather-on-phillips-hue-light-bulb Working from home during the pandemic created opportunities for short walks throughout the day. With a baby, this is all the more tempting. Unfortunately the weather in Kansas is neither cooperative nor predictable. This meant frequent lookups of current weather conditions. Sometimes that means opening the Weather app on my iPhone. Sometimes it’s Google Assistant. And other times it’s opening the front door and peeking my head out. But each of these actions carries friction. To eliminate that friction I built a service to set my Phillips Hue light bulb color based on the current weather conditions. Table of Contents 1. Introduction 2. Hue API 3. Open Weather Map API 4. Docker 5. Where to take it further 6. Outcome Introduction An oil painting of Paris sits above our fireplace, lit by overhead spotlights. I replaced these spotlights with two color Phillips Hue light bulbs. The idea was to color the Parisian sky based on the weather conditions. The painting itself stays static, but the color of the bulbs gives an illusion of rain, snow, clear or cloudy skies. For the implementation in Python, I used a combination of: • The Phillips Hue API, via the phue library • The Open Weather Map API, via pyowm The inspiration for this combination of libraries came from friedmud/hue_weather which is the closest thing to what I was looking for. Similarly to the author, I found the IFTTT offerings extremely limited. Luckily these APIs are extremely approachable, and I had a working prototype after just two hours of coding. Hue API The Hue API is extremely easy to use thanks to the phue library. You must authenticate your Hue Bridge to generate a credentials file. That means pushing the physical button on the device once, then immediately executing the bridge.connect() function. Once the credentials file exist, it need not be renewed. See details in their documentation. Adjusting colors has many options, such as changing on/off, brightness, hue and various other properties individually. I found the easiest way to set colors was to do it manually in the iPhone app, then using the API to fetch the xy “coordinates” for that color. I noted those colors down, then set just the xy property on the light bulbs based on the weather condition. Open Weather Map API For my use case, 15 mins between forecast checks (all day, so long as the light bulbs are turned on), is well within the boundaries of Open Weather Map’s free tier. Accessing this API with the pyowm library was slightly confusing. My API key returned strange errors when using many of the library’s functions. It may be that some functions are limited by the pricing tier. Admittedly this was not clear in the documentation. However I found that the weather_manager.one_call() function did work as expected and met my use case. See the documentation for “OneCall data” here. I pass it the longitude and latitude for my location, and it returns a whole heck of a lot of information. I was impressed with the API’s decision to use status codes to indicate weather conditions. I know very little about weather forecasting so I’m not sure if they are standard or not. They are conveniently similar to HTTP status codes. For instance 500 level status codes indicate various levels of rain, while 600 level status codes indicate snow. See the documentation for those codes here. Ultimately my implementation relies on the status codes entirely to display “rain” colors, “snow” colors, etc. I struggled with choosing distinct colors to indicate “cloudy”, “drizzle” or “clear”. Off white can’t mean everything. But I settled on some combinations that I could remember. For “clear” skies I also colored one of the bulbs warmer or cooler (more red or more blue) based on the current temperature. Docker I’ve found that the easiest way for me to deploy services to my home server from my laptop is using Docker containers. It’s definitely possible to set up a daemon, but personally I’m more comfortable with Docker. The Dockerfile installs python3 and pip , then feeds the requirements.txt file to pip (which is the standard Python package manager). This is my preferred pattern for combining small Python services with Docker. My home server runs this container continuously. There is a 15 minute wait between executions of the business logic within the code. It’s also quite fun to test, since I’m programming something in the physical world for once. Where to take it further 1. The code is currently far too specific to my house. It targets two light bulbs, intending to light a painting of Paris above a fireplace. That doesn’t have to be the case. Add a few more configuration options and this could be usable by others. At this point I’m happy if it inspires someone to try these APIs out themselves, using my code as a working example. 2. Additionally I’m still not really that pleased with the color combinations. I struggled to come up with colors that indicated weather in an intuitive way. One possibility is color coding them more explicitly. There’s no reason the sky in Paris would ever turn green, so I did not use it. But if it can indicate something useful and distinct, such as a flash flood warning, then it makes sense. 3. Finally, there are opportunities for similar projects. I have many other (non-weather indicating) Hue bulbs throughout the house. It would be convenient to change to warmer tones as sunset nears, similar to how f.lux works on the computer. Outcome It works! The service has been running for a few days now without issue. Since the weather has been clear for these last few days, I’ve only seen the bulb indicating heat turning increasingly red as the day progresses. Sometimes it stays red way after dark. I should raise the threshold for red, since it makes Paris look like an erupting volcano. I’m satisfied with both of these APIs. It took very little time to set it up. As described earlier, this took about two hours total. The majority of that time was spent choosing colors to indicate the weather. That’s a good thing. Given just how simple it was to spin this up, I’m tempted to jump further into home automation programming. It’s neat to program something that can be demoed to house guests. See the source code on Github here. --- ## Building a Newborn Simulator Date: 2021-06-16 URL: https://snevsky.com/blog/newborn-simulator The mechanics of caring for a newborn child are surprising and fascinating. It’s both challenging and simple at the same time. And it’s not like any other experience in my life. This inspired me to build a Newborn Simulator over paternity leave. I figured it would be a fun challenge to work on a project in the short bursts of free time I had between feedings, diapers and sleep. The idea was to create a simple user interface consisting of buttons that give the “player” feedback about a simulated newborn’s condition. The aim of the “game” is to keep the newborn satisfied, fed and clean. The Technology For rapid interactive front end development create-react-app remains one of the best ways to get started. I feel comfortable using React and this set of scripts served me well before. Sometimes the best technology is the one you know best, particularly for short term projects such as this one. It was my first time using the gh-pages package along with create-react-app but it made deploying the app an absolute breeze. I also used semantic-ui for UI components and styling, which is a killer time saver for a developer. The Game The user interface is split into three columns. The first column displays the baby’s condition and metrics, as well as the player’s stamina. The next column is a list of actions the player can take. And the final column displays game statistics. The baby’s condition or “feeling” is equivalent to health points in classic gaming terms. If feeling drops too low, the game is over. Similarly the player’s stamina is almost like magic points, since taking actions “uses it up”. It recovers when the player takes rest. If you neglect your stamina, you will pass out from exhaustion. The baby’s weight grows as the player progresses through juggling the various actions. The weight can also drop upon neglect. As such, weight is essentially the game score. Finally the baby’s age is the in game clock. It doesn’t run out, but it does allow you to compare the rate of weight gain in different play throughs. This is intended to motivate the player to replay the game again and do better. Ultimately this is a game of balancing your responsibilities towards the child and your own health. Not so different than raising a baby. Try playing the Newborn Simulator here. --- ## Newborn daughter Date: 2020-05-13 URL: https://snevsky.com/blog/maya Our daughter Maya was born just in time for lunch on April 25, 2020 at 11:55 AM. 👶 We are now happily enjoying her adorable facial expressions, her hilarious sounds that remind us of a squeaky door, and arguing over who she looks most like. I know it would be impossible to convey the instant bonding that took place at birth to myself just weeks ago. The effect is astounding. All credits go to human nature. Everyone is happy and healthy. Now we are working through learning this absolutely new mode of life. It can be exhausting, but it’s constant pleasure. And we remain thankful for all the moments. --- ## Authentication in ASP.NET Core Web API with Amazon Cognito Date: 2018-09-18 URL: https://snevsky.com/blog/dotnet-core-authentication-aws-cognito Amazon Cognito is the user management and authentication product in AWS. It allows for unified sign-up and sign-in flows across web and mobile apps. I like it particularly for its pricing: Free for the first 50,000 monthly active users. The next 50,000 will cost you half a penny. Think you can sell your Director on that? This article will show you how to set up Amazon Cognito in AWS, then configure Authentication for a Web API project to use Bearer tokens. If you’d like to skip setting up Amazon Cognito in AWS, you can skip straight to the C# portion for code samples. Table of Contents 1. Create a User Pool 2. Create an App Client 3. Add authentication to Web API 4. Register Users 5. Authenticate Users Create a User Pool Navigate to the Cognito home page from the AWS Management Console. You can search for Cognito in the AWS services search box, or click the link under the Services dropdown under “Security, Identity & Compliance”. From there you’ll see that Cognito is split into two parts: User Pools and Identity Pools. Identity Pools grant access to AWS services, but User Pools are what we want for API authentication. Click on “Manage User Pools” and “Create a user pool”. Click either “Review defaults” or “Step through settings” to create the app pool. If you follow the defaults, you may want to adjust the aggressive default password policy. Create an App Client Each of your applications utilizing a Cognito User Pool is called an “app client”. You will need to register your Web API application with Cognito in this way. Under “General settings” in the side bar, click on “App clients”. Then, “Add an app client”. There are a few options here: Choose a custom name for your app client, keeping in mind any future application that utilizes the same app pool will use a separate app client. Check only “Enable sign-in API for server-based authentication”. Do not check “Generate client secret”, “Only allow Custom Authentication” and “Enable username-password flow”. Click “Create app client”. An “App client id” will be generated for your app client. Take note of this ID as we will use it soon to configure the Web API. Add authentication to Web API ASP.NET Core Web API applications configure Authentication in the Startup class. Navigate to the Startup.cs file in your solution Now find the ConfigureServices function. Above the call to AddMvc include the AddAuthentication and AddJwtBearer extension methods: public void ConfigureServices(IServiceCollection services) { services.AddAuthentication("Bearer") .AddJwtBearer(options => { options.Audience = "Your App Client ID goes here!"; options.Authority = "Your Authority URL goes here!"; }); services.AddMvc(); } We are required to set just two options: Audience represents the recipient of the token. In our case it is the App Client ID. To refresh your memory, it can be found in the AWS User Pools console under General Settings > App clients. This is typically a random string of characters. Authority is the address of the token issuing authentication server. This will point to the user pool. For example, the authority for a user pool in the us-east-1 region will be the following URL: https://cognito-idp.us-east-1.amazonaws.com/<userpoolID> Not sure what your region is? Check the URL in your AWS console. It’ll be the same as the subdomain in the address bar like this: https://us-east-1.console.aws.amazon.com Can’t remember your User Pool ID? In the User Pool console, it’s written across the top of General Settings as “Pool ID”. Note: If you don’t care for the magic string "Bearer", you can use JwtBearerDefaults.AuthenticationScheme from the Microsoft.AspNetCore.Authentication.JwtBearer namespace. There is one other thing for the separate Configure function. You must add the Authentication middleware simply by including the following line: public void Configure(IApplicationBuilder app, IHostingEnvironment env) { ... app.UseAuthentication(); ... } Authentication is now configured for the Web API application! You can secure any API controllers by using the [Authorize] attribute. For example: [Authorize] [Route("api/values")] [ApiController] public class ValuesController : ControllerBase { [HttpGet] public ActionResult<string> Get() { return Ok("Success!"); } } Let’s test this out. Run the application and attempt to hit your Controller. I use Postman for this. From the above example /api/values returned the status 401 Unauthorized which indicates we failed to authenticate. This is actually the behavior we want, since we did not provide a Bearer token! Unfortunately we do not offer a way to retrieve Bearer tokens. Let’s mock out a sign-in flow in the next section so that we can verify our authentication code works. Register Users Create a new API Controller to deal with registering and authenticating users. For demonstration purposes this will be pretty simple. [ApiController] public class AuthenticationController : ControllerBase { [HttpPost] [Route("api/register")] public async Task<ActionResult<string>> Register() { // TODO: Use AWS SDK to register the user return Ok(); } [HttpPost] [Route("api/signin")] public async Task<ActionResult<string>> SignIn() { // TODO: Pull in AWS SDK and generate our Bearer token return Ok("The Bearer token!"); } } We will need to pull in the AWS SDK as Nuget packages. This will allow us to initiate requests to our Cognito User Pool from code. Open Nuget Package Manager for the solution and add both packages AWSSDK.Core and AWSSDK.CognitoIdentityProvider to your project. Note! In order for the to work, the application needs two Environment Variables set: AWS_SECRET_KEY and AWS_ACCESS_KEY_ID. If you haven’t generated these keys already: open up the AWS console home page, click your name in the top right corner, click “My Security Credentials”, expand the “Access keys” section and “Create New Access Key”. Set the Environment Variables for your project once they are generated. Now we can fill out our Register method and start creating users. [ApiController] public class AuthenticationController : ControllerBase { private const string _clientId = "Your App Client ID!"; private readonly RegionEndpoint _region = RegionEndpoint.USWest2; public class User { public string Username { get; set; } public string Password { get; set; } public string Email { get; set; } } [HttpPost] [Route("api/register")] public async Task<ActionResult<string>> Register(User user) { var cognito = new AmazonCognitoIdentityProviderClient(_region); var request = new SignUpRequest { ClientId = _clientId, Password = user.Password, Username = user.Username }; var emailAttribute = new AttributeType { Name = "email", Value = user.Email }; request.UserAttributes.Add(emailAttribute); var response = await cognito.SignUpAsync(request); return Ok(); } ... } Here are the few things going on in the above. The newly defined class User will act as our payload to the controller methods. This contains all the data we need to register the User, and it will be passed in with the POST body. First we initiliaze an instance of the Cognito Identity Provider Client. The constructor requires the region to be passed in, which I hard coded at the top of the controller. Ensure this region matches your User Pool! Next we create a SignUpRequest and fill in the values from the User passed in to the method. Note that the ClientId is assigned here as well, which is hard-coded at the top of the Controller in a private property. Ensure this matches your App Client ID! Additional registration attributes need to be added to the UserAttributes collection on the SignUpRequest object. Here an e-mail address attribute is added. Finally we await the SignUpAsync function to register the user. Return Ok() to indicate success. Run the application and test it out with Postman. Call the route api/register as a POST and pass a User JSON object in the raw body of the request: { "Username": "test_user", "Password": "test_password", "Email": "test_user@snevsky.com" } Send the request and expect to get back a status of 200 OK. If anything fails, such as password requirements, the exception details will be displayed as the response. The first user has now been successfully registered with the Cognito User Pool! However before this user can be used to authenticate, it needs to be confirmed. The easiest way to do this is now is manually through the AWS console: Navigate to “Users and groups” under “General settings”. The newly registered user from above should be present on the list of users. It will be set as “Enabled” but “UNCOFIRMED”. Click the Username and confirm the user by clicking the “Confirm user” button. The user can now be used to authenticate. Authenticate Users Back in the API controller, modify the SignIn controller method with the following: [ApiController] public class AuthenticationController : ControllerBase { ... [HttpPost] [Route("api/signin")] public async Task<ActionResult<string>> SignIn(User user) { var cognito = new AmazonCognitoIdentityProviderClient(_region); var request = new AdminInitiateAuthRequest { UserPoolId = "Your User Pool ID!", ClientId = _clientId, AuthFlow = AuthFlowType.ADMIN_NO_SRP_AUTH }; request.AuthParameters.Add("USERNAME", user.Username); request.AuthParameters.Add("PASSWORD", user.Password); var response = await cognito.AdminInitiateAuthAsync(request); return Ok(response.AuthenticationResult.IdToken); } } There are some new things happening here: We create an authentication request object that we will pass to the Cognito client. This requires the User Pool ID, the Client ID and authentication flow to be set. Then we add the authentication parameters: USERNAME and PASSWORD. For convenience this method accepts the same User object as before, so we use the data from that object to fill in these parameters. Finally we await initiating the authentication flow with Cognito. This returns a rich response object containing the Bearer token upon successful authentication. We can return the AccessToken on success. Run the application to test this out with Postman. Call the route api/signin as a POST and pass the User credentials as a JSON object in the raw body of the request. Upon success the API returns a status of 200 OK and the Bearer token. This value can now be used to authenticate the secured API controller: Recall from the Add authentication to Web API section, ValuesController was decorated with the [Authorize] attribute and returned a 401 Unauthorized upon request. This token should allow the API consumer to resolve this error. To pass the Bearer token to the API call, an Authorization header must be included with the request. The header Key is Authorization and the header Value follows the following format: Bearer <Bearer Token Value goes here!> Now send the request to GET /api/values. The response “Hello” should be returned with a status of 200 OK as expected. This validates an entire successful flow of Authentication in ASP.NET Core Web API with Amazon Cognito! --- ## Honeymoon in Maldives Date: 2017-03-29 URL: https://snevsky.com/blog/maldives This must to be the most beautiful place on the planet. When we arrived at Hadahaa Island in the Maldives for our honeymoon this year we immediately fell in love with it. The tropical vegetation was a sparkling green. It always felt great to be outside even away from the ocean. The light breeze ruffled the leaves just enough for a peaceful feeling. Where the island really shined was the amazing ocean view. The shallow water was a bright cyan tone, distinctly different from the deep blue water. There is no gradual fade from one color to another. The water suddenly creates a dark stripe deep into the horizon. The water was very clear. Mixed with my wife’s Mehendi designs still covering her limbs after the wedding, it created some fantastic psychedelic effects. The sand was spotless and practically white. From a distance it looked imagined. With so few people around and nothing in the distance save for a few passing ships, we felt like we were in a film, stuck on an uninhabited island. The resort was clean, well-kept and furnished nicely. This spa area became our favorite hang-out spot on the island. Some moments felt like we were living in a computer desktop background. With many nooks scattered strategically around the island, we discovered several new places every day. We promised ourselves we would come back to Maldives. We fell for this small paradise. --- ## Interviewing developers Date: 2016-09-24 URL: https://snevsky.com/blog/interviewing-developers I hear it a lot in Kansas City: “We can’t find good engineering talent,” followed by some excuse. “Engineers are spoiled by the high salaries at big companies.” “Programmers have so many options that it’s hard to compete.” “Great developers are drawn to the “coasts” and not the Midwest.” These premises are false. The real reason developers aren’t taking offers from your company is the draining interview process. In a market full of job opportunities, applicants don’t have the time to research your company thoroughly. We rely on the interview process to give us a sense of how working at the company will be like. For this reason so many developers ignore potentially great fits because the company fails to put forth any sort of effort during the interview process. The technical phone screen The biggest mistakes happen during the initial “phone screen.” This phase typically consists of rapid fire questions pulled from the first result found on Google. “Top 100 C# interview questions.” Did you realize that the applicant read that same article last night in preparation? Prefer home-grown questions. Prompt your developers to come up with a small handful of technical questions that apply directly to the work the new developer will be doing. The nature of the questions is often problematic. An applicant’s ability to define an abstract class does not indicate their ability to actually implement it. Favor questions that display critical thinking rather than recall ability. Consider a conversational approach. Ask which technologies interest the applicant and why. This answer will be genuine. You can get a great sense of their comfort level based on how they answer. Give them a reason to care It’s true that the applicant applied to work for your company, but that does not mean they will take your written offer blindly. Give them a reason to join the company. That initial phone screen is your only opportunity to make the applicant excited about continuing the process. Explain the company’s vision, values, the work/life balance and the interesting problems you are solving. If any of these are missing, consider why you think you can hire a developer in the first place. This will naturally bring out the applicant’s curiosity. Be prepared to answer their questions and hold a deep conversation. If you have to prompt them, “now do you have any questions for me?” you’ve failed. Represent your culture The interview demonstrates your company’s culture. If an hour-long interrogation is representative, then prepare to bid farewell to the applicant. Have developers from the team to meet the applicant. Include future coworkers in on the call or allow them to meet in the privacy of a conference room. Allow the developer to solve an interesting problem either during the interview or at home. Don’t burden them. It should be light yet insightful, fun yet challenging. Leave them craving for more. The best developers will stay just for that. It isn’t difficult to hire new team members if you display effort and interest. Drop the culture of cross examination and aim to be inclusive. The right talent will come to find you. --- ## Moments between the minutes Date: 2016-09-16 URL: https://snevsky.com/blog/moments I learned to play guitar in the moments between the minutes. I did not look for a teacher. I did not sit down to deliberately practice. I did not keep my guitar in its case. I kept the guitar by my side. I reached for it when my computer was rebooting, a file was downloading, a video was buffering, or code was building. These moments added up to days, weeks and months. Years later I play with confidence and pride. I didn’t need lessons like my guitar didn’t need its case. It was always ready. Make it stupid easy to get started and you won’t be able to procrastinate. Forget the guitar case. Eliminate barriers to entry and keep tools ready at your side. Become a pro without even trying. It just takes a few moments between the minutes. --- ## Kindle 2 Date: 2016-09-15 URL: https://snevsky.com/blog/kindle The Kindle 2 is the perfect product. I bought mine almost ten years ago. Today, that same exact unit goes with me everywhere I go. It isn’t annoying, it’s simple and it’s perfect. In the time I’ve owned my Kindle, I’ve upgraded my smart phone, my laptop, my car, my career, even my house. But the Kindle remains the same. Books pop up as expected every single time. The pages never require a software update to continue turning. The battery lasts for days without charging thanks to the lack of a high resolution screen and backlight. The software doesn’t change, so more powerful hardware isn’t necessary. The device is dead simple and just works. When my iPhone’s text messaging app began lagging after updating to iOS 10, I began to realize. Devices like the Kindle 2 don’t exist anymore. A decade from now eBook readers will be more powerful than my current work laptop. But the Kindle 2 will still work. It serves one function and it does it perfectly. --- ## The perfect notebook system for getting things done Date: 2016-03-09 URL: https://snevsky.com/blog/pocket-notebook I accidentally invented the single best system to keep a pocket notebook. It turns out it’s really not so difficult at all. In fact, it turns out that a system isn’t even necessary. Recently many journal systems began popping up online. I know several people who picked one and tried it out. Eventually they grew tired and moved on. It didn’t take very long either. Why didn’t it stick? These systems look beautiful. They aren’t difficult to understand. They’re easy to implement. They’re very, very tempting. But they don’t stick. I’ve used a pocket notebook to keep track of tasks for a long time. I didn’t start by researching existing systems either. I simply started. The single best system to keep a notebook is to eliminate the system. Define a loose set of rules, then let your mind wander. My notebook looks like this. It’s small and it fits in my pocket. I can carry it around and never feel burdened. I tend to keep each day to two pages. I lay out my tasks on the left and do whatever else on the right. I check off tasks when they’re complete. Sometimes I even prioritize tasks, as above. Other times it’s barely legible. But it’ll make sense in that day. Packing lists are perfectly suited. I still haven’t found an app for my iPhone to track workouts with as much freedom as a notebook does. Empty space is opportune for drawings… …and half-baked concept album ideas. Do yourself a favor and pick up a pocket notebook. You can write and track anything you want without any cumbersome interface or system around it. The perfect system is right there in your pocket, and it doesn’t need its battery charged. --- ## Blogging is backwards Date: 2016-02-19 URL: https://snevsky.com/blog/blogging Though I’m constantly tempted, I just can’t seem to keep up a blog. I just find the format to be weird. Blogs are series of loosely related thoughts told to an ever-increasing audience on an irregular basis, backwards. It doesn’t make much sense to me. It never has. It seems like the ideal blog visitor is one that familiarizes themselves with the entire blog from the start to finish. That is how we consume most information, isn’t it? I haven’t started a book from its last chapter since I was a toddler naively picking up a book upside down. So why are blog articles displayed by decreasing date of publication? It makes sense for news, since the most recent content is typically the most relevant. For the majority of blogs, I’m not sure that it does. Some blogs I frequent have terrific content from years back being pushed further out of sight by recent posts of questionable quality. Still, we accept that displaying our posts backwards is just the way it is. I’m writing down some thoughts right now. Are they bound to be forgotten years later once this blog fills with hundreds of entries? Maybe it’ll sit at the top for a few months as I procrastinate writing a new article. Time will tell. So let me take you back. My first website was a fan page to my favorite Pokemon, Jigglypuff. I was around eight years old then. This was around 1998, before Y2K caused the planet to explode. I updated Jigglypuff’s Puff Palace fairly regularly with new artwork, animated gifs and webrings on one long scrolling page. Blogs weren’t a hit yet. Back then it was enough to add a small gif of the text “NEW” to highlight fresh content. But even that was just optional. I was satisfied with updating my gigantic index.html page, padded by copy and pasted javascript snippets, bringing it closer and closer to Platonic perfection. There was no instinct to place new content at the top of the page, in fact it was opposite. But then blogs took off. Suddenly non-technical and technical users alike were putting content online with ease. Maybe LiveJournal is to blame for convincing those poor souls that content should be time driven, plotted on a calendar and date stamped under the header. Everyone started doing it. Wordpress made it better and easier. Older websites weren’t like that. I’d show you my old webring to prove it! – If I could. And now I’m blogging about how I don’t like blogging. There’s a word for someone like that and it begins with a hippo. But the truth is I believe blogging really is an effective medium. Audiences are magically engaged when they notice the date stamp matching today. Somehow the age of content is evidence of its validity. You can see that in the comments for linked articles, calling five month old content “old”. That’s about as heartbreaking as dog years. The solution? Write blog content frequently. The audience will show up and they’ll love it, for that week. Regardless of how weird the blog format might be, it works. Pretty brilliant guys like Seth Godin swear by it. I’ll ride the wave too, until the next big paradigm shift. May the backwards narrative be it, for now. --- ## It’s the little things in my Google Inbox Date: 2014-10-24 URL: https://snevsky.com/blog/google-inbox Google Inbox isn’t some great innovation in the industry. It’s just one step toward making e-mail fun again. We aren’t forwarding e-mail hoaxes anymore, we’re retweeting them on Twitter. Your grandmother doesn’t write you from her AOL address, she’s busy trying to figure out how to add a profile picture to the Facebook account you set up for her two years ago. Even the spam filters are growing too effective for you to need to prune the latest Viagra alert from your inbox. Where did the fun go? Google Inbox is new. It feels pleasant. It’s easy to use. And it has some powerful features disguised as adorable swiping actions. Snoozing isn’t particularly new to e-mail clients. Neither is treating your inbox like a TODO list. Even prioritizing important e-mails was tried by Google years ago. Still this presentation makes it feel different. It makes it feel nice.I get joy out of seeing the inbox clear out and display a cartoon sun and clouds. I don’t process 700 e-mails a day, I’m just happy to see my mother’s e-mail sooner than the latest J.Crew lookbook. Go ahead, give me the satisfaction of swiping away all my promotional e-mails in one stroke. I like it better than filing them to yet another manila folder icon. It’s true, I like simplicity in my technology. But that doesn’t mean it shouldn’t have heart. There are clear skies in my inbox today.