So, I have been freelancing on and off for the past 5 years. I have seen a lot of projects and worked with both technical as well as non-technical people. Over time, I managed to set up a system that seems to work well for me, though I will definitely edit this page whenever I find a better way on how to handle things. Underneath, you will see how I handle new freelance contracts that I take on.

The initial contact

It doesn’t really matter to me if someone reaches out to me or if I reach out to some job post somewhere. Though, I general prefer to have people reach me. That way I know that:

  • they are somewhat familiar with what I do and how I code (as a lot of my code is open-source);
  • I am not bidding against other people who are sometimes really desperate to get work (and therefore work for prices that are way below industry standard);
  • they probably have some sort of technical knowledge (I don’t decline anyone that doesn’t, but I generally prefer people who do know how to code and review what I do, I will elaborate on this below)

This initial contact generally happens over email. In most cases, people introduce themselves and what they are working on/what they need help with. This is great. I then instantly know if it’s indeed something that I want to work on and if it peaks my interests.

I always reply to an email requesting my help - even if I think that I won’t to be a good fit for them. I don’t like it when people leave me hanging, so I don’t do this to others either. If it does interest me, I forward my calendly link to schedule a meeting. This will take 30 minutes to an hour. I will always turn my camera on during this first meeting. Oftentimes, I am fiddling around with cables and pens and what not during meetings, so I actually prefer to not use my camera, but for the first initial contact, I want to keep it personal.

During the meeting, I will always try to get as much info as possible about who the (potential) client is and what they want from me. If they have some kind of demo running somewhere, I am always eager to see it.

Projects from scratch and existing projects

Speaking of projects, I can work on both existing and completely new projects.

Existing projects

Having said that, I do have strict requirements for existing projects:

  • I want to see the code before I will say yes to the contract (I am okay with signing reasonable NDA contracts beforehand);
  • All credentials to production servers need to be cleared from both the source code and the git logs (or got rotated). I prefer it if people operate on the principle of least privilege.

If I don’t have access to something, I also can’t mess it up. This isn’t to say that I would mess something up, but having access to something that I shouldn’t have access to gives me chills. I can’t be blamed for something that I have never had access to in the first place.

New projects

These are massively prefered. I like to code a project up from scratch, that way I can implement principles like least privilege, 12-factor, CD/CI etc right away.

In most cases, these are the basic things that I need:

  • Globally overview of the purpose of the app;
  • Designs (even if we go with a standard CSS framework (like Bootstrap, Bulma or Material UI), but in this case it doesn’t have to be pixel perfect);
  • Use cases and wireframes.

I generally also want to know a lot of miscellaneous things, like the scale of the app (internal use for a few people or used by thousands), potential feature upgrades (i.e. maybe implement websockets or can we get away with pinging, if no further plans?) etc. Some of these might be clear right away, others will come up during discussions.

Technical and non-technical people

I have worked with both people. Some caveats for non-technical people that are often not super obvious:

  • Software development is expensive. Sometimes it might look like only something really small changed (or, maybe nothing actually changed at all from the user’s point of view), yet I still put in a lot of hours. This can have many reasons, and I will always clarify this on invoices/time reports and/or discuss beforehand. Here are some reasons to give you an idea:

    • Sometimes code needs to be refactored to keep it maintainable. I value clean and organized code a lot, but that doesn’t mean that I refactor something that only adds very limited upside.
    • Updating packages to the latest version can take a lot of time. Even if all tests pass, there might still be things that are slightly off. As an example: recently, I updated an icons library and all icons were off by a few pixels - that’s hard to catch with testing.
    • Patching rare exceptions. Sometimes it’s hard to replicate a bug that only happens every so often. In most cases, those bugs should still be investigated/fixed.
    • Running an app is kinda like running a car. Every now and then it needs some extra attention to keep everything running smoothly. This is also the reason why I will always charge a maintenance fee if you want to keep me on the project.
  • There are risks to storing user data. Most apps do collect some kind of data. It might just be the IP address that is used to access the site, but it could also be a lot of sensitive info. This data needs to be stored somewhere and be protected. There are many layers to this, but you will always run the risk of getting that exposed or getting held hostage by some ransomware. It’s up to you on how to handle this. Obviously, I will always try to keep everything secure. I always lock everything down (with authentication/rate limiting) and then add exceptions manually where necessary.

Working with technical people is generally a little easier as those are already aware of the things above. Actually, most clients just give me access to their Github repo. Assign me to an issue and then expect a pull request. That’s how I like to work in general. It allows us to skip a bunch of steps and gets me right into the project. Bonus points if there isn’t a 10 step set up plan, but just a docker-compose up and done!

Contracts

If a client has a contract that they want me to sign, then I am happy to do that (as long as the contract is reasonable. Yes, I read them!). Though, I do have a default template that I use for new contract work. This contract includes IP ownership, an NDA, payment terms and more. It’s about two pages and based on the default developer template from Hellobonsai (signing happens through their platform as well).

I think it’s important though to keep in mind that we are all human. If someone forgets a payment, but then quickly corrects their mistake, then I am not going to enforce a late payment fee, even though I could enforce it due to our contract.

Communication

I love email. It’s async, so it doesn’t block me from anything that I am currently doing. The thing about email is that we are all aware that it might take a few hours before someone responds, unlike chat applications, like Skype or Slack. Generally, I do respond quickly to emails though. In most cases, I do respond within 2-3 hours to an email (within business hours), unless you need something that takes longer (signing a contract for example). I rarely respond during the weekend, I need time to wind off too.

Some clients do require me to be on Slack or Skype. I can do that and will if you want, but oftentimes, I find Slack/Skype to be a pretty big time consumer and suboptimal. Chat applications allow you to be sloppier at organizing questions and you sometimes expect a quick reply from someone, which will leave you waiting for a few minutes (switching back and forth between work and chat isn’t efficient from what I have found).

Here is a quick example of what I mean by “suboptimal” (this example shouldn’t have happened over chat/email in the first place - there are tools for code review, but let’s forget about that for a second).

Chat application (M: me, C: client)

C: I have a few comments on your latest pull request. Can you take a look at that?
M: You mean, this one right? [link]
C: yeah
M: Okay, what's up with that?
C: Can you change the background color a bit lighter?
M: Sure.
C: Oh, while we are on it, can you also make the border width a bit bigger?
M: Will do.

With an email, this could have been reduced to this:

Hey Stan, 

Regarding this pull request: [link]
Can you change the following, please?
- Make the background a bit lighter
- Make the border width a bit bigger

Thanks,

You might say that the email could have also been a Slack message. That’s completely true. BUT, a chat application makes it much easier to quickly write a few lines without thinking it through. The bar to send a message is much lower compared to sending an email.

In some cases, it’s also much easier to simply get on a call and figure things out on the spot. Typing takes much longer than talking. Chat applications might be all hot and fancy, but personally, I think that in many cases they are a huge waste of time, from a freelancer point of view.

Code deliver / milestones

If I am writing a full app, I will set up milestones. With every milestone, I like to get feedback. How I receive feedback depends a bit on the type of project and the person (technical vs non-technical). A call can work fine here, so can code reviews (without live chatting).

When I push code to a repo, I will always put a lot of effort into the text of the pull request. Some info might be redundant, but I think it’s important to always be able to quickly look back at a merge and see what got done (without having to look through the code). My typical message would be something like this:

Fixes #123

This PR adds the ability for users to download pdf files of their reports.

## What has been changed:

* Added button to download PDF file of xxx records
* Added backend code to create PDF file
* Set up AWS S3 integration to save PDF files long term

## Things that need to be done after this gets merged:

* AWS environment variables need to be added to server environment variables. See the changes in the config file for what's necessary.

If AWS environment variables are not added, it will raise an error on startup. Please make sure to add the variables before releasing the new build.

You should then review the PR. With the first PR, there are generally a few comments that need to be addressed. Please also mention very small details that need to be fixed. I learn quickly and keep your preferences in mind with new PRs that come after that, so we can move quicker on new PRs.

After care

If the client is technical, there generally isn’t much aftercare needed. When I have completed the tasks, then that’s it. If there are probably no new tasks in the near future, then I will leave the repo as soon as everything is done. If there might be a follow up project, then I am fine with staying on the project. Though, if we haven’t worked together in a year, I will still leave the repo (but you are free to add me back whenever you want me to do something).

For clients that are not technical, I will generally have the client create the repo (as the client also owns the code according to the contract and needs to have access to it). I will stay on the repo for as long as our contractor agreement is active. In most cases, our contractor agreement will include what kind of support you get afterwards. If you pay a fixed price for a feature/app, there is generally a clause that covers free bug fixes for up to a few weeks after deployment, just to cover most common issues. When I get a notification of a bug or something else happens on the server, I will either go ahead and fix it or contact you with a quote on how much it would cost to fix it. I don’t just go ahead and fix it and then bill you afterwards, unless we have agreed on that.

I also rarely ask for feedback afterwards. I am Dutch, so I am used to direct communication. If you don’t like something, I want you to come forward with that during our time working together. Not afterwards. That way, we can both enjoy working together and get issues out of the way quickly without them getting annoying over time.