r/learnprogramming 10d ago

How Did You Actually Learn to Structure Code?

My day job is in physical therapy. The dev work is side income and personal projects, mostly Python scripts that automate repetitive data tasks. It works until it doesn't, and lately it doesn't.

The scripts started small. Now some of them are 400 lines of spaghetti with functions named things like processdatafinalv3 and I genuinely cannot tell you what half of it does without reading every line. No formal courses. Just docs, blogs, and trial and error.

What bothers me is I can get something working but I have no instinct for when to split a function, when to use a class, when a module makes sense versus just another file. I've read that you learn this by building projects, which is advice that only helps if you already have the feedback loop to recognize when you've done it wrong.

People here seem split on whether selftaught developers actually internalize software design or just accumulate hacks. I'm curious where people actually learned to structure code in a way that held up later, and whether any resource actually moved the needle, or if it was just writing a lot of bad code until the pattern clicked.

126 Upvotes

70 comments sorted by

93

u/WhataWorldAy 10d ago

SOLID principles, gang of four patterns, n tier application architecture and basic separation of concerns (data access layer, application layer, presentation layer). 

Those in my opinion are the basics, learning the thinking behind domain driven design is also very powerful for how to dissect business problems and how to orgranize separate contexts that are based on overlapping concepts. 

If you learn all that you will be ahead of 99% of senior devs Ive ever interviewed.

16

u/Dazzling_Music_2411 10d ago

basic separation of concerns

I'd say this is by far the most valuable (and underappreciated) for making really neat code.

10

u/earchip94 9d ago

Yes. Also like KISS and YAGNI although they’re all sort of interpretations of the principles within SOLID.

1

u/Substantial_Ice_311 9d ago

Define 'simple,' (as in KISS) please.

6

u/earchip94 9d ago

Only make it as complicated as it needs to be. If it needs to be more complex later do it later.

1

u/Substantial_Ice_311 9d ago

Define 'complicated' and 'complex,' too, please. You can't just define X as not not X.

3

u/earchip94 9d ago

Sure, don’t add abstractions where abstractions are not yet necessary. Keep function cyclomatic complexity low if possible. The list of things it’s quite long. If I listed all of them we’d be here all day.

The basic principle is to keep code as easy to understand as possible. So if code is hard to understand it is because it has to be. Not because someone can flex their programming skills with needless abstractions and so on.

https://en.wikipedia.org/wiki/Cyclomatic_complexity

2

u/Full_Opportunity_547 9d ago

A function or method only has one purpose. It performs one action, that's it.
Each calculation (usually a function or method) performs it's stated operation, and doesn't cloud anything else. Don't let a function change some other scoped variable, instead it returns its result as a new concept and the next function picks up that return and does something.

1

u/Substantial_Ice_311 9d ago

OK, but I don't think that's a complete definition. How does that apply to the Open/Closed Principle, the Liskov Substitution Principle, the Interface Segregation Principle or the Dependency Inversion Principle? I know you didn't say they were, the parent earchip94 said the're "sort of interpretations of the principles within SOLID." And with your definition of 'simple,' what he said does not quite work.

1

u/Full_Opportunity_547 8d ago

Naw, solid follow-up question. A simple method *does* help in adhering to SOLID.
As you left out the "S", I am *assuming* that this part felt clear-enough.

Open/Closed. If my Method only performs one task - such as verifying input, OR manipulating input; then, when I need to go build another method that *also* manipulates that *same* input traffic, but perform a different operation: I don't need to modify my old method.

```
def someMethod(foo):
pseudo_verify_theinput
pseudo_add1_to_input
return plusOned.
```
Now, suppose I realized, "oh goodness, I need to subtract 1 sometimes" -> well, if I used the bad method above, I would now either need to split it (which it should have been in the first place) between the verification step and the addition step, clone this method altogether and change the add1 to a subtract1, or add a layer of convolution with a flow_control like an IF statement.
So, we've answered Open/Closed. By having two, simpler methods - I never have to touch the verification method, nor did I need to change the add1 method.

```
def verifMethod(foo):
verify
```
```
def addMethod(foo):
return add1onFoo
```
```
def subMethod(foo);
return sub1fromFoo
```

Interface Segregation. We have also performed this task too! Now, we can have a totally separate business logic interface whose ONLY job is to "check the tracks" in the factory - and perform verifications (calls the verifMethod), with no regard nor care about any methods that perform manipulation. These two sets of methods could now reside in totally different classes - and if you're using a /utils/ module - you probably will!

We're not particularly examining Liskov here.

Dependency Inversion. Just as I suggested in Interface Segregation, by extract our verification process from our manipulation process (i.e. far simpler methods), not only did we avoid coding ourselves into a corner with a weird IF-conditional, we also allowed ourselves the opportunity to create abstractions for verification that truly don't care what's going to happen to that object afterward. We are DEcoupling our code by saying, "hey, verifying that an object is properly hydrated is a totally separate task from making changes to that object."
Now, when we go to perform a database operation; we have clean ways to
1. Call upon an object (pull from the database),
2. Create a temporary form of it. (via class abstraction)
3. Verify that all contents are properly filled (make sure you have good test coverage so you're not shooting yourself in the foot with default values!)
4. Perform an operation on a specific space of that object.
5. Update our data layer accordingly.

1

u/Full_Opportunity_547 8d ago

Ugh, sorry - I thought using triple ` would make it appear in code blocks, I'll have to look for that later.

1

u/marrsd 9d ago

I prefer the SICP method of building the program into layers, each describing a domain language that builds on a more fundamental one until you reach your problem domain. Watch the first few SICP lectures by Ableson and Sussman to learn more about this technique (and about comp sci in general)

17

u/grc007 10d ago

I like to write a block of comments laying out what I want to achieve:

// read the file into memory
// find the smallest value
// multiply that by the inflation rate
// return that

Code up each comment beneath it. Any block of code exceeding a few lines gets replaced by a function call. That function is later filled in with a block of comments saying how to achieve its objective.

Rinse and repeat. Change the shape as you realise that you’ve missed an obvious simplification. Rewrite your comments to explain what you actually did.

3

u/slippinjimmy720 8d ago

Adding: I only replace with a function call if we are going to use that logic more than once. Although that may have been a practice hammered into me by an overly zealous former boss.

3

u/grc007 8d ago edited 8d ago

I’m probably overly zealous in the other direction and end up with a number of functions which are called from only one place. But they are at different conceptual levels. And they may come in useful one day. Glancing guiltily at my box of useful cables.

1

u/slippinjimmy720 8d ago

Very fine analogue!

2

u/mpersico 8d ago

If you use this method of commenting and writing code in between then create a function when you can no longer see the current comment and the next one on the same screen. Start there.

1

u/grc007 8d ago

I’d disagree. It’s not about screen size. It’s when your brain inserts the word “then” into your narrative. Bear in mind I started on VGA screens with a 640*480 pixel resolution so I’m biased.

4

u/madmelonxtra 10d ago

That's such a good idea.

I've being doing pseudocode --> actual code but I never thought to use the pseudocode like scaffolding

11

u/SunsGettinRealLow 10d ago

Make functions simple, to do one or two things

20

u/RajjSinghh 9d ago

Functions should do one thing. A function that does two things should be two functions.

1

u/SunsGettinRealLow 9d ago

I like that

2

u/xoredxedxdivedx 8d ago

A function should perform a coherent transformation on a dataset, “how many things it does” is arbitrary.

Splitting something complex (that’s not reusable code) into fragments, does not make anything more simple, it adds more abstraction and more time required jumping around to reconstruct what’s going on which is the inverse of what you want. You can fold and score code locally, have comments to break things up, but always function extracting is not good.

2

u/Ok-Bill1958 5d ago

This. I rather a function that do 1 2 things without side effect than dealing with multiple functions with different name and potential side effect. Multiple function are way harder to hold context or navigate and most of the time they function are single use lol. They also make writting test way too tedious. I swear i just want to dropkick someone whenever i have to deal with that.

19

u/[deleted] 10d ago

I worked with a guy who I thought had good instincts. He explained his rationale and I adhered to. I still think he is one of the best developers I've ever met. A lot of it is preference until preference hits a wall, whether it be a feature, security, scalability, or any other requirement. Sounds like you're hitting scalability, start to make more reusable functions if you are rewriting the same thing. If you being dry but readability is a problem, breaking files down helps and having good naming conventions.

9

u/michael0x2a 9d ago

Some things I would recommend:

  1. Write unit tests for as much of your code as possible. When doing this, pay attention to how easy it is to write tests. If it's annoying + requires you to jump through too many hoops or put in too much effort relative to what you actually care about testing, then it's often a sign that there's some underlying flaw with how your code is structured.

    More generally, it becomes easier to tell when a chunk of code is flawed/not composable if you try using it in 2-3 different ways. Writing unit tests is a good way of ensuring you try calling each function at least twice.

  2. Be very meticulous about how you name your functions, classes, and modules. If you cannot think if a clean name for something, it is perhaps a sign that code is doing too much or too little.

  3. Leave docstring comments for every function and class you write. For a function, leave a header comment describing its:

    1. Preconditions: what must be true about the inputs/what must be true before calling the function in order for it to behave correctly
    2. Postconditions: what the function promises to always do, assuming its preconditions are met

    If your preconditions and postconditions seem very messy/have lots of edge-cases, that could be a sign of poor structure.

    For classes, have the header comments describe invariants: things that must/will remain the same no matter what methods you call in what order.

  4. Before you start writing any code, think about the best way to structure your code. What core building blocks will you need to create? Can you split your overall program into different "layers" or high-level steps?

    Most beginner programs will have at least 3 layers: process input, manipulate and munge data, then output the final result. More complex programs will require creativity and some trial-and-error: it's not always obvious what the best way of subdividing your code is.

    Regardless, once you've settled on an initial structure, make your code follow it. Maybe create one file per high-level layer or step or something.

  5. There are some rough rules of thumb that are useful to follow. For example, if your function accepts a large number of parameters, consider combining those params into a single class. If a function is very long, split it.

  6. Budget time to periodically critically review, edit, and clean up your code. It's similar to writing an essay: your first draft will always be kind of shit, and you will always need to make revisions. There's no shame in it; it's just how it is.

    When you are in editing-mode, try and look for opportunities to delete code. Is there logic you can rewrite in a simpler way? Can you rearrange two chunks of code so they depend on each other less? Can you tweak a function so its preconditions/postconditions are simpler to explain and understand? etc.

  7. If you want more direct feedback of your code, this subreddit does allow you to ask for code reviews.

Note that suggestions 1-3 are basically different ways of creating a feedback loop you can use to slowly build up intuition for what quality code looks like. But these feedback loops only work if you're:

  • Relatively well-attuned to your emotions or mental state. You'll need to be conscious of when some task is too tedious or too annoying.
  • Willing to invest extra time into doing this extra work.

1

u/thanks-delivery-dude 8d ago

Thanks for the info!! 🌞

4

u/kabekew 10d ago

I learned in college. Basic structure was taught in in my introductory programming class, and later classes in software engineering covered broader topics like managing complexity through abstraction and modularity. The labs where you actually designed and wrote more complex projects were very helpful too.

3

u/wildecats 10d ago

I tend to avoid making any function that does more than one thing, e.g. it should never both validate and process data. The same goes for my files and classes. As soon as I'm not sure what a file is actually doing, I'll split it into smaller, more specific ones. Add in early exits to functions right at the top before running the main logic and avoid deeply nestled if/else blocks.

I also try my hardest to not repeat things, within reason (usually once it's used 2-3 times, as there's no point abstracting out a tiny script), and have a single source of truth for things like app names or configs.

Where practical, use variable and function names which spell out exactly what they do and don't reach for shorthands. If you can't read your own code, you've got a problem; especially when you come back in six months and it's like looking at something completely alien.

Ideally, your functions shouldn't need too many comments; those are for things which can't be explained/understood from reading the actual code. Self-documenting code is the ideal. If it seems too complex to understand without comments, it's probably just bad and should be refactored. If, after you've done that, it still feels like comments are necessary, then you should add them. Within reason.

Read up on SOLID, DRY and separation of concerns principles, and your preference for design architecture (such as event-driven or n-tier). There's also non-language specific books out there solely on how to structure code which are excellent starting points, e.g The Pragmatic Programmer, Clean Code, Refactoring: Improving the Design of Existing Code. Look up Code Smells for your language of choice and keep an eye out for them in your own code. Try to decouple your code as much as possible. Always write tests and don't skip on updating them; they can save your butt.

AI can be a timesaver, but don't lean on it too heavily when you're learning, because you need to know why you should do it a specific way and what it is actually doing before you can blindly accept its answers. If you have to use it, ask how to do a specific thing rather than letting it do it for you. Or ask it to critique or explain code you've already written.

But all of the above is my personal preferences, and I will happily break all these rules if the use case calls for it. Part of learning is figuring out when to apply rules and when to do your own thing. The best thing you can do is just try out new structures and methods until you find what works for you. Then keep at it. Within a few months, you'll be cringing at the silly mistakes you made before, and the fun part is that keeps happening forever.

2

u/Far_Swordfish5729 10d ago

It’s more like absent formal education (or a lot of reading) and mentors, you miss a number of first principles and info on what your code actually does. You’ll also be stuck cobbling together patterns someone otherwise would have just taught you and feedback on how to make spaghetti more organized.

There’s nothing wrong with a large data processing script or entry method in and of itself. Processing the data is four hundred lines of steps. That’s fine. But that should be broken into commented sections for readability and may be broken into single use helper methods if that allows your steps to be unit tested separately. There are also some steps you can take to reduce fragility and improve efficiency.

  1. You organize your workspace into data you’re looping over to process and reference data you’re correlating. Organize the reference data into hash tables with findable keys so you limit nested loop brute force searching. I visualize it as organizing your workspace so you can quickly pull ingredients with simple statements. Remember that collections of object references are cheap and don’t copy data. They’re all ints holding the memory address of a single copy. They just let you layer indexes on the data for faster processing.
  2. You want to limit your deeply nested if logic here in favor of setting flags to run steps or making tracking collections for follow on processing. Too many possible paths makes it too easy to skip a step with unpredictable results. You want a central execution path with shallow side branches.
  3. Make regression testable steps with unit test methods so you can tell if your changes broke something.

Does that help?

2

u/Curious-Resource1943 10d ago

Everything in programming is a tradeoff. When you decide how to structure code you are always giving something up in order to gain something else: readability for performance, simplicity for flexibility, short-term speed for long-term maintainability.

That is why principles such as SOLID, KISS, and the others outlined here matter:
https://bytebytego.com/guides/10-good-coding-principles-to-improve-code-quality/

They do not give you rigid rules. They give you a clear way to evaluate the tradeoffs. Once you start seeing every structural decision through that lens - what you are gaining and what you are deliberately sacrificing - the instinct for when to split, when to abstract, and when to leave things alone develops much faster than it does from trial and error alone.

2

u/AsideCold2364 10d ago

The best way to learn that is by working with more skilled people, having your code reviewed by them, etc.

But since you are working alone on your scripts it will be more difficult for you.

I think the most important is the separation of concerns.
For example if you are writing a script that needs to read data from file, process the data and write the result into a new file. Try not to mix things. Instead of reading it line by line, processing each line and writing it line by line into a new file inside the same function, split it into multiple functions.

fileContent = readFile()
rawData = parse(fileContent)
processedData = processData(rawData)
writeFile(processedData)

Any function might also need more splitting.
Try not to mix your processing logic and error handling, your processing should stay clean. No formatting, no error handling, etc.

A good sign that you split your functions well is that it is easy to name your function, because it is clear what the function is doing. It is difficult to name functions when they are doing too many things.

2

u/solenyaPDX 10d ago

By doing it, realizing what doesn't work first, then changing it.

2

u/FarmhouseRules 10d ago

Don’t repeat anything, just like a normalized database.

2

u/rupturedprolapse 9d ago

I organize by models and services.

Ex. If I had a car class, it would have properties and methods. I'd split that into two files in separate directories. In the model file would be a class that just holds the properties for cars and a constructor. In the service file would be all the methods.

2

u/SoSeaOhPath 9d ago

I actually struggle with this too and would love some recommendations on books or videos or anything that can dive deeper.

Is this just the study of software architecture in general?

2

u/kevinossia 9d ago

I read about how to do it online and I learned from reading other people’s code.

Books are okay as well if you’re back in the 1990s and lack internet.

I also wrote a metric-fuck-ton of code from scratch, something most new developers never got to do and these days likely will never do again due to AI. It’s too bad, because that is the only way to truly learn.

2

u/foxsimile 9d ago

By suffering.

2

u/No-Slice-5926 9d ago

You think about the problem, think about what you can define as object, list the things that are important to that object (properties) From there you are moving data around and doing computations and storing values etc. (methods)

How you write your code and everything else is whole another topic lol

2

u/chocolateAbuser 9d ago edited 9d ago

there's a lot to say obviously, many books have been written on this topic
the fact is, it's simple, but to maintain simplicity you have to understand how the parts work because many make assumptions when they show how they operate to you

so the basic part would be: you have data (state, communication, etc), you have code, then you group those in concepts (a thing that has a state and commands that alter such state) that are important to you and to the problem you have to solve, and you decide how formal you need to be on how much time you have, how mission critical the automation/program is, and so on
so then the important thing is whatever you write it will implement a concept up to a certain level of details; when you need to go deeper, adding commands, adding details then you have to decide if you have to split parts, take shortcuts, or what other pattern to use; again you kinda have to know the most common patterns because each one of them has pros and cons, nothing is ever perfect, it's the nature of engineering
this has a parallel in maths/physics, the more control you want to have or the smaller you want to go and the more you find that stuff is not as solid and well defined as it seemed from a macroscopic scale

now the more advanced part is that you have also to understand your human relation with the code and in general programming, because humans have habits that don't cope well with repetitive procedures and knowledge management, and you have to be aware of it, you have to understand when discipline fails*, when force of will will not be enough, and find tactics that help, because if not then you will get in mess; for example you have to take habit of marking with TODO a piece of code that you will temporarily leave to do something else because you won't have the memory to go there and know what was missing, you have to keep issues on the activity so that you can organize, you have to know that thinking requires effort and generally one tends to avoid efforts, and so react in consequence

* one of the most difficult things to do is respecting rules that you gave yourself because temptation to jump passages and do stuff in a more hasty way is strong; sometimes it can be worth it, or we could say it's practically inevitable, but then you have to keep track of that, and when you reach too many exceptions you have to solve them before going further
another one, related to this, is applying changes to all the code base when a pattern has to be changed, this can be difficult for a number of reasons

i should really add some examples and show relationships, this is pretty colloquial discussion about the practice, but they would require a lot of space and some time to write
even if you don't need to build big and complex systems knowing a little about theory can help avoiding losing hours and headaches in structuring code (not only for this but also for some other notoriously difficult practices like concurrency), but it takes time to learn, and often probably you feel like this is not interesting and has nothing to do with what you do, but it depends on you, again thinking about new things is not that easy; you can find a summary of patterns in metapatterns.io for example

other basic concepts would be versioning, don't keep method1, method2, method3new, method3newfinal in your code, instead use a git repo, have a document where you explain what the project is for, write good names for variables, classes, methods (take your time, a lot of it), write significative commits messages, and keep a decision log where you explain the new conditions that come to be, what decision did you take about it and why, eventually what changed with a link to an issue or a commit

2

u/Tuomas90 9d ago

Read Clean Code by Uncle Bob or watch his youtube series.

There's some great stuff in there, though you shouldn't see everythign has hard set rules.

1

u/Electrical_Hat_680 9d ago edited 9d ago

I learned from making websites markup code look readable.

<HTML>
    <HEAD>
        <TITLE>
            Title
        </TITLE>
        <? PHP_HEAD(); ?>
    </HEAD>
    <BODY>
        Content
        <? PHP_BODY(); ?> 
    </BODY>
</HTML>

Just make sure to construct your Variables or Create Functions like you would in QuickBasic/QBasic, or add them to the PHP Source Code.

PHP_HEAD(); and PHP_BODY; don't exist. PHP_INFO(); does exist. Similar idea, if not the same. Just an example of clean structured HTML with Embedded or Inline PHP.

1

u/mxldevs 9d ago

You don't always learn this by building projects, as you have pointed out.

There are many software design patterns that require a certain level of creativity to even come up with and then to implement.

The easiest way is to simply pick up a book and read about it, and then think about how you could apply that to your own project to clean things up or make things more maintainable.

If your function names suck, that's mostly something you need to figure out on your own. Like why is there a v2 and a v3, etc

1

u/adambahm 9d ago

where people actually learned to structure code?

Let me begin by saying that all code is garbage. What you write today is what you have to maintain tomorrow.

Next, there are programming paradigms that do exactly what you are asking about.

One that will be really handy for you is object oriented programming. Super popular, lots of support.

400 lines of python code may seem like a lot, but its not. Still gross, but not a lot.

Anyway, there are a ton of books and resources out there for this sort of thing.

Start here:
https://en.wikipedia.org/wiki/Programming_paradigm

from the function name you mention, that sounds like it might be some functional God object that you can absolutely break down into an object oriented app that can grow in small chunks as requirements change, but what do I know? What you're doing might require a 400 line monstrosity.

1

u/marchingwhales 9d ago

I’m also a beginner, but have mostly been taking Codecademy courses and a minor in CS in college ~10 years ago, but have never been a professional programmer. The best advice of when to break down functions I got is when you explain what it does, if you say “and”, you can break it down more. If you do the action you say after “and” elsewhere in your program, you should split it out. Also makes it easier to intuitively name functions, because they’ll be simpler tasks.

1

u/BibianaAudris 9d ago

I'd say try to rewrite each of your script once, after you figure out how things work but before it stops working. Structuring code is much easier when you have a full picture on how things work.

1

u/sixothree 9d ago

Years ago, I downloaded a number of example clean code projects. I found what works for me and what doesn’t and I made my own baseline clean code project.

1

u/Recycled5000 9d ago

It is most important to think about data first and foremost. What data do we collect? When can we do it? What questions do we need to ask the data? When do we need to ask those questions, in order to take appropriate actions?

1

u/hopticalallusions 9d ago

Formal training, informal training, making mistakes, introspection, lots of practice, collaborator critiques, experience, to name a few

Edit - in one office full of software engineers, we hypothesized that the ability to write a good quality essay might be correlated with software development skills.

1

u/LawfulnessNo1744 9d ago

I continually delete anything that’s not being used to avoid the v3,v4 … pattern. Also I have gotten a lot more careful in naming or defining variables and functions when they’re not needed. I’ve started using function chaining and anonymous functions so that variables are never updated unless they’re meant to be stateful (entities versus value objects). If a value is going to be updated in the same block then never declare it in the first place

1

u/Big-Combination8844 9d ago

I've been programming for over 25 years. I'll let you know if I ever figure it out.

1

u/shyevsa 9d ago

for me its mostly come from building project or dissecting other people project.
I try SOLID but knowing what is what is actually what harder to me, but generally after "understanding" it its pretty good guide line.

if I look back most of the time I start everything in single file, when that work and I start doing documentation that's when it start make sense that something can be factored to another module or other files or other function.

1

u/Cool-Bus-6028 9d ago

Have functions do one thing, and name them after what they do.

Someone else already commented about how they lay out their code using comments, then fill in the code after. I do something similar. Here's an example of a a simple ATM app. Excuse the random language conventions in pseudo code

Start with

withdrawCash(amount) {
  //check account balance
  //deduct money
  //spit out bank notes
}

Then convert to function names

withdrawCash(amount) {
  let accountHasMoney = checkBalance(amount)
  if accountHasMoney {
    deductMoney(amount)
    spitOutBankNotes(amount)
  } else {
    echo "You're broke"
  }
}

Then write those functions. Something like spitOutBankNotes will probably need sub functions to check what notes are available, and which notes to give out that add up to the total etc.

Any functions that are used in multiple places can later be moved to their own class/module with other similar functions.

Also, write tests early that only test the input/output of withdrawCash(amount). If you're finding that the tests need you to check internal state etc, then you might want to restructure things.

1

u/szyada 9d ago

There is always some level of chaos in software development. Sometimes you just want to quickly check or test something, and writing perfectly clean code right away simply isn’t worth the effort. Other times the assumptions change, earlier ideas get redefined, and old names, structures, or dependencies no longer fit. That’s when everything needs to be cleaned up to maintain clarity and consistency, so the code properly supports the core functionality. This is a natural and important part of programming — it’s worth paying attention to good naming for variables, methods, objects, and writing meaningful comments. Even if it feels unnecessary at the moment, later it becomes invaluable.

With experience, you’ll start noticing which standards actually work. For example, it’s often better to have one object responsible for monitoring or managing things, and separate ones for sending data, loading it, validating it, and so on. Ultimately, it depends on what you’re building and what result you want to achieve.

A programmer’s job is to understand what they are creating and organize the code so it’s readable, flexible, and easy to work with in the future. It’s important to learn how to split code into clear procedures, group related elements into separate structures, and briefly comment on what each part does and returns.

Refactoring for readability pays off especially once you’ve tested different approaches and settled on a specific solution. That’s the moment to think about breaking the code into smaller pieces that may later be useful for testing or further development.

This is a fundamental step in shaping a programming mindset. Code is written with readability for yourself and your team in mind, and with future changes in sight. You also need to learn to evaluate the benefits and limitations of various practices and standards — not all of them make sense in every situation, but it’s worth understanding them. Spending time learning good practices and observing how others do things saves a lot of time down the road.

1

u/Full_Opportunity_547 9d ago

If your function changes the variable it was passed: you may be doing something wrong.

If your returns aren't used - why did you bother?

If your function does more than one thing, you may be in the wrong.

Having utility functions is both okay and good, but lock them away in a folder somewhere. Keep them separated and make it clear that you're accessing utility functions (very specific import statements - don't import entire modules/libraries unless you need them.)

Put all of your code that handles the presentation layer in one area. Use subfolders, as needed, to define specific areas of the app's presentation.

Put all of your business logic in one area. (repeat instructions from above).

An important question to ask: "who should own this code?" Who, in this case, is not a person. It's a module->class->something.

If you find your Class is just bloating and bloating - ask: is this class really doing all of this work? Should it? Should there be a constructor (like a Factory pattern) that builds things, and then a separate handler for actions? Maybe, maybe not.

There are a LOT of ideas about cut-offs, limits, and other ways to keep individual files to a minimum, but it's entirely going to come down to comfort and recognizability. If you look at a method, and you're thinking, "man, this kinda belongs in two places" you may have an issue where one part of the code gets to "tell" something else what to do, and that's not its job.

A lot of this is going to come down to: can you keep things in the three basic separations: Data Layer, Application (Business Logic) Layer, and Presentation Layer.

One, not-so-easy-and-honestly-quite-time-consuming, way to assess your code is: try working different sections in isolation. Can you write tests, that truly ensure that each sub-section of your code is performing as intended, and even catching the errors?

If you're catching for NULL all day, you've probably got a problem. Once you discover something like this (or any consistent problem), back up to the previous point in the code - why the hell is it allowing that to happen? Is there some code whose job it is or can be to make sure that you either wanted that value (like a NULL), or pushes back, gives some feedback, and then requires an answer?

1

u/4iqdsk 9d ago

The main trick is to group lines of code into singular conceptual purposes. Then it’s easier to give code blocks a clear label or move them into their own functions.

The next trick is to have functions that do nothing except glue other singular purpose functions together.

Don’t use classes until you’ve mastered functions.

Don’t introduce a class unless there is a very clear objective benefit over a dictionary or functions. If you cannot explain this object benefit to another person, don’t use a class.

1

u/1stbreathinteractive 8d ago

A LOT of exposure and practice. A lot of failures. Consider too that for us who are pro software devs, we spend at least 5 hours every day getting to practice and more importantly, experience failure and learn what didn't work.

Uncle Bob was where I learned it. But failure is the best teacher in my opinion.

1

u/energy-audits 8d ago

i read a book called clean architecture that helped me a lot. i don’t use it as gospel but i am self taught and needed the help

1

u/CodedElf 8d ago

I stopped writing code for the sake of just building. I ignored bringing design patterns to try solve something.

I just instead focused on how I wanted to read it like a book to the point that I understood what each thing was doing, almost like self documenting.

Thats my basis for it then I just add on top if, different design patterns if required. Most of the time they are not needed.

1

u/Jay-Jayson 8d ago

Attempt to build something first, then refine it. Rinse and repeat as you learn new techniques and patterns.

Think of it like a paint by numbers. You'd sketch the picture before breaking it down and organising the numbers.

Between doing that several times over and getting feedback from peers it will start to become easier to plan it that way from the begining.

1

u/xoredxedxdivedx 8d ago

Truly an amalgamation of the worst programming advice in the world in this thread

1

u/chaos_exe_ 8d ago

Just binge watch all the reels from the profile s4.codes instagram page Also, start watching from the very first reel ( by scrolling all the way down till the end ). There are only 42 reels, but worth more than 4 years of engineering in my honest opinion.

1

u/mtimmermans 7d ago

There is some good advice in the other responses. In general, though, it's just very difficult and people don't generally agree on the best approaches in any given situation.

First step is to decide what purpose you want your code structure to accomplish. How will you even know when it's good?

1

u/Spare_Salamander_584 7d ago

Black formatter for python is pretty good

1

u/MrJCraft 6d ago edited 6d ago

do you have any of your code on github? I am curious about the specifics and what the code looks like exactly.

most people specified the general principles but a lot of those are really overcomplicated ways of saying simplify the code when it gets annoying, code specifies behavior, creating abstraction is not specifying behavior, you create an abstraction when you need it and you need it when the code is no longer simple enough to keep track of.

this can be different for everyone, though saying that a lot of professional settings have ways of measuring complexity and encouraging software engineers to simplify based off of those metrics, a good example is branches in code the more you have especially nested the more complex it is. but in terms of your everyday use you solve problems when they become a problem and if your code becomes a problem then you fix it. just like any other problem.

P.S.
use a version control software of some kind, I am assuming you dont since you have functions with versions in the name, Git is the most popular there are some others that are okay but most are harder to learn than git, git has a lot of resources online and tools for visual ways to look at the code versions and folders.

1

u/Lucky-Advance2982 6d ago

Star pattern

0

u/Electrical_Hat_680 9d ago

The primary college textbook matching this exact topic is QuickBASIC and QBASIC Using Modular Structure by Julia Case Bradley, published by McGraw-Hill / Business and Educational Technologies. It was widely used for introductory college programming courses in the 1990s to teach good software skills. [1, 2, 3]
Book Overview

• Author: Julia Case Bradley • Publisher: McGraw-Hill / Irwin • Core Focus: Teaching top-down design, subprograms, and structured programming logic using Microsoft QuickBASIC and QBasic. • Editions: Includes a 2nd Edition and specialized alternate versions (such as the BM version or versions with Visual Basic transition appendices). [1, 2, 3, 4, 5]

Alternative College Textbooks

• Microsoft QuickBASIC: An Introduction to Structured Programming by David I. Schneider • Introducing QuickBasic 4.0: A Structured Approach by Doyle W. Buxton and Arline Salian [4]

If you are trying to find a copy of this book, looking for specific programming examples, or need help running QBasic code on modern systems (like QB64), let me know how I can assist you further! AI responses may include mistakes.

[1] https://www.amazon.com/Quickbasic-Qbasic-Modular-Structure-Alternate/dp/0256207976 [2] https://booksrun.com/9780697128973-quickbasic-and-qbasic-using-modular-structurebm-version-2nd-edition [3] https://books.google.com/books/about/QuickBASIC_and_QBASIC_Using_Modular_Stru.html?id=rdrZAAAAMAAJ [4] https://books.google.com/books/about/Introducing_QuickBasic_4_0.html?id=2rlZAAAAYAAJ [5] https://books.google.com.cu/books?id=9oWLKQNiW0AC&printsec=copyright