본문 바로가기
프로그래밍/기타

좋은 개발 습관

by W.C. 2024. 11. 20.
728x90

 

 

Good software development habits

Note: This got and got some attention. This post is not advice, it's what's working for me. It's easy to pick up bad habits and hard to create good o...

zarar.dev

 

좋은 개발 습관에 대한 글이 있어서 해당 내용을 번역해서 올린다. 

This post is not advice, it's what's working for me.

It's easy to pick up bad habits and hard to create good ones. Writing down what's working for me helps me maintain any good habits I've worked hard to develop. Here's an unordered list of 10 things that have helped me increase speed and maintain a respectable level of quality in the product I'm currently developing.

이 글은 조언이 아니라 저에게 효과가 있는 습관입니다. 나쁜 습관을 들이기 쉽지만 좋은 습관을 만들기는 어렵습니다. 저에게 효과가 있는 것을 적어두면 열심히 개발한 좋은 습관을 유지하는 데 도움이 됩니다. 다음은 현재 개발 중인 제품의 속도를 높이고 상당한 수준의 품질을 유지하는 데 도움이 된 10가지를 순서 없이 정리한 목록입니다.

 

  1. Keep commits small enough that you wonder if you're taking this "keep commits small" thing a little too far. You just never know when you have to revert a particular change and there's a sense of bliss knowing where you introduced a bug six days ago and only reverting that commit without going through the savagery of merge conflicts. My rule of thumb: compiling software should be commitable.

    커밋을 작게 유지하는 것이 너무 지나친 것은 아닌지 의문이 들 정도로 커밋을 작게 유지하세요. 언제 특정 변경 사항을 되돌릴지 알 수 없고, 6일 전에 버그를 도입하고 병합 충돌의 야만적인 과정을 거치지 않고 해당 커밋만 되돌릴 수 있다면 행복감을 느낄 수 있습니다. 제 경험칙: 소프트웨어 컴파일은 커밋 가능해야 합니다.

  2. Live Kent Beck's holy words of wisdom: "for each desired change, make the change easy (warning: this may be hard), then make the easy change". Aim for at least half of all commits to be refactorings. Continuous refactoring is thinking of changes I can make in under 10 minutes that improve something. Doing this pays off whenever a bigger requirement comes in and you find yourself making a small change to satisfy it only because of those smaller improvements. Big refactorings are a bad idea.

    켄트 벡의 거룩한 지혜의 말씀을 실천하세요: "원하는 변경이 있을 때마다 쉽게 변경한 다음(경고: 어려울 수 있음), 쉬운 변경을 하세요." 모든 커밋의 절반 이상을 리팩터링하는 것을 목표로 하세요. 지속적인 리팩터링은 10분 이내에 무언가를 개선할 수 있는 변경 사항을 생각하는 것입니다. 이렇게 하면 더 큰 요구 사항이 들어왔을 때 그 작은 개선으로 인해 그 요구 사항을 충족하기 위해 작은 변경을 할 때마다 성과를 거둘 수 있습니다. 대규모 리팩터링은 나쁜 생각입니다.


  3. All code is a liability. Undeployed code is the grim reaper of liabilities. I need to know if it works or at least doesn't break anything. Tests give you confidence, production gives you approval. The hosting costs might rack up a little with so many deploys but it's a small price to pay for knowing the last thing you did was a true sign of progression. Working software is the primary measure of progress, says one of the agile principles. Working and progress are doing a lot of heavy lifting in that sentence, so I've defined them for myself. Working is something being working enough to be deployed, and if it's code that's contributing to a capability, that's progress.

    모든 코드는 책임입니다. 배포되지 않은 코드는 책임의 저승사자입니다. 제대로 작동하는지, 적어도 망가뜨리지는 않는지 알아야 합니다. 테스트를 통해 자신감을 얻고, 프로덕션을 통해 승인을 받아야 합니다. 배포 횟수가 많으면 호스팅 비용이 약간 증가할 수 있지만 마지막으로 수행한 작업이 진정한 발전의 신호라는 것을 알기 위해 지불할 수 있는 작은 대가입니다. 애자일 원칙 중 하나는 작동 중인 소프트웨어가 발전의 주요 척도라고 말합니다. 이 문장에서 작업과 진행은 많은 의미를 내포하고 있기 때문에 제가 직접 정의해 보았습니다. 작업은 배포할 수 있을 만큼 충분히 작동하는 것이고, 기능에 기여하는 코드라면 진전이라고 할 수 있습니다.


  4. Know when you're testing the framework's capability. If you are, don't do it. The framework is already tested by people who know a lot more than you, and you have to trust them that the useState() hook does what it's supposed to do. If you keep components small, then you reduce the need for a lot of tests as the framework will be doing most of the heavy lifting in the component. If the component is big, then you introduce more complexity and now you need to write a lot of tests.

    프레임워크의 기능을 테스트할 때를 파악하세요. 테스트하고 있다면 하지 마세요. 프레임워크는 이미 여러분보다 훨씬 더 많은 것을 알고 있는 사람들에 의해 테스트되었으며, 여러분은 사용State() 훅이 해야 할 일을 한다는 것을 믿어야 합니다. 컴포넌트를 작게 유지하면 프레임워크가 컴포넌트에서 대부분의 무거운 작업을 수행하므로 많은 테스트의 필요성을 줄일 수 있습니다. 컴포넌트가 크면 더 복잡해져서 많은 테스트를 작성해야 합니다.


  5. If a particular function doesn't fit anywhere, create a new module (or class or component) for it and you'll find a home for it later. It's better to create a new independent construct than to jam it into an existing module where you know deep down it doesn't make sense. Worst comes to worst, it lives as an independent module which isn't too bad anyway.

    특정 함수가 어디에도 적합하지 않은 경우 해당 함수를 위한 새 모듈(또는 클래스 또는 컴포넌트)을 만들면 나중에 해당 함수를 위한 집을 찾을 수 있습니다. 의미가 없다는 것을 뻔히 알면서도 기존 모듈에 끼워 넣는 것보다 새로운 독립적인 구조를 만드는 것이 더 낫습니다. 최악의 경우 독립된 모듈로 존재하는 것도 나쁘지 않습니다.


  6. If you don't know what an API should look like, write the tests first as it'll force you to think of the "customer" which in this case is you. You'll invariably discover cases that you would not have thought of if you had just written the code first and tests after. You don't have to be religious about TDD and it's OK to work in larger batches (e.g., write more than just a couple lines of code before making it pass). The amount of code to write in a red/failing state doesn't always have to be small. You know what you're doing, don't let dogma get in the way of productivity.

    API가 어떤 모습이어야 할지 모른다면 테스트를 먼저 작성하면 '고객'(이 경우에는 사용자)을 생각하게 될 것입니다. 코드를 먼저 작성하고 테스트를 나중에 작성했다면 생각하지 못했을 경우를 항상 발견하게 될 것입니다. TDD를 고집할 필요는 없으며 더 큰 배치로 작업해도 괜찮습니다(예: 통과하기 전에 몇 줄 이상의 코드를 작성하는 것). 합격/불합격 상태로 작성하는 코드의 양이 항상 적을 필요는 없습니다. 자신이 무엇을 하고 있는지 잘 알고 있으므로 도그마가 생산성을 방해하지 않도록 하세요.


  7. Copy-paste is OK once. The second time you're introducing duplication (i.e., three copies), don't. You should have enough data points to create a good enough abstraction. The risk of diverging implementations of the same thing is too high at this point, and consolidation is needed. It's better to have some wonky parameterization than it is to have multiple implementations of nearly the same thing. Improving the parameters will be easier than to consolidate four different implementations if this situation comes up again.

    복사-붙여넣기는 한 번만 해도 괜찮습니다. 두 번째로 복제를 도입하는 경우(예: 복사본 세 개)에는 하지 마세요. 충분히 좋은 추상화를 만들 수 있을 만큼 충분한 데이터 포인트가 있어야 합니다. 현재로서는 동일한 것을 서로 다르게 구현할 위험이 너무 높으므로 통합이 필요합니다. 거의 동일한 것을 여러 개 구현하는 것보다 약간의 불안정한 매개변수화가 있는 것이 낫습니다. 이런 상황이 다시 발생할 경우 네 개의 서로 다른 구현을 통합하는 것보다 파라미터를 개선하는 것이 더 쉬울 것입니다.


  8. Designs get stale. You can slow the rate at which they get stale by refactoring, but ultimately you'll need to change how things work. Don't feel too bad about moving away from something that was dear to you a while ago and something you felt proud about at the time. You did the right thing then and shouldn't beat yourself up for not getting it right enough that you wouldn't need to change anything. Most of the time writing software is changing software. Just accept it and move on. There's no such thing as the perfect design, and change is at the core of software development. How good you are at changing things is how good you are at software development.

    디자인은 오래되면 낡아집니다. 리팩터링을 통해 진부해지는 속도를 늦출 수는 있지만 궁극적으로는 작동 방식을 바꿔야 합니다. 얼마 전에 소중하게 여겼던 것, 당시에는 자부심을 느꼈던 것에서 멀어지는 것에 대해 너무 안타까워하지 마세요. 그때는 옳은 일을 한 것이므로 아무것도 바꿀 필요가 없을 만큼 제대로 하지 못했다고 자책할 필요는 없습니다. 대부분의 경우 소프트웨어를 작성하는 것은 소프트웨어를 바꾸는 일입니다. 그냥 받아들이고 계속 진행하세요. 완벽한 디자인이란 존재하지 않으며, 변화는 소프트웨어 개발의 핵심입니다. 변화에 얼마나 능숙한지가 곧 소프트웨어 개발의 실력이 됩니다.


  9. Technical debt can be classified into three main types: 1) things that are preventing you from doing stuff now, 2) things that will prevent you from doing stuff later, and 3) things that might prevent you from doing stuff later. Every other classification is a subset of these three. Minimize having lots of stuff in #1 and try to focus on #2. Ignore #3.

    기술 부채는 크게 세 가지 유형으로 분류할 수 있습니다: 1) 현재 작업을 방해하고 있는 것, 2) 나중에 작업을 방해할 것, 3) 나중에 작업을 방해할 수 있는 것입니다. 다른 모든 분류는 이 세 가지의 하위 집합입니다. 1번 항목에 많은 항목을 넣는 것을 최소화하고 2번 항목에 집중하세요. 3번은 무시하세요.


  10. Testability is correlated with good design. Something not being easily testable hints that the design needs to be changed. Sometimes that design is your test design. As an example, if you find yourself finding it difficult to mock em.getRepository(User).findOneOrFail({id}), then chances are you either need to put that call into its own function that can be mocked, or write a test utility which allows for easier mocking of the entity manager methods. Tests go unwritten when it's hard to test, not because you don't want to test.

    테스트 가능성은 좋은 디자인과 상관관계가 있습니다. 테스트가 쉽지 않다는 것은 디자인을 변경해야 한다는 것을 암시합니다. 때로는 그 디자인이 바로 테스트 디자인일 수도 있습니다. 예를 들어 em.getRepository(User).findOneOrFail({id})을 모킹하기 어렵다면 해당 호출을 모킹할 수 있는 자체 함수에 넣거나 엔티티 관리자 메서드를 더 쉽게 모킹할 수 있는 테스트 유틸리티를 작성해야 할 수도 있습니다. 테스트하기 어려울 때 테스트를 작성하지 않는 것이지, 테스트하고 싶지 않아서 테스트를 작성하지 않는 것은 아닙니다.