DEV Community

Ben Halpern
Ben Halpern Subscriber

Posted on

What are the least intuitive fundamentals and best practices in software development?

Some things we do kind of make sense in and of themself. Some things have evolved to be the way we do it but just don’t map up to our brains cleanly at first.

What are the non-intuitive parts of our craft?

Latest comments (47)

Collapse
 
_hs_ profile image
HS

Patterns everywhere. And unit testing everything. Unit testing is adding more code to check is code workig. It ussually ends in tests being green yet application not working correctly. Basically you spend more time writting tests that will be obsolete in some time as the test are usually written to test feature in a wrong way. It doesn't mean don't test. It means unit testing everything won't help you all the time.

Collapse
 
aarone4 profile image
Aaron Reese

Not easy on brownfield, but this is what TDD is for. The spec becomes the tests and you then write code that passes the tests. If business needs change, then tests change first then the code. Writing comprehensive tests is cheaper than rewriting code because the requirements were not well understood.

Collapse
 
_hs_ profile image
HS

It usually ends up being other way around. Tests pass because people still don't understand requirements and no one knows what's the issue, than you change tests and make code pass test but in live environment it fails to deliver. Besides as from Uncle B Martin TDD is about architecture not having well tested code. You can find him telling that on multiple occasions but find Jim Complain and him discussing it. For him it's for helping you check what needs to be built how. Last time I did it in C# I ended up exposing too much services and mappers which made it confusing to deliver new features and code was to chopped up. Ended up removing almost all unit tests leaving only ones for calculations and having only sort of end to end test with scenario like approach close to regression test which made much more sense and made architectrue much more clean.

I met too many people disagreeing with usefulness of having a lot of test coverage. Having great QA team that understand clients need beats test for now in my experience.

Still my experience and people I met. I don't think no one benefits from it, just haven't met those people in person.

Collapse
 
juliusdelta profile image
JD Gonzales

Abstraction and DSLs practically.

Process more non-practically.

Everyone has opinions on what a good product development process is, but because people vary so much it's hard to say with any certainty that "[insert your favorite thing here] process is best." So many things impact process, from the very people themselves to the business model of the company. It's very hard to determine a good process, experiment, iterate, and improve upon it because it requires time, planning, and a significant amount of thinking. It's even worse if the team you work with is large but the process isn't working. Stakeholders who are unaware of the product life cycle might just see it as a broken machine that needs "motivation" rather than optimization of some kind.

I graduated from a boot camp a few years ago, and this is definitely one of the things they don't tell you about ;).

Collapse
 
jdmedlock profile image
Jim Medlock

The worst teams are often top heavy with rock star developers. The best teams are those with a broad range of experience, culture, and ideas.

Collapse
 
kayis profile image
K

To me, it's still TDD.

Sorry

Collapse
 
remojansen profile image
Remo H. Jansen

Software principles, design patterns, and practices should never be considered as a law that one must follow at all times. These are just heuristics. They are guidelines that we should apply carefully and only in the right amounts. For example, if we take the DRY principle to the extreme, we are more likely to introduce too many abstractions and many times the wrong abstraction is worst than code duplication. In my experience, the same can be said about almost every other software principle. So my recommendation is never to follow principles blindly and to use them with moderation and judgment. I call this idea the The Yin and Yang principle of software architecture.

Collapse
 
steelwolf180 profile image
Max Ong Zong Bao • Edited

The usage of style guides those are the one that doesn't wrap around my head when I first started.

Cause I have no idea why you should do that except cases in developing. Luckily we have linters that comes with almost all of the programming or scripting languages in IDEs or text editors that I had been working with.

Collapse
 
nektro profile image
Meghan (she/her)

Just because users are asking for a feature, the reason they give might not be the root problem.

However, users are the greatest sources of finding pain points and bottlenecks throughout your program. This is commonly called usability testing.

Collapse
 
aarone4 profile image
Aaron Reese

And this is where a great BA is vital. Give the user what they need, not what they ask for. The analogy I use is going into a hardware store and asking for a 6mm (1/4 inch) drill bit. You don't want a 6mm bit, you want a 6mm hole. If I dig a bit further, what you are actually going is trying to hang a picture. If I can build you a picture hanging process that is repeatable, automated and 10x faster, now I have solved the business problem rather than letting the inexperienced user do the requirements analysis

Collapse
 
cjbrooks12 profile image
Casey Brooks

The whole concept of application "state". It's very much a part of the language of React and other functional-style frameworks/libraries, but that doesn't mean those are the only things that deal with state.

It can be especially difficult to understand state and its impact in a world like Android, where there isn't an established pattern for state management. Android has built-in support for marshaling state immutably between UI components without them needing to share a global object, but it is very tedious and requires an incredible amount of boilerplate, even when using code-gen tools. So most codebases don't do this properly, and subtle bugs start to become major issues as more and more of your app is sharing a data source with no governance.

But once you get used to the idea of passing all data around as immutable objects and not allowing yourself to "set and forget" variables, your codebase will become much easier to read and maintain, especially for new developers who didn't originally write it. Everything they need is handed to them, they don't have to go hunting for it.

Collapse
 
_bigblind profile image
Frederik 👨‍💻➡️🌐 Creemers

I'm sorry if I'm harping too much on this, but it's been on my mind because it's something that I want to change in my own way of thinking as well.

Organize code by domain, not by architecture component.

Very often I find myself creating directories named "components", "reducers", "routes", ... at the top level of a React/redux app, or "models", "views", "controllers" in an MVC app. Avoid that!.

Try grouping things by what functionality they offer in the app. For example, put the User model, profile view, password reset form and logic, etc... all in a "users" folder. This way, changes are more often confined to a single directory.

I think this could actually be an intuitive idea, but we're often taught a framework or technology, starting from the architectural overview, so that's how we often structure these things in our mind when starting out. Some scaffolding tools even default to building a structure like this.

Collapse
 
keirlavelle profile image
keir-lavelle

I would tend to disagree when it comes to components, I think that style of code organization leads to a high amount of repetition, and can make sharing components unintuitive.

For example, you need a simple card component on your user profile so now Card.js lives under /User, but then after some time the same card is to be re-used by another view - now in a large codebase with different devs working on the features in parallel because there is no common place where components exist, it's not totally unlikely that the same UI component is made twice, which doubles future work when the styling needs to be changed.

Even if that worst case scenario doesn't come to pass, in your code you'll end up with import Card from "../../User/Card" or something of that sort, which feels really messy and a bit discombobulating for the dev who's working in that area currently ("Why are we importing a UserCard in our Music view?") or if you decide to lift that component when it gets re-used then you'll end up with a UI component at the top level alongside your journey or feature directories, which feels equally as messy.

Routes and models and things like that are well grouped by domain feature that they represent I guess, but components should probably by and large be feature agnostic, and aren"t a good fit for this organisation technique.

Collapse
 
_bigblind profile image
Frederik 👨‍💻➡️🌐 Creemers

I think it’s perfectly fine to have directories for cross cutting concerns like generic interface elements, logging, network communication, etc.

Collapse
 
cjbrooks12 profile image
Casey Brooks

I actually find it's best to use a combination of these. Start by grouping by domain (which may be nested), and then within your domain folders have an opinionated directory structure organized by architecture component. So, for any given domain, the code is organized the same internally, but it's nicely separated from other domains and easy to navigate to.

Bonus points if you use some kind of multiproject structure where each domain's isolation is actually enforced by compilation boundaries, but able to communicate through a shared module's interfaces.

Collapse
 
_bigblind profile image
Frederik 👨‍💻➡️🌐 Creemers

Completely agree.

Collapse
 
mortoray profile image
edA‑qa mort‑ora‑y

Non-intuitive: There's generally no correlation between amount of code and usefulness to a user. There is however a definite correlation between amount of code and amount of defects.

This leads to the best practice of keeping code as small as possible, primarily through reduced redundancy.


Non-intuitive: Comments are the least effective way to describe what code is doing. They end up diverging from the code over time, and may miss nuances. Comments can actually make code harder to read.

Code is the best way to describe code. Using effective names and clear structures is far better than comments.

Collapse
 
eljayadobe profile image
Eljay-Adobe

Reminds me of a quote (reformatted):

Goal of programmers is to ship, on time, on budget. It’s not “to produce code.”

IMO most modern C++ proponents:
1) overassign importance to source code, over
2) compile times, debugability, cognitive load for new concepts and extra complexity, project needs, et cetera

2 is what matters.

~ Christer Ericson

Collapse
 
mortoray profile image
edA‑qa mort‑ora‑y

Isn't the importance of the code what helps ensure all that stuff under 2?

Collapse
 
kungtotte profile image
Thomas Landin

Regarding your first point, I'm reminded of Jack Diederich's talk "Stop Writing Classes" where he says: we don't ship code, we ship features.

He also says "I hate code and I want as little of it as possible in our product" :)

Collapse
 
mortoray profile image
edA‑qa mort‑ora‑y

I'm sure he'd appreciate that my book What is Programming? starts out by looking at users and understanding features, not even getting to code until about half way through. :)

Yes, we have to learn that code is a tool, it is not the product.

Collapse
 
cjbrooks12 profile image
Casey Brooks

Comments should never be used to describe what code is doing. It should describe why it's being done the way it is. You've got the code right in front of you, but if it isn't immediately obvious what it's doing, a comment explaining the why is quite nice. Note that these comments rarely go at the declaration site of a method, they're more effective when they're written inline, as close to its relevant code as possible.

And on the other extreme, don't go so deep into the why comments that the code becomes difficult to read. The code is still the shining star, make sure it is still easy to find the code amongst your comments. Anything longer should go in the official documentation.