Can a 4-day work week work?

5 days of work in 4 days: can it work for both a developer and their company?

Background

I have been working as a professional software developer for over 13 years. In that time a lot has changed about the way I work: sometimes in an office, sometimes remote; sometimes in the centre of London and sometimes in the sticks. One thing has always been constant though: 9-5 (ish), 5 days a week.

Ok, sure, that’s what it said on the contract and in practice there’s plenty of flexibility in those working hours but it’s always been 5 days, and in my current role that’s worked out as 4 days in London and 1 day remote each week.

I live a fair distance outside London so when I come into town for my (nominally) 8h working day I’m spending a solid FOUR hours commuting on bikes, trains and tubes. Most of my non-weekend free time is a desperate attempt to get enough sleep.

This is not fun.

Proposal

Working remotely definitely solves some of these problems. I’m a great believer in remote working and when done right it can be incredibly effective, but I wanted to know if I could go one better.

Instead of shaving a couple of hours from the end of a couple of days, could I claw back an entire day?

I had already agreed to working remotely on Wednesdays (it breaks the week up nicely) but I was still coming into London 4 times every week. If I’m already spending 4h travelling, wouldn’t it make more sense to spend more time working and reduce my (hours worked)/(total hours) ratio?

Here’s my proposal:

Day Place Hours
Monday Office 10h
Tuesday Office 10h
Wednesday Remote 10h
Thursday Office 10h
Friday “On Call”

Through the week I would would work long days on Mon-Thu and then have Friday effectively free. I didn’t want to cause blocks for my team so I planned to be available on email, chat etc. but not actively working.

Overall this should mean that I’m working more-or-less the same hours every week. We’re in an industry where “hours worked” really shouldn’t be the metric by which we judge people but I’ve tried to make it tally up anyway.

Why this is a great idea for me

On the face of it this seems like a pretty big win! Who wouldn’t love extra time off??

The most important thing for me is seeing my kids for more than the half hour before bedtime that I currently get. It’s rarely their best time (they’re young) and weekends are always busy so it will be nice to have some one-on-one time with them. Maybe get a bit of that “work life balance” I’ve heard so much about.

Beyond that I’m looking forward to a bit more sleep and a little less time on trains!

Why this is a great idea for the company

If this works out then there should be a bunch of upsides for my company as well as my family.

Besides the correlation between “happy employee” and “hard-working employee” I’m hoping to come back from the longer weekend full of ideas and energy. You know how you go away on holiday and have enough headspace to come up with the really great ideas? That. But every week.

Another bonus is that I will have great availability on Mon-Thu. We have a lot of people working offset hours so some people do 8:00-16:30 and some 10:00-18:30, with both ends of that spectrum in my team. With my new working pattern I’ll be able to work with both the early risers and the night owls equally.

Finally, I am hoping that my regular semi-absence will encourage my team to act more autonomously. It’s harder to delegate decisions to someone senior if they’re not around!

Why this might be a disaster

Ok, I’ll admit there are a few things that could go wrong with this plan. I might be exhausted every day and not get any work done. I might be so exhausted by the end of the week that I spend my Fridays as a zombie. I might even be tempted to work on Friday as well if we’re under pressure.

Beyond various flavours of exhaustion, it may turn out that my absence on a Friday is a real problem for the team. It could be a blocker, even when I’m on email. It might turn out that it’s harder to book meetings or client visits.

The only way to find out if these problems are real or imagined is to try it out!

The plan

I had a chat with my boss and they’re happy for me to give this a try. I was a little surprised – I thought this was a fairly unusual request – but it’s nice to see a company that doesn’t just pay lip service to employee work/life balance.

We agreed that I would trial the new working pattern for a few weeks and observe the improvements (or otherwise). There isn’t really a good metric for “developer output” so the results are going to be largely subjective but I’ll be focussing on:

  • personal energy levels (work & home)
  • feedback from my team
  • feedback from other teams and departments
  • a fuzzy “quality of life” feeling

It’s not particularly scientific but I suspect it will become obvious quite quickly if it’s not working.

If nothing else, it’s going to be interesting finding out!

Advertisements

Conditional Rendering in React

Conditionally rendering content is a pretty common pattern in React components.

class MyComponent extends Component {
  render() {
    const { user } = this.props;
    return (
      <div>
        {user && <h1>{user.name}</h1>}
        {/* other content */}
      </div>
    );
  }
}

This can quickly get messy when you introduce multiple parmeters or large conditional content blocks

render() {
  const { user, profile, otherData } = this.props;
  const shouldDisplayProfile = user && profile && otherData;
  return (
    <div>
      {shouldDisplayProfile &&
        <div>





        </div>
      }
      {/* other content */}
    </div>
  );
}

And don’t even mention ternary operators. Nothing better than scrolling through a component and finding : null} with no context 👀

Wrapping Dependent Content

In React, our unit of reuse is usually a component so can we move this behaviour into a component?

const example = (
  <OnlyIf all={{ user, profile, otherData }}>
    only render this content if all of user, profile & otherData are defined
  </OnlyIf>
);

It turns out that this is actually a pretty simple component:

  1. determine if the all prop values are truthy
  2. only render the children if they are
interface OnlyIfProps<T> {
  all: T;
}

class OnlyIf<T> extends PureComponent<OnlyIfProps<T>> {
  render() {
    const { all, children } = this.props;

    let allValuesSpecified = true;
    Object.keys(all).forEach(
      key => (allValuesSpecified = allValuesSpecified && !!all[key])
    );

    return allValuesSpecified ? children : null;
  }
}

Lazy Rendering Content

The “ component above may be useful but there is an important scenario that is not covered: children attempting to use undefined values.

const example = (
  <OnlyIf all={{ user }}>
    <h1>{user.name}</h1> {/* <-- this will throw if user is undefined */}
  </OnlyIf>
);

In this case we shouldn’t even attempt to render the children if user is undefined. We cannot prevent it when we use the structure above but if we switch to a render props pattern then we can control when children are rendererd:

const example = (
  <OnlyIf all={{ user }}>{values => <h1>{values.user.name}</h1>}</OnlyIf>
);

We can update our component to support both scenarios by…

  1. accepting either ReactNode (the default) or (values: T) =&gt; ReactNode as our children
  2. identifying the function in render and invoking it
interface OnlyIfProps<T> {
  all: T;
  children: ReactNode | ((values: T) => ReactNode);
}

class OnlyIf<T> extends PureComponent<OnlyIfProps<T>> {
  render() {
    const { all, children } = this.props;

    let allValuesSpecified = true;
    Object.keys(all).forEach(
      key => (allValuesSpecified = allValuesSpecified && !!all[key])
    );

    if (!allValuesSpecified) return null;

    return typeof children === 'function' ? children(all) : children;
  }
}

Now we can accept either a render function or a component as the situation demands!

Is this a good idea?

So we absolutely can create “ but is it useful?

On the negative side, it is an unfamiliar component that may have unexpected effects for new developers.

On the other hand, it’s fairly self explanatory and is an improvement in general readability in my opinion.

Overall I think it’s a nice addition. It certainly beats the hell out of a 20 line ternary expression!

Higher-Order Components with React & TypeScript

Higher-order components are a great way of reusing common functionality in your react app.

TypeScript is a great way of making sure your react app can grow without you losing your mind.

So how can we use the two together?

Higher-Order Components

A higher-order component (HoC) is a function that accepts a component as an argument and returns a new component that has been enhanced in some way.

const EnhancedComponent = myHigherOrderComponent(WrappedComponent);

The enhanced component can add behaviour, manage state or in any other way modify WrappedComponent.

Injecting Props

A common pattern is for a higher-order component to provide some props to the wrapped component, moving the management of those props out of WrappedComponent and allowing it to focus on other concerns.

For example, connect(...)(WrappedComponent) in react-redux provides props to both expose redux state and to dispatch actions. withRouter(WrappedComponent) in react-router similarly injects routing-related props into WrappedComponent from the current route.

Getting the prop types right when injecting props can be a bit fiddly. We want:

  1. WrappedComponent to have new props injected automatically
  2. Injected props not to be required on the created EnhancedComponent
  3. Any other props on WrappedComponent to be forwarded from EnhancedComponent
  4. TypeScript to infer all of the above with no manual specification for the user

For example, let’s say we have a HoC that will manage the isExpanded state of an expander component. It will provide the following props to WrappedComponent

interface ExpanderProps {
  isExpanded: boolean;
  toggleExpanded(): void;
}

Our wrapped component will need to accept these props but it might define some others as well. Let’s say it has a title that needs to be specified and an optional className:

interface WrappedComponentProps {
  isExpanded: boolean;
  toggleExpanded(): void;
  title: string;
  className?: string;
}

note that you could (and should!) define this as WrappedComponentProps extends ExpanderProps... and avoid duplicating the prop definitions. I’ve left this as it is here for clarity

In this case we want both title and className to be available on EnhancedComponent:

const EnhancedComponent = withExpander(WrappedComponent);

const usage = (
  <EnhancedComponent
    title="The title"
    className="class-name">
    ...
  </EnhancedComponent>
);

The Wrapped Component

At this stage we have already defined the provided props as an interface and we have an example of what the wrapped component might look like. Let’s flesh that out a bit (and give it a more appropriate name):

interface ExpanderComponentProps extends ExpanderProps {
  title: string;
}

class ExpanderComponent extends PureComponent<ExpanderComponentProps> {
  render() {
    const { isExpanded, toggleExpanded, title, children } = this.props;

    return (
      <>
        <button onClick={toggleExpanded}>{title}</button>
        {isExpanded && children}
      </>
    );
  }
}

Fairly simple: render a button containing title that toggles the expanded state. If isExpanded=true then also render the children.

Create the Enhancer

Now we want to create the enhancer function that we can use to inject isExpanded and toggleExpanded. Our first requirement is that it accepts an argument of WrappedComponent where WrappedComponent accepts the props we want to inject. That function signature might look something like this:

function withExpander(WrappedComponent: ComponentType<ExpanderProps>) {
  //...
}

ComponentType is a react type that allows you to pass in either a component class or a stateless functional component that has props of T

The next requirement is that it returns a component that doesn’t require the ExpanderProps to be specified, which means that we need to provide them from the enhanced component. In this case we’re going to get those values from the state on the component but that’s not a requirement – they can come from anywhere.

Once we have the values we need we can pass them to WrappedComponent in the render method:

function withExpander(WrappedComponent: ComponentType<ExpanderProps>) {
  return class WithExpander extends PureComponent<{}, { isExpanded: boolean }> {
    render() {
      return <WrappedComponent
        {...this.state}
        toggleExpanded={this.toggleExpanded}
        />
    }

    private toggleExpanded = () => this.setState(state => ({ isExpanded: !state.isExpanded }));
  }
}

All right, nice and easy! Except… build failure!

const EnhancedComponent = withExpander(ExpanderComponent);
// Error!

Our ExpanderComponent requires a title prop; when we use it (as WrappedComponent) in withExpander we don’t specify the title!

We could make withExpander aware of the title prop but that’s not very useful for the future: there will likely be other props that need to be passed through and we don’t want to keep adding them to our HoC.

This brings us on to Requirement 3 above: any other props from the wrapped component should be forwarded from the enhanced component. In this case, we really want to have the title prop be exposed on EnhancedComponent.

The first step in getting to that point is to allow the WrappedComponent parameter of our HoC to accept props that aren’t on ExpanderProps. In fact, we need our wrapped component to accept props of both ExpanderProps and whatever else it wants.

We can introduce a generic type parameter to the HoC function to represent that combined props object:

function withExpander<TWrappedComponentProps extends ExpanderProps>(
  WrappedComponent: ComponentType<TWrappedComponentProps> ) {
  //...
}

That solves our build failure: withExpander will now accept any component as long as it has the two isExpanded and toggleExpanded props.

Sadly we’re not quite done yet though; try to use the enhanced component and you will see our next problem:

const EnhancedComponent = withExpander(ExpanderComponent);

const usage = <EnhancedComponent title="Some title" />;
// Error!

Another build failure, this time telling us that title does not exist on the enhanced component. We’ve managed to write our HoC so that it allows extra props but all it does is ignore them!

What we really want here is to create a new Props type that we can assign to our created component. TypeScript 2.8 includes 2 built-in types that are going to help us out:

  • Pick<T, U> that takes the props from T specified in U. e.g. Pick<ExpanderProps, ‘isExpanded’> creates a type with only the isExpanded property
  • Exclude<T, U> that takes everything from T except U. e.g. Exclude<‘one’ | ‘two’ | ‘three’, ‘two’>* creates a type 'one' | 'three'

By combining these with keyof we can build up the “all props that are on the inner component but excluding the ones we’re providing” type. We might want a better name though…

function withExpander<TWrappedComponentProps extends ExpanderProps>(WrappedComponent: ComponentType<TWrappedComponentProps>) {
  type WrappedComponentPropsExceptProvided = Exclude<keyof TWrappedComponentProps, keyof ExpanderProps>;
  // => 'title' | 'className'
  type ForwardedProps = Pick<TWrappedComponentProps, WrappedComponentPropsExceptProvided>;
  // => { title: string; className?: string }

  //...
}

Now that we know what our forwarded props should look like we can specify those on the component.

return class WithExpander extends PureComponent<
  ForwardedProps,
  { isExpanded: boolean }
> {
  render() {
    return (
      <WrappedComponent
        {...this.props}
        {...this.state}
        toggleExpanded={this.toggleExpanded}
      />
    );
  }

  //...
};

the additional spread of this.props onto WrappedComponent copies the externally-specified props onto the wrapped component

Now we can use our enhanced component as intended.

const EnhancedComponent = withExpander(ExpanderComponent);

const usage = (
  <EnhancedComponent title="title">
    <div>...</div>
  </EnhancedComponent>
);

As a bonus, TypeScript gives us Requirement 4 for free! Type inference means that we don’t have to specify any types explicitly in our usage of this HoC but we still have full type safety. Try removing title or adding an unknown property and your IDE will light up with compilation errors – thanks TypeScript! ✨

Post-Logout Redirect with ASP.NET Core and ADFS 2016

Redirect after logout

When a user logs out from your app you have the option to log them out of the provider as well by redirecting the browser to the logout endpoint. By default this means that the user will end up sat on your providers “You have signed out” page – not brilliant.

You can, however, tell your provider to redirect back to your app once they’re done with logout by specifying a post_logout_redirect_uri.

For ASP.NET Core Identity you can specify this redirection as a parameter on the SignOutResult.

[Route("auth")]
public class AuthController
{
  [HttpPost("logout")]
  public IActionResult Logout() => new SignOutResult(
    OpenIdConnectDefaults.AuthenticationScheme,
    new AuthenticationProperties { RedirectUri = Url.Action(nameof(LogoutSuccess))});

  [HttpGet("logoutSuccess")]
  public IActionResult LogoutSuccess() => View();
}

Useless ADFS error messages

For ADFS 2016 you need to do a little bit more than just set the redirect URL. On first inspection you can see that the above will set the parameter in the ADFS URL but ADFS will silently ignore it and your user will sit forever on the ADFS sign-out page.

Digging into the event logs you will find the following error message:

The specified redirect URL did not match any of the OAuth client’s redirect URIs. The logout was successful but the client will not be redirected

If you’re unlucky, this wonderfully-misleading error message can take you down a rabbit hole of further configuration. It’s a shame, then, that no-one thought to expose something a little more accurate:

That redirect looks good but you need to specify id_token_hint or we’ll ignore you

Thanks ADFS!

Sending ID Token Hint

To be fair to ADFS, sending an id_token_hint is recommended by the spec. This parameter needs to be set to the id_token that was sent to your app when the user first logged in; provide this value and ADFS will happily redirect back to your app.

The only problem here is that you probably don’t still have that id_token. ASP.NET Core Identity uses the identity information to create an auth cookie and then (by default) discards it.

Happily, the OpenIdConnectOptions exposes a SaveTokens property to persist the received token to the auth cookie. Even better: the OIDC logout mechanism will automatically pick this up once enabled so you should be good to go as soon as you set the flag:

public class Startup {
  public void ConfigureServices(IServiceCollection services)
  {
    services.AddAuthentication()
      .AddOpenIdConnect(options => {
        options.SaveTokens = true;
        //...set other options
      });

    //...other service config
  }
}

This does have one important downside though: you’re now storing much more information in your auth cookie and that adds extra data to every client request, maybe even doubling the cookie size.

Whether or not this is a problem for your app is another decision – at least your logout redirect works now!

Find .NET Core packages in all projects

In a quick aide-memoire for next time I need to use it: here’s a Powershell snippet that will return a list of all unique package names in all .NET Core projects under the current folder:

get-childitem -recurse -filter *.csproj |
  foreach { get-content $_.FullName } |
  select-string -pattern "PackageReference Include=""(.+?)""" |
  % { $_.matches[0].Groups[1].Value } |
  sort-object -unique

Line by line…

  • Get all *.csproj in the current and child folders
  • Read the content of each one
  • Extract every line that matches the specific regex and extract the name of the package
  • Grab the package name group
  • Sort & filter to unique values

This outputs something like

CommandLineParser
CsvHelper
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.Logging
Microsoft.Extensions.Logging.Console

Generic behaviour in ASP.NET Core with Action Filters

Everyone hates copy/pasting code, and Action Filters in ASP.NET Core MVC offer a great way to avoid filling your controllers with boilerplate.

Filters offer you entry points into the execution pipeline for an action where you can examine the incoming parameters or generated results and modify them to suit your needs.

Here are a couple of examples of how this can help.

Treat a null result as a 404 Not Found

By default an ASP.NET Core controller will return a 204 No Content response if you return null from an action:

[Route("api/example")]
public class ExampleApiController : Controller
{
  [HttpGet("")]
  public string GetExample()
  {
    return null;
  }
}

In some cases, however, you might not want to treat null as No Content. If your API is looking up a resource by ID, for example, then a 404 Not Found response would be more useful:

[HttpGet("{id}")]
public MyDtoObject GetById(int id)
{
  if (!_store.ContainsId(id))
    return null; //should return 404

  //...
}

We can use an action filter to automatically replace the null result with a NotFoundResult:

//filter
public class NullAsNotFoundAttribute : ActionFilterAttribute
{
  public override void OnActionExecuted(ActionExecutedContext context)
  {
    var objectResult = context.Result as ObjectResult;

    if (objectResult?.Value == null)
      context.Result = new NotFoundResult();
  }
}

//controller
[HttpGet("{id}")]
[NullAsNotFound]
public MyDtoObject GetById(int id)
{
  //...
}

Here we override OnActionExecuted to invoke our code after the action method has generated a result but before that result is processed.

If the generated result is an ObjectResult with a null value then we replace it with an empty NotFoundResult and our controller will now return a 404 response.

Treat invalid models as a 400 Bad Request

It is very common to see the following pattern in MVC controllers:

[HttpPost("")]
public IActionResult Create(MyModel model)
{
  if (!ModelState.IsValid)
    return new BadRequestObjectResult(ModelState); //or a View, or other validation behaviour

  //...eventually return created model
  return Ok(model);
}

This has 2 downsides:
* Boilerplate code in every action that needs to validate
* Return type must be IActionResult to accomodate 2 result types

The second point is fairly minor but worth noting. By exposing IActionResult instead of the concrete type we lose metadata about the action.
That metadata is useful for things like generating swagger docs, and losing it can mean you need to decorate the method with response types (though this is improved in ASP.NET Core 2.1 with IActionResult).

In any case, we can make this behaviour generic by moving the validation check into another action filter:

public class InvalidModelAsBadRequestAttribute : ActionFilterAttribute
{
  public override void OnActionExecuting(ActionExecutingContext context)
  {
    if (!context.ModelState.IsValid)
      context.Result = new BadRequestObjectResult(context.ModelState);
  }
}

This time we are overriding OnActionExecuting instead of OnActionExecuted so our code gets run before the controller action. We can tell if the model is invalid before hitting our controller so we can skip the action entirely if we know it should be replaced with a 400.

Other Possibilities

Wherever you find yourself writing duplicate code in many actions it is worth considering whether it can be pulled out into a filter (or middleware) to keep your controllers clean and focussed on their intent.

Stop Agonising Over Tiny Details

I recently started a new side project using React and – having not used React in anger before – wanted to get off on the right foot.

And by “on the right foot” I apparently decided that I meant “with the perfect folder structure for my code”.

Obviously we can all agree that folder structure is the most important predictor of code quality  (<sarcasm/>) so I spent hours agonising over whether to separate  components from screens or whether to group all actions together in an actions folder and a hundred other basically-irrelevant details. I read blog posts. I tried template project generators. I poured over a huge number of “sample” GitHub repos (every one different, of course).

To reiterate: this was for a new, greenfield side project. I spent hours of my limited time worrying about where to put all the code instead of…writing any of that code!

facepalm

Hence this post. This post sits here as a reminder to myself to STOP AGONISING OVER UNIMPORTANT THINGS.

And you know what? I changed the entire structure after a week anyway.