TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Good Software Development Habits

364 点作者 mmphosis6 个月前

30 条评论

leetrout6 个月前
&gt; It&#x27;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.<p>Hard disagree. If you cant decompose to avoid &quot;wonky parameters&quot; then keep them separate. Big smell is boolean flags (avoid altogether when you can) and more than one enum parameter.<p>IME &quot;heavy&quot; function signatures are always making things harder to maintain.
评论 #42168888 未加载
评论 #42166363 未加载
评论 #42165868 未加载
评论 #42166370 未加载
评论 #42169453 未加载
评论 #42171152 未加载
评论 #42165902 未加载
评论 #42167534 未加载
评论 #42167823 未加载
评论 #42166217 未加载
评论 #42166579 未加载
评论 #42168489 未加载
评论 #42168263 未加载
评论 #42166004 未加载
评论 #42169755 未加载
评论 #42166774 未加载
评论 #42167282 未加载
G1N6 个月前
&gt; Copy-paste is OK once. The second time you&#x27;re introducing duplication (i.e., three copies), don&#x27;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&#x27;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.<p>The more I do this software engineering thing the more I feel like this “advice” bites me in the butt. Understanding when you should duplicate code versus when you should consolidate (or if you should just write a TODO saying “determine if this should be split up by [some set in stone timeline]”) is simply just a HARD problem (sometimes at least), and we should treat it as such.<p>DRY&#x2F; WET or whatever shouldn’t be a maxim (let alone a habit! lol), it should at best be a hand-wavey 2-bit dismissal you give an annoyingly persistent junior software dev who you don’t want to actually help!
评论 #42167673 未加载
layer86 个月前
&gt; Copy-paste is OK once. The second time you&#x27;re introducing duplication (i.e., three copies), don&#x27;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.<p>This heavily depends on how likely it is for the reasons of change to also apply to the other copies. If the reasons for why the code is the way it is are likely to evolve differently for the different copies, then it’s better to just leave them as copies.<p>Just being the same code initially is not a sufficient reason to create an abstraction. Don’t focus on the fact that the code is currently the same, instead focus on whether a change in one copy would necessarily prompt the same change in the other copy.<p>This also applies to pieces of code that are different from the beginning, but are likely to have to change in conjunction, because they rely on shared or mutual assumptions. If possible place those pieces of code next to each other, and maybe add a source comment about the relevant mutual assumptions.<p>In other words, avoiding code duplication is a non-goal. Keeping code together that needs to evolve together is a goal. Instead of DRY or WET (don’t repeat yourself, write everything twice), think SPOT (single point of truth).
评论 #42167993 未加载
评论 #42167981 未加载
simonw6 个月前
&quot;Know when you&#x27;re testing the framework&#x27;s capability. If you are, don&#x27;t do it.&quot;<p>Hard disagree on that. Frameworks change over time. How certain are you that they won&#x27;t make a seemingly tiny design decision in the future that breaks your software?<p>One of the most valuable things tests can do for you is to confirm that it is safe to upgrade your dependencies.<p>If all your test does is duplicate tests from dependency that might be a waste of time... provided that&#x27;s a stable, documented feature and not something that just happens to work but isn&#x27;t necessarily expected stable behavior.<p>But you shouldn&#x27;t skip testing something because you&#x27;re confident that the dependency has already covered that.<p>The tests should prove your software still works.
评论 #42167793 未加载
评论 #42167251 未加载
评论 #42168677 未加载
vander_elst6 个月前
&gt; It&#x27;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.<p>From <a href="https:&#x2F;&#x2F;go-proverbs.github.io&#x2F;" rel="nofollow">https:&#x2F;&#x2F;go-proverbs.github.io&#x2F;</a>: A little copying is better than a little dependency.<p>Curious to see how the community is divided on this, I think I&#x27;m more leaning towards the single implementation side.
评论 #42166264 未加载
评论 #42165963 未加载
评论 #42169200 未加载
评论 #42166107 未加载
simonw6 个月前
On commit size:<p>&gt; You just never know when you have to revert a particular change and there&#x27;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.<p>This is key for me: a good shape to aim for with a commit is one that can be easily reverted.
评论 #42166356 未加载
评论 #42165815 未加载
评论 #42166417 未加载
评论 #42166824 未加载
评论 #42166427 未加载
评论 #42167574 未加载
评论 #42167218 未加载
Barrin926 个月前
Pretty substantial disagree with the second half of 4. and 5.<p>&gt;If the component is big, then you introduce more complexity[...] If a particular function doesn&#x27;t fit anywhere, create a new module (or class or component)<p>This smells like the agile&#x2F;uncle Bob &quot;every function should be four lines&quot; school of thought which is really bad.<p>Paraphrasing Ousterhout&#x27;s book, it&#x27;s the other way around, when components are big and contain significant implementation you&#x27;re <i>hiding information</i> and reducing complexity, which is the purpose of good program design. When your component&#x2F;object&#x2F;module is just surface you&#x27;ve basically done no work for whoever uses your code. I see it way too often that people write components that are just thin wrappers around some library function in which case you haven&#x27;t created an abstraction, you&#x27;ve just added a level of indirection.<p>If a function does not fit anywhere that&#x27;s a strong indication that it shouldn&#x27;t be a separate function, it&#x27;s likely an implementation detail.
评论 #42168099 未加载
vrnvu6 个月前
“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.”<p>How many times have you had to roll back a minor version upgrade because the library maintainers *absolutely don’t* know what they are doing? Spring, Netty, and Java ecosystem, I&#x27;m looking at you...
评论 #42167716 未加载
lifeisstillgood6 个月前
There is this dichotomy - companies say they want stable codebase with clear justifications for each chnage (at least heavily regulated companies do).<p>But good practise here is continual refactoring - almost inimicable to that stability plus imagine the final sign off comes from business who don’t understand why you rewrote a codebase that they signed off two months ago and now have to re-confirm
atoav6 个月前
Software development is simple, try to maximize all of these at the same time:<p>1. Performance<p>2. Reliability<p>3. Readability<p>4. Correctness<p>5. Maintainability<p>6. Extendability<p>7. Consistency<p>8. Adequacy<p>9. Simplicity<p>10. Predictability
评论 #42167010 未加载
评论 #42169725 未加载
评论 #42170204 未加载
tegiddrone6 个月前
&gt; 5. If a particular function doesn&#x27;t fit anywhere, create a new module (or class or component) for it and you&#x27;ll find a home for it later.<p>I worked at a place that did this with their frontend app. Devs rarely knew where anything should go and so for any given Component&#x2F;Module, there was usually some accompanying `MyComponent.fns.ts` file. Homes were NEVER found for it later. Code duplication through the nose and lots of spaghetti coupling.<p>Edit: i&#x27;m definitely blowing off some steam. That said, I think there is good virtue in this &quot;habit&quot; so long as there is good reason that it &quot;doesn&#x27;t fit anywhere&quot; ... and when another module starts referencing the temporary home module, it is a smell that the time is now to give it a proper home.
评论 #42168380 未加载
评论 #42170223 未加载
评论 #42168425 未加载
marginalia_nu6 个月前
I don&#x27;t think these points are well justified. They&#x27;re all on the format &quot;do this or a bad thing will happen&quot;, where often it&#x27;s not obviously clear why the supposed bad thing is bad.<p>1. The alternative to small commits (as motivated by the difficulty in reverting large commits) is to not revert the commit, but just add a new commit that fixes the bug. The merits of this is of course debatable, but it does consitute a gap in the reasoning.<p>2. &quot;Big refactorings are a bad idea&quot;, why though?<p>5. &quot;It&#x27;s better to create a new independent construct than to jam it into an existing module where you know deep down it doesn&#x27;t make sense&quot;, why though?<p>6. As a counter point to designing an API via unit tests, you can also just have a design session. Think about the problem for a moment, write some design documents down. When dealing with APIs and interfaces, database schemas, this type of up-front design tends to deal by far the best results.<p>7. There&#x27;s no clear argument why having more than two instances of a function is bad. Yeah implementations may diverge, but is that necessarily a bad thing? Even if they started out the same, why do they need to keeps staying the same?<p>10. &quot;Testability is correlated with good design&quot; is not really motivated at all. I know many designs that are good but not easily testable, and many designs that are extremely testable, but also hideously convoluted (e.g. &quot;uncle bob&#x27;s syndrome&quot;).
评论 #42168642 未加载
rtpg6 个月前
&gt; 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.<p>I have struggled a bit with this at times. There are certain things that can go from &quot;this implementation fits on a postcard&quot; to &quot;this implementation fits on 3-4 pages&quot; if you want to provide the introspection required to provide useful tests (less true in languages like Haskell that provide nice monadic tricks, granted). I like having tests just to prove the point, but I will feel quite bad ripping up _tiny_ implementations to get tests working.<p>But test code is also code that should be introspected in a certain way (though the objectives are different). Maybe I&#x27;m just doing some things the wrong way.
Scubabear686 个月前
“Aim for at least half of all commits to be refactorings”.<p>I feel like this is the end game of scrum and most agile methodologies - endless refactoring on a treadmill with no off button,<p>I like to be introspective, and I am human so my code is far from perfect. But if I was refactoring half of my time I would go more than a little crazy.<p>The good systems I have worked on have converged on designs that work for that space. Both developers and users see and value the stability.<p>The bad ones have had the kind of churn the article mentions. Developers are constantly rewriting, functionality is subtly changing all the time; stability doesn’t exist.
deterministic6 个月前
I mostly agree. One thing to add:<p>Your tests should test the API of the code&#x2F;module&#x2F;system you are responsible for. Nothing else.<p>And the tests should <i>really</i> push your API to the limit and beyond. For example, if your API is a server (with a HTTP API) then have N clients try to use it at the same time, as fast as possible, and see what happens.<p>And of course measure memory usage, disk usage etc. while running these tests continuously for days.<p>This will automatically test everything you depend on. And you will know instantly of any of the dependencies you rely on have changed in a way that impacts your code.<p>I have had zero (yes zero) bugs in production for years. Only because of tests that really push the servers I am responsible for <i>hard</i>. Way harder than any customers would.<p>While the tests often reveal that I am very capable of adding bugs to the code :)<p>The systems I typically work on are large C++ applications used by large international companies you most likely have heard about.
javajosh6 个月前
<i>&gt;If a particular function doesn&#x27;t fit anywhere, create a new module (or class or component) for it and you&#x27;ll find a home for it later. It&#x27;s better to create a new independent construct than to jam it into an existing module where you know deep down it doesn&#x27;t make sense. Worst comes to worst, it lives as an independent module which isn&#x27;t too bad anyway.</i><p>Innocuous and fine I guess but it points to (and then ignores) a deeper and interesting issue around how codebases grow, split, and merge over time. When the same thing happens at several levels of abstraction&#x2F;zoom, take note. Refactoring to extract a method is similar to splitting a package is similar to splitting a monolith into microservices (and the reverse operations). The creation of a new package&#x2F;module&#x2F;whatever is an early signal of a &quot;fault line&quot; around which a future refactoring will occur (or, more often than not, a signal that the dev may not be familiar with where things go - but even in this case I tend to agree with the OP to just put it in a new place and let the code review fix it.)
sgarland6 个月前
&gt; [ignore] things that might prevent you from doing stuff later.<p>This only works if you know what is and is not a potential future blocker. A perfect example is the data model: IME, most devs do not understand RDBMS very well, and so don’t understand how their decisions will affect future changes or growth. Or worse, they recognize that they don’t know, but choose to dump everything into a JSON column to avoid migrations.
normie30006 个月前
Alternative to #10: avoid mocking.
评论 #42166862 未加载
majorbugger6 个月前
I don&#x27;t get the part about the small commits. To me a commit could be massive and that&#x27;s alright, provided it introduces some major feature, while a fix could a one-liner. It really depends on the situation.
评论 #42167335 未加载
评论 #42167320 未加载
评论 #42167213 未加载
评论 #42167418 未加载
brigandish6 个月前
&gt; If you don&#x27;t know what an API should look like, write the tests first as it&#x27;ll force you to think of the &quot;customer&quot; which in this case is you.<p>The other way to do this (or if writing tests isn&#x27;t helping) is to start with writing examples in the README (or wherever it is you keep docs). If your examples look tortured then your API is torturous. If your examples are understandable then your API is probably laid out reasonably.
zombiwoof6 个月前
Seems like the definition here of software is always “maintenance” of something as is, like replacing the boards on Theseus<p>Sometimes software is hard and 10x engineers just need to rewrite the whole thing or replace large systems<p>To subscribe to some world where we have to do that in “small changes” limits us<p>We shouldn’t make process to the weakest engineers
评论 #42166367 未加载
评论 #42167411 未加载
评论 #42167508 未加载
评论 #42174018 未加载
评论 #42167881 未加载
评论 #42166537 未加载
avg_dev6 个月前
i do think these are good habits. my favorite is the one about type #3 of tech debt. i wish i could push a button and impart this way of thinking to many of my old coworkers.<p>(and, there is some room for taste&#x2F;interpretation&#x2F;etc. i think the thing about copy-paste and &quot;the third time it&#x27;s in the code, encapsulate it, and deal with flag params later&quot; is maybe true and maybe not true and may be context or team dependent. i know i have done this a few times and if i am trying to cover that func with tests, the complexity of the test goes up fast with the number of flags. and then sometimes i wonder it is even worth writing these tests when the logic is so dead simple.)
chipdart6 个月前
From the article:<p>&gt; Copy-paste is OK once. The second time you&#x27;re introducing duplication (i.e., three copies), don&#x27;t. You should have enough data points to create a good enough abstraction.<p>There&#x27;s already a principle that synthesizes this: Write Everything Twice (WET).<p>It&#x27;s a play on words to counter the infamous Don&#x27;t Repeat Yourself (DRY) principle, which clueless but opinionated developers everywhere have used time and again to justify introducing all kinds of problems involving a combination of tight-coupling unrelated code, abstraction hell, adding three classes and an interface to avoid writing two classes, etc. This nonsense is avoided by tolerating duplicate but uncoupled code until the real abstraction and coupling needs emerge.<p>I still cringe at a PR that a former clueless junior developer posted, where in the name of DRY added a OnFailure handler which, instead of doing any error-handling and recovery logic, simply invoked OnSuccess, because &quot;it&#x27;s mostly duplicate code and this keeps the code DRY&quot;. Utter nonsense.
kolja0056 个月前
Unrelated but does anyone have any recommendations for good resources on learning how to write tests&#x2F;testable software?
hackable_sand6 个月前
Good software development habit: develop good software.
revskill6 个月前
Good code is an asset.
henning6 个月前
No.<p>&gt; Know when you&#x27;re testing the framework&#x27;s capability. If you are, don&#x27;t do it<p>Except that many frameworks are full of confusing behavior that is easy to misuse. It&#x27;s funny that the post mentions `useEffect()` because `useEffect()` is so easy to misuse. Writing integration tests that make sure your app does what it is supposed to is totally fine.<p>&gt; If you don&#x27;t know what an API should look like, write the tests first as it&#x27;ll force you to think of the &quot;customer&quot; which in this case is you<p>This is pointless. It doesn&#x27;t give you any information, you&#x27;re just guessing at what the API should look like. You won&#x27;t actually know until it&#x27;s integrated into a working application. The idea that you can design in a vacuum like this is wishful thinking.<p>&gt; Copy-paste is OK once. The second time you&#x27;re introducing duplication (i.e., three copies), don&#x27;t. You should have enough data points to create a good enough abstraction.<p>No you won&#x27;t, and it will often be with code that is similar in some ways but differs in others. Since the kind of people who write this kind of vague bullshit advice disapprove of things like boolean function parameters and use shitty languages that don&#x27;t have metaprogramming support, this leads to &quot;abstractions&quot; that create awkward, tight coupling where changing one little thing breaks a million stupid fucking unit tests.<p>&gt; Testability is correlated with good design. Something not being easily testable hints that the design needs to be changed.<p>Testability is neither necessary nor sufficient for any particular quality attribute. Depending on the application being written, it can be counterproductive to write out full unit tests for everything.<p>As always with these stupid &quot;software engineering&quot; posts, there is zero data, zero evidence, zero definitions of terms up front, and zero of anything that is actually real. It&#x27;s just personal preference, making it dogma.
评论 #42167554 未加载
danesparza6 个月前
&quot;Technical debt can be classified into three main types&quot; ....<p>No. You haven&#x27;t seen real tech debt until you&#x27;ve stared into the abyss and the abyss has stared back.
DanHulton6 个月前
&gt; 9. Technical debt can be classified into three main types: ...<p>This isn&#x27;t _incorrect,_ but I&#x27;d say it&#x27;s insufficient, or at least it lacks a sufficient treatment of what technical debt is and what is important about it.<p>Technical debt is known technical problems that are affecting or will affect your velocity or the business as a whole. When considering technical debt, you need to know:<p>- the estimated amount of time required to correct the problem - the ongoing penalty you&#x27;re paying by not correcting it, if any - the hard cutoff by when the problem must be correct, if any - the consequences for not correcting the problem by the hard deadline<p>Three examples to demonstrate:<p>1) You have a User god-model that is thousands of lines of code long. It is incredibly hard to work with, and any change that interacts with it takes, on average, 5x as long as a change that doesn&#x27;t. It would take appx. four weeks to refactor sufficient methods out of this model to make it as easy to work with as the rest of the code, but there is no hard cutoff by when this problem must be solved.<p>2) You&#x27;re only able to clear your job queues on the weekend, and the job queue time has been growing steadily for the past few months. By mid-week, the average queue time is appx. 10 minutes and by end-of-week, it&#x27;s nearly 30. If this problem is not solved in one month&#x27;s time, the end-of-week queue time is likely to be over an hour, and in two month&#x27;s time, the mid-week queue time is, too. We can add extra capacity to our job runner pool in an hour or so, at a cost of $x&#x2F;month.<p>3) The new account creation script is a mess of spaghetti code, a real eyesore. Changing it requires about 10-20x as much effort as any other part of the system. It would take appx. 2 weeks to untangle. However, there is no hard cutoff by when this problem must be solved, and in fact, this code is rarely ever touched anyway, only twice in the last year and only small changes were required.<p>These three cases fall roughly into the three categories suggested by OP (1 -&gt; preventing from doing stuff now, 2 -&gt; preventing from doing stuff later, 3 -&gt; might prevent you from doing stuff later), but you have sufficient information to make informed, better decisions that the simpler model would miss. For example, under the simple mode, the job queue problem would be classified as &quot;try to focus on&quot;, but the User god-model takes priority (&quot;minimize&quot; &quot;stuff now&quot; problems). But 2 seems much simpler to fix (provided you can afford it), and the consequences to deprioritizing it in favour of the god-model fix could be catastrophic to user confidence.<p>And in both systems, we&#x27;re most likely going to ignore problem #3, but if we know that a larger change to new account creation is coming up, one that you would expect to take 2+ days in another other part of the system, you now can expect that it would instead take 20-40 days in the spaghetti code, but that refactoring it would be appx. 16+2 = 18 days, a net win.
hugodan6 个月前
reads like a chatgpt answer