DEV Community

Ben Halpern
Ben Halpern

Posted on

What are your guiding principles in software development?

Regardless of tech and challenge-specific context, what overarching principles do you come back to?

Discussion (39)

ben profile image
Ben Halpern Author

For me, I often go back to this Alan Kay quote:

Simple things should be simple, complex things should be possible.

To me it basically describes all great software.

jrohatiner profile image

The Commandments of a Great Frontend Developer

  1. I will represent the user and protect the user's interests to the best of my ability
  2. I will respect all challenges - human and technical
  3. I will not over-complicate my project
  4. I will honor all code that came before mine, respecting the work and struggles another developer may have put into their contribution.
  5. I will learn more and keep moving forward
  6. I will say "I don't know" if I don't know.
  7. I will think outside of the box without crushing the box.
  8. I will respect that my body needs to move and stretch and that my mind needs a rest as well.
  9. I will share my tools and offer mentoring to others.
  10. I will believe that anything is possible
kspeakman profile image
Kasey Speakman • Edited on

Understand the customer's actual problem, not the request specs.

Organization is hard and important to get right, so invest effort into it. When you put something in the wrong place it creates non-trivial, unnecessary overhead on future work. This applies to architecture, lines of code, and even the company itself. This is why "refactoring" (reorganizing) is important. Otherwise, the effort of overcoming disorganization eventually dwarfs forward progress. Aka "technical debt", only it is not really technical.

Production code is the only code you can count on. When it is in production, you have a feel for how much it costs to operate and maintain. Until then, it is guesswork and you cannot rely on it. As much as is possible, focus on releasing features incrementally to production instead of going dark for long periods of time. For new projects, deploy something simple and iterate. Building something complex to start is a losing proposition... unless you already have working production code you can use as a template.

Invest lightly in technologies but heavily in skills and understanding. Techs come and go constantly. Knowing a framework inside and out may be entirely wasted effort after a few years. But skills and logical concepts can serve you for many years to come. In practice, this means I prefer simple libraries where usage is obvious instead of frameworks with lots of abstractions. This also informs my preference for functional programming, because abstraction is minimized, and if you want to get into abstractions, they are based on provable/reusable mathematical properties... not some random opinion of the language/framework writer.

Be good to work with. You will never succeed without the cooperation of other people. There is no point in fighting this inevitability. Instead, work on improving yourself so that you can make the best of it. I am deeply introverted, so if I can learn enough to get by in this area, I know you can too. That classic book How to Win Friends and Influence People is a great starting point.

thomasjunkos profile image
Thomas Junkツ • Edited on

If I had to chose one principle to be my guiding principle, I would go for

KISS - Keep it stupid simple

Most of my career, I've been fixing / debugging other people's creations. And this taught me the lesson that it does not pay to be (too) clever.

Build systems mostly with primitives and simple abstractions helps avoiding errors easily and saving time and energy.

Or how Brian Kernighan once put it:

»Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?«

cjbrooks12 profile image
Casey Brooks

Slow down, take the time to do things right. You'll end up going faster in the end.

Numerous projects I've worked on with this in mind seemed to have really slow progress in the beginning, but really fast progress towards the end. In all cases we've always hit our initial timeline goals, but exceeded expectations on follow-up work.

shostarsson profile image
Rémi Lavedrine • Edited on

That is indeed a good approach but as I had experimented in a lot (too many for sure) of organizations, you are too often force to rush on things because of business deadlines, promises made (not by the devs) to the upper management, and the list could go on and on.
So if your Product Owner, Stakeholders, etc... are not from technical background you are going to have a hard time.

So I found it very useful to make quick Brown Bag Lunch open to everyone, so that anyone, from technical background to marketing etc can join, have fun and have a better understanding about what it takes to develop something. But as it is not the end, debug it, test it, deploy it, etc...

It is very helpful for everyone. And then if everyone speak a common language it makes things easier and we can tend to take the time to do things right so that we can go faster in the end.

champi profile image
Champi • Edited on

Yeah and do TDD.

sergio profile image
deleteme deleteme

I disagree with TDD. Sure write tests for your things, but TDD is just kool-aid that caught on in early 2013. Academically it makes sense, but in reality it's not practical.

matmooredev profile image
Mat • Edited on

My guiding principles:

Shorten feedback loops
Work iteratively and deploy small changes whenever possible. Catch errors as early as possible, and don't allow minor failures to become major ones. Minimise the cost of experimentation. Also don't force users to fill out lengthly forms and then present them with a bunch of errors at the end. This makes me sad.

Bias for action
This is stolen from amazon. It means don't spend a lot of time making decisions if the decisions are easily reversible.

If teams are quite risk averse they can default to having a meeting about everything. I can also slow things down by overanalysing something or thinking I need permission/buy-in to do something. Sometimes you just have to assume the answer will be yes, and ask things like "what if we just did X" to get things moving. If you're not sure if something will work, build a prototype and find out.

Minimise the amount of work in progress
Finishing things is more important than starting things. Avoid juggling multiple things at the same time, and try to resolve blockers as soon as possible. If you have to change what you're working on, be explicit that you're stopping working on the old thing to work on the new thing so managers understand why stuff isn't getting done.

When you are about to start a new thing, that's a good time to help other people finish their stuff, for example by pairing with them or reviewing their code.

Don't refuse requests for help
If someone asks you a question you can't answer, don't just say "I don't know" or act like it's not your problem. Help them find someone who can help them or suggest ways they can find the answer themselves.

Don't try to do everything by yourself
Know when to ask for help. If the site is down and you can't fix it in 5 minutes, get other people in involved in investigating or communicating what went wrong. Even if it's just someone to bounce ideas off of. If you're stuck on something for more than a couple of hours, ask someone else for advice - it will probably be a learning opportunity for both of you.

Also, don't become a single point of failure for your team. You should be able to go on holiday without the team grinding to a halt because only you know about something. Write code that is easy for your team/the future team to maintain.

Ask stupid questions
Stupid questions are useful for gaining insight. They can also prompt further discussion and force people to explain stuff in plain english.

It should always be ok to ask why you're doing something or why a more naive solution won't work. If someone explains something and it's slightly unclear, don't assume you understood it correctly, check your understanding with the other person by repeating it back to them.

Assume good intentions and learn from failure
Follow the retrospective prime directive. If something bad happens, focus less on the people and more on the systems, processes, and incentives that enabled it to happen.

If you have problems with someone else's behaviour, don't ascribe emotions or motivation to them. Talk about the things they objectively did, what the impact was, and what they could do differently. Find a way to be assertive without necessarily reacting in the moment.

Document anything important

  • Use architecture design records to document major technical decisions
  • If the domain is really complicated, draw diagrams that simplify it
  • Make an onboarding guide for new starters
  • Make a playbook for supporting your product in production
  • When investigating a thing, write down what you learned, then present it back to people
michaelgv profile image
Mike • Edited on

First and foremost for me, understand who wants what, and why. Take it slow and steady, I'd rather take 10 extra hours and have it "perfect(1)" than skip 20 hours and only half work. Don't write sixteen layers of abstraction, you'll give yourself and other developers a headache; if you don't need it, don't do it. Finally, take 30 seconds and write a comment somewhere about why you wrote that file/line/n... etc, it saves time for future developers not having to guess! Nice to have for me is a "maybe later" - it'd be nice to have a lot, but let's focus on what we need to have

(1) perfect, understanding there is some minor bugs, but the functionality is implemented to the best of my ability

rhymes profile image

I'm getting better at writing comments and commit messages about the why. The how is in the diff :-)

genejams profile image
  • zero design constraints, go with the flow
  • think of tomorrow uses while implementing
  • think also of tomorrow refactoring, so keep it clean and beautiful
  • do not add any functionality that can be achieved with the existing ones
  • avoid specialized solutions
  • document while implementing
  • if you can't get over a issue, take a break, you will tomorrow
gaja6413 profile image
Gajapathy Raj

Change is the constant in this world.
So, developing applications that can easily adapt the changes and can be easily extended is the key factor in software development.

Always keep in mind that anything you make is should be easily configurable.

sergio profile image
deleteme deleteme

Boring and simple! If your solution is overly architected and just a way for you to masturbate your ego, I'll tell you and we'll refactor to keep things simple.

Example: You have a crazy redux middleware razor form wrapped in a data wrapping component attached to actions and thunks and sagas and fuck!

Nah, we're just going to create a nice form with CSS and onSubmit={this._handleSubmit} handle the data POSTing to.

I code to make onboarding new engineers easy, that's my #1 goal when programming anything from websites to backend services.

katylava profile image
katy lavallee

There is no right answer or one true way.

Every time I think "Aha! This is how you do software development!" I run into someone who's very good at their job who doesn't do it that way. Ultimately I just strive for quality.

malgosiastp profile image

Creating quality product takes very long time. If you try to make it faster, it will take even more time

I found this on Twitter recently but this for sure is one of the principals I will follow.

jonlauridsen profile image
Jon Lauridsen • Edited on

The team must understand all changes. Together we stand.

We pair to ensure shared code-knowledge and no “waiting for review” queues, and I advocate for isolated PRs so other devs can look at closed PRs and make sense of recent changes. It’s tempting to push unrelated changes into your ongoing PR to save time but it confuses every time.

By isolated I mean a PR should have a simple, understandable title, it’s changes should all relate to that, and the size should be small enough that no one sighs when they see it.

rvprasad profile image
Venkatesh-Prasad Ranganath
  • Understand the problem and its context before devising a solution
  • Design interfaces and tests before implementation
lepinekong profile image

System thinking (excellent introduction by Ackoff must watch it you won't regret it'll make your day and even life), Deming PDSA (also known as PDCA in case you don't know Jeff Sutherland says PDCA is used by Scrum), Deming SoPK (System of Profound Knowledge).

ravernkoh profile image
Ravern Koh

Less code is more ☺️

mathur_anurag profile image
Anurag Mathur 

In addition to what others have mentioned, I value the following:

  1. My product is ethical, my design is ethical, my code is ethical and my team never builds anything in violation to this.
  2. Whatever is built has good UX.
  3. Code and design are extendible and maintenable.
  4. We don’t rediscover and reinvent the wheel twice in the same project.
juankortiz profile image

With my limited experience, I'm trying to teach my clients that "rushing" the developer isn't the greatest experience. For me, quality is better than speed, and taking the time to correct errors and improving the code is time well invested.

sam_ferree profile image
Sam Ferree • Edited on

"Make it work. Make it right. Make it fast" -Steve Smith

"Legacy code is code without tests" -Michael Feathers
"...You could be writing legacy code right now." -continuation by Rich Campbell

"Nothing is a performance issue until the profiler says it is" -Rich Campbell

Some of my own musings:

The question is so rarely "Should I log this?", but instead "At what level should I log this?", Ops can decide how chatty they want the logs to be based on how the system is running.

Schedule time to refactor, right after your tests pass is a fantastic time.

Don't ask the business or customer for permission to write tests or refactor. You're in charge of the product you deliver.

alchermd profile image
John Alcher

Real developers ship. Sounds elitist and I can't even remember where I first read it, but it's a really nice principle to follow.

bgadrian profile image
Adrian B.G.

The response could be an entire book, but a few that comes in mind:

  • do not forget you have to solve a real problem, and that is your goal
  • use proper tools, ex: if I can solve the problem by using a bash command or a spreadsheet in 5min each month is ok, even if I know few programming languages
  • KISS, this can be applied in many things, and is one of the hardest to comply. eg: do not over engineer, do not future proof, do not apply micro-performance smart code or "code tricks"
  • DRY but only until it makes sense, and it doesn't: over complicate things or make unnecessary dependencies (between modules/services)
  • Single source of truth (applies to Code, Data flow, documentation)
  • if you had to make a manual action, more then 3 times in a month or so, automate it
  • keep project-level consistency, even go to extreme enforcing linters warnings as a blocker to PR/merge. If the base is rotten, probably is full of bugs.
  • leave the code better than you found it, everyday, every task, every sprint
erikthered profile image
Erik Nelson

I always try to keep in mind that someone else will eventually inherit whatever project I'm currently working on, accordingly:

  1. Write easy to follow code: this is certainly a balancing act, you don't want to be needlessly verbose, but I've seen plenty of developers go too far in the other direction and write "clever" code that is short but much too difficult to unwind and understand.

  2. Document just enough: you should cover things that are necessary for a new developer to get up to speed quickly, such as "how do I run this on my development machine?". I'm surprised at how often this type of information is left out. It's also a good idea to explain why certain design decisions were made in a project.

I've got more guiding principals than just these two, but I'd certainly appreciate it if others would consider adding these two to their own.

stenpittet profile image

I really love Kasey's and Mat's answers in this thread and I only have a few more things to add to it.

Seek first to understand

It's really easy to find code that does not look great, especially in old codebases. But it's important to try to understand context before lashing out. There are legit cases where it was a job being poorly handled, but a lot of the time the answer is more subtle. Priorities, budgets, technical constraints, maturity... There are many reasons why you might be looking at something and thinking - oh my god, why did they do it that way?!

Hope for the best, prepare for the worst

Make sure that you know what could go wrong with your product. It does not mean having a fix for every possible problem, but it means having estimated the risks and knowing which ones need a mitigation plan. This is especially true if you're dealing with private data (probably 90% of apps today...).

Build for the refactor

You'll rarely see code that doesn't need to be changed. That's because software is built on moving foundations. Technology evolves, user behaviors change and you need to adapt to it. So make your code easy to replace because even if it's perfect now, there's a high chance that it'll be changed in the future. Pick clarity over cleverness.

Do retrospectives

The single, most powerful tool I've seen used in my experience is the practice of retrospectives. There are many ways to run them but no matter how you do them they bring amazing benefits. They naturally force you to stop, look back and improve of your work - and they give your team an excellent opportunity to provide feedback. Embrace them!

vrushaliwaykole profile image

For me it's -
Refactor when it's necessary. Don't delay it, otherwise the codebase will keep on increasing and will become unmanageable one day.

jaimemateo profile image
Jaime Mateo • Edited on

In the last times in my team we are approaching a principle of "divide and conquer" for almost everything.

Taking this to a development example, the Pull Requests we make are very small (always under 300-500 lines of code). Then we end with a lot of pull requests that are very easy to review and this makes the team much more agile.

hoelzro profile image
Rob Hoelz

Premature optimization isn't just about speed/memory usage - it covers things like abstraction or thinking ahead for potential features, too. As Sandi Metz says:

duplication is far cheaper than the wrong abstraction

Obviously with features it gets tricky - you don't want to create a program that's hard to extend to add new things later! There's a lot of nuance involved, which brings me to my next point...

Don't be dogmatic; context is everything. Sometimes TDD is the right decision, sometimes it's not. Sometimes switching the team to deploy on Docker is the right decision, sometimes it's not. Sometimes rewriting a component in Rust is the right decision, sometime it's not.

A lot of blog posts don't cover the context behind the decision, which is like doing math problems without showing your work. And a lot of hard decisions never end up solidified in blog post form, because communicating that nuance and context is really hard!

This is something I've seen in a lot of blog posts recently (such as those written by Ted Kaminski), and I'm glad. I wish I had links to each of the ones I've read discussing this, but they're kind of hard to find in my history!

de_maric profile image
Dejan Maric

A lot of blog posts don't cover the context behind the decision, which is like doing math problems without showing your work.

This is so true. Every year we developers come from our favourite conferences and are so geared up to completely rewrite our apps. Whether it was (or is) SOA, NoSQL, microservices, you name it, we jump the bandwagon without thinking whether we really need the technology. Just because Google/Facebook/Netflix/Spotify is doing it, doesn't mean you have to.

lewiscowles1986 profile image
Lewis Cowles

Simplicity, functionality

courier10pt profile image
Bob van Hoove

At the 'top level' it should be easy to figure out what is going on.

dfockler profile image
Dan Fockler

I think mostly it's being comfortable relying on abstractions until something doesn't work, and then being comfortable digging into the details to fix the it.

adampb profile image
Adam Piechocki-Brown

Your code does not exist in a vacuum. Keep the wider context in mind.

Consider the social, moral and political implications of the code you create. Do no harm.

robertsvensson profile image
Robert Svensson

Plan, plan and plan. Then plan some more. Once, you're done planning - code as little as possible.

mortoray profile image
edA‑qa mort‑ora‑y

Put the user first! Use-driven-development is my guiding principle.