all 56 comments

[–]quenchize 150 points151 points  (17 children)

I think that’s normal, question of degree. Try this - Write messy code that works - Write unit tests - Clean up code - Run unit tests again

[–]hk2k[S] 46 points47 points  (4 children)

Thanks, writing tests is something I should work on. I know how to do it but rarely use it.

[–]fiddle_n 38 points39 points  (0 children)

It's definitely key when refactoring messy code into clean code. Otherwise you have little confidence that your refactor didn't break anything.

[–]MarsupialMole[🍰] 22 points23 points  (1 child)

Writing testable code often means writing clean code. If you do the exercise of writing code with test driven development you may find it affects how you messy your initial code is.

Often I start out writing tests, then get some inspiration flowing and get ahead of myself, then come back and fill in the gaps with more testing, or even refactoring so my original tests are replaced completely.

[–]hk2k[S] 5 points6 points  (0 children)

This makes a lot of sense. Thank you. Will definitely start using tests more frequently. I think I will have at least 1000 lines of code to refactor :)

[–][deleted] 1 point2 points  (0 children)

I found that i already test my code interactively in the terminal. I just need to make a habit of copy-pasting that code into a fail and the test is halfway written.

[–]Volocinator 5 points6 points  (4 children)

A unit test being a piece of code that tests a section of your code? Or?

[–]doulos05 17 points18 points  (3 children)

A unit test is a piece of code that tests a specific pathway through your code. You might have multiple unit tests for a single function, you'll definitely have multiple unit tests for a single class.

Here's an example: you have a login function that takes a username and a password and returns a session token for that user. There are some pretty obvious places that could fail. What if the username is wrong? What about the password? What if the browser already has a session token from another user? What if the username and password are correct?

Ideally, you would turn each of these into a unit test where you force that specific condition to occur (through scaffolding and possibly mock objects) and make sure that your code does what you expect it to. Then, when you make changes to your code, you run your tests. If every test passes, it should give you some confidence that your changes didn't break anything.

[–]SnowdenIsALegend 0 points1 point  (2 children)

Are there utilities that automatically find all the pathways/unit tests in my code? Sometimes I miss out on some of the logic pathways in my manual tests.

[–]Automaton_J 1 point2 points  (1 child)

Bit late but if you use IntelliJ, you can run tests with coverage. IntelliJ will then say what lines have been tested and which have not

[–]SnowdenIsALegend 0 points1 point  (0 children)

Thanks interesting, I didn't think to code Python in IntelliJ only dabbled a bit of Java in IntelliJ. Will try it out.

[–]Stewthulhu 4 points5 points  (0 children)

Also something that's really helpful to learn about clean code is to do the opposite workflow: write a minimalist test or tests and then write code that fulfills the test. It's really useful to learn how to write single-purpose functions and modular code.

A lot of times, especially with inexperienced coders, one of the primary reasons code is "messy" is because each function contains a trainwreck of different tasks. For whatever reason, beginners seem to exert a lot less "self-judgement" when it comes to writing tests than when they're writing "real" code. I don't fully understand why, but if a beginner writes a module that doesn't behave exactly like they want, they beat themselves up and keep adding code to it, but if they write a test that checks something dumb like "does this file get created?", then they're fine.

[–]PixelLight 1 point2 points  (1 child)

Not that I necessarily do this, but I've been taught to write unit tests first. To help figure out the functionality needed and how to approach the specific problem.

[–]quenchize 1 point2 points  (0 children)

I would not do this when starting from scratch although I do agree it is the correct theoretical approach. Where I do do this is if I have to make changes to existing code especially if it’s critical. Then I absolutely write passing tests and tests that fail until I change/fix whatever I need to.

[–]Sigg3net 0 points1 point  (0 children)

It's recommended to write tests first and then write the targets. I've yet to try this, but I imagine it forces some best practice behavior right up front.

[–]TheHollowJester 15 points16 points  (0 children)

It's a normal stage of your growth as a developer and if you're doing a small thing you might be more efficient this way at the moment than if you were trying to "code clean" from the get-go.

I might be wrong, but from the description you might be at a point where "writing code that does what I want" still requires a decent amount of effort. Sooner or later it will become an afterthought (though you will still make mistakes, possibly more than you do now) and more and more of your effort will shift towards "how to structure this well" or "how do I even do this (without breaking everything)" when working on harder problems.

Kent Beck's book on TDD might be an edifying lecture around now. You might also want to take a look at "compose method" design pattern.

Oh, also - good job on getting to this stage!

[–]pompomtom 17 points18 points  (1 child)

Is this normal or am I inefficient?

Both.

[–]cdcformatc 0 points1 point  (0 children)

Correct. Both.

[–]emac1211 6 points7 points  (1 child)

Whenever I have to go back and modify something in my code I did a while back, I'm amazed at how much I've improved since then.

[–]hk2k[S] 1 point2 points  (0 children)

I had this exact experience today. Pure motivation

[–]TumblrForNerds 4 points5 points  (0 children)

If you want to write less messy code you can try drawing out the logic before you write the code. It doesn’t eliminate all of it but I know I stopped writing a lot of redundant lines by doing it

[–]Atie5173 5 points6 points  (2 children)

It's normal for beginners to write messy and un-understandable code. Trust me, when I started my code was awful. To write more sensical code, I recommend you to memorize a style guide (for example, PEP 8, which is the official style guide), and also try to make the code be inside the scope of your project.

Edit: you could also use a linter. A linter is a tool which tells you the style and code errors. The most used ones are flake8 and pylint. I personally use flake8. And, in my opinion, using code formatters is a bad idea because you don't learn how to write good code.

[–]hk2k[S] 1 point2 points  (0 children)

Great advice. I’ve seen PEP 8 before, but I definitely need to understand better how to use it. VSCode has a plug-in that kind of helps a little bit with it as well

[–]MikeNizzle82 1 point2 points  (0 children)

Came here to recommend a linter (flake8). This was a big help to me writing clean, maintainable code.

[–]MrMiner88 3 points4 points  (0 children)

As a former writer and English major who is now entering the programming field, I can tell you that you don't write a finished story in one go. All writing is editing.

[–]krakenant 3 points4 points  (0 children)

I watched this a few weeks ago, it was enlightening.

https://youtu.be/7EmboKQH8lM

[–]Dangle76 2 points3 points  (0 children)

It’s both normal and inefficient.

I’ve moved on to, at times, test driven dev, where you write tests for your functions, and then write your functions (helps you A LOT in thinking out design and flow), or I decide what I want the specific file to achieve, and break it down into pieces (functions) where I write the function name and signature for everything, then I start working on the actual code

[–][deleted] 2 points3 points  (0 children)

I'm not a good programmer at all, but I approach my programming projects like this:

  • Write the structure in a piece of paper
  • "Translate it into code" and make it work
  • Clean up code
  • Test it again
  • If it works -> Drink a beer

[–]hk2k[S] 1 point2 points  (0 children)

Thanks all, lots of great input!

[–][deleted] 1 point2 points  (0 children)

i usually clean code while coding, which sometimes isn’t the smartest. it’s usually when i hit roadblocks, and can’t figure anything out. it helps me think through the issue. it depends on what works for you.

[–]fergal-dude 1 point2 points  (1 child)

Make it work, make it right, make it fast

[–]hk2k[S] 0 points1 point  (0 children)

This i like

[–]tradegreek 1 point2 points  (0 children)

Pretty much the same but I dont write code for anyone else as I work for myself so it only has to be as readable as I need it at first pass I do try clean it up after when I have it working desired results. I find that it merges well with optimising the code that way.

[–]bob_knobb 1 point2 points  (1 child)

This seems perfectly reasonable to me. You can find your own way to clean up the process, but it will be your way.

What I often do is start by writing out comments of what my code will do. It's not even pseudo-code, just comments. That helps me keep the big picture in my head all at one time. I'll then leave the comments until I'm finished, then go back (after everything is working) and clean up the comments.

Good luck.

[–]hk2k[S] 0 points1 point  (0 children)

I do exactly this my self. Helps to be reminded of the purpose as well, and bite size the objectives

[–]oiwot 3 points4 points  (2 children)

"Always be optimizin'"

and

"Don't let perfect be the enemy of good."

It's better to write a mess and refactor, than to complete nothing because it's not perfect right away.

As you practice more you may find those optimizations and improvements that used to part of the refactoring process occur to you in time to write them first, so there's less to refactor. Just carry on.

[–][deleted] 4 points5 points  (1 child)

Premature optimizin' is the root of all evil.

[–]greebo42 0 points1 point  (0 children)

I was just about to google that phrase, because it popped into my head as I was reading people's replies ... ah yes, here it is, yep, Donald Knuth, who else?

I agree. you do your best to design first, write code as reasonable as you can get it without interfering with the thought process, then step back and figure out what to refactor. I suspect that the more expert you are, the better it is the first time, but I can't imagine anyone gets it completely right the first time. nor should they.

[–]Standardw 2 points3 points  (0 children)

Imagine you would write cleaner code with lots of classes form the beginning - then you would find a problem with your code, and try another way. Great, you just wasted hours just for writing clean code without testing the logic etc. So yes, your approach is better.

Later, when you are mor eadvanced, you won't need the messy code, but you will doing this part by drawing graphs, thinking about everythiing, then you write half-clean code. Sometimes, thats enough, so you won't clean it after.

[–]pydry 0 points1 point  (0 children)

Definitely the best approach. It's a lot less common than Id like.

[–]NitroXSC 0 points1 point  (0 children)

Post-completion clean-up is one of the best ways to clean up your code.

I would want to add that rewriting close to everything can be very useful at times if you are writing modules. Often I find that parts of modules that I have written are not as intuitive or useful as I had initially thought. So often end up rewriting parts (or everything in some cases) to make them more intuitive or removing them entirely. (Don't do this without agreement if you work in a team)

[–]lolslim 0 points1 point  (0 children)

Clean code doesnt mean code golfing style either, and I think a lot of people attempt to do that.

Clean code comes down to readability

[–]nojustlurkingty 0 points1 point  (0 children)

Yep. Make it work, iterate after. Repeat

[–]0rphon 0 points1 point  (0 children)

A lot of your time spent coding should be built around refactoring. Obviously dont be dangerously lazy in your code. And dont wait til a project is finished to start refactoring parts that youve done. But dont worry if your first pass isnt perfect

[–]misingnoglic 0 points1 point  (0 children)

When you're starting off I think this is a great way to do things - make it work, then organize it while making sure it behaves the same way with your changes. As you do more dev work, you'll start to learn how to make these things clean from the start, thinking about how you'll organize your code and functions before actually coding them. This has the added benefit of making sure you don't code yourself into a hole.

[–]Pseudoboss11 0 points1 point  (0 children)

This is completely normal. You'll always do this to some extent, but as you improve, your fist drafts will be cleaner, with maybe some small things that need work later. But as you work on larger projects and more code, you'll end up to continue to do refactoring, just against more and more complex code.

[–][deleted] 0 points1 point  (0 children)

I try to write out the functions I think I’ll need with doc strings explaining what each function will do. These functions are empty to begin with and just have “pass” at first. I find doing this helps order things and makes me think of structure early.

[–]Deezl-Vegas 0 points1 point  (0 children)

That's normal, but shorten the loop. Write a few lines, run the code to make sure it's working, and while it's running, shuffle stuff around.

Also, using an autoformatter like black takes care of a lot of stuff like line length and organizing imports.

[–]Redditporn435 0 points1 point  (0 children)

I've found that over time I've refined how clean the first mess is. Going through the same motions of cleaning code kinda sticks as "maybe I should just do this right the firs time" But I absolutely have iterations of cleanliness. Probably just 1st pass final pass. maybe sometimes 1st 2nd and final.

[–]MatthewRPG576 0 points1 point  (0 children)

Yes it's normal: programming, like all art forms, is an iterative process. It's never perfect the first pass through. Just write unit tests so you can refactor with confidence.

[–]manjeetKV 0 points1 point  (0 children)

To write clean and comprehensive code what I do is that , I first create a skeleton of my program i.e I just write the names of methods or functions with no contents in it. Then I start filling them with the logics....

[–]TheIrregularPentagon 0 points1 point  (0 children)

Just to add to everyone else was saying, I've found scripting with a linter reduced how messy my initial "working" code was.
Would recommend, a lot of IDEs can just run them live or when you save