7 ms·
I Have a Dirty Secret. I’m a Software Craftsman
- pif 3y agoWhat a lot of hot air!
- smoldesu 3y agohttps://archive.is/4d7X1 https://archive.is/4d7X1
- thatguyknows 3y ago>I get the cold sweats when I see methods longer than a few lines of code This guys code might not be as readable as he thinks. I do not want to read through your hundreds of 10 line functions because a few people said "long functions bad". I liked the portion on naming. My God the amount of AbstractFactorySingletonViewModel garbage I see is astounding.
- mberning 3y agoIt’s a different kind of overhead. But I will take the tradeoff between ten 10 line methods and one 100 line method every time. I stand a much better chance of successfully modifying and testing the former.
- pxc 3y agoSmall functions are easy enough for me to deal with when they're basically library functions, but when they're split up/distributed in an OOP-y way I find navigating them and keeping track of them way more troublesome.
- mattwad 3y agoEspecially if some of them have side-effects, which is often the case unless you're dealing with a purely functional codebase which is pretty rare.
- RSHEPP 3y agoI think this is one of the more important distinctions, but you never seen it brought up. High level, business oriented functions almost never end up being more readable split up into a bunch of sub functions.
- vineyardmike 3y agoMy second job had amazing code quality, and one that that always struck me was how the code was separated cleanly into layers that made the business logic layer super obvious. It was 3 layers - API interface (unpacking objects, etc) - Business Layer - DB/System Interface. The business logic changes could often be totally contained, without updating the API or the database. It would be so obvious what layer needed to be edited, and the problems could be fixed so much faster. Rarely did a commit change two layers at once. You can easily handle AuthN in the API layer, AuthZ in the business layer, and then access to a db in the system layer. Assume API is un-authZ’ed, assume the system layer is fully AuthZ’ed, etc.
- Kamq 3y agoThat's fair if you only have 100 lines of code, but I don't think it automatically follows that the best solution for 10,000 lines of code is 1,000 ten line functions. There's a tradeoff between understanding the function itself and understanding how/where the function is used (and therefore understanding what will break when that function is changed). The best heuristic I've got at the moment is roughly the square root of the size of the module. So, for the 10,000 line module, my vague instinct is that I'll have one hundred functions approximately one hundred lines each. That's not a hard and fast rule, just an observation about tradeoffs and I would definitely expect (quite possibly even most) functions to differ significantly without losing sleep over it.
- rootlocus 3y agoSimple anecdote: A colleague of mine had a really hard time getting some topologic sort to work. I kept finding issues with his implementations and he was getting frustrated so we aggreed to have a pair programming session. He wanted to put all the code in a single method (not terribly long, maybe 30, 40 lines), but the conditions kept nesting and no matter how much he tried to figure them out, he couldn't get them to work. I convinced him to extract two methods which would only be used once and only inside this sorting method. He was vehemently against it. After he finally agreed he realized the code was so easy to read, it was basically self-explanatory and obviously correct. No ammount of fiddling with the if statements could've produced that. I don't impose fixed line counts for my methods. But when it makes sense, the readability improves a lot.
- CameronNemo 3y agoYeah line count is a hard metric to evaluate. Is your code 100 lines of code like this: let foo = Foo::new() .with_bar() .with_baz(bak, bat) .listen(); Or code like this: for f in in foo.iter() { if f == 1 || f > 9 || f % 2 == 0 || is_edge_case(f) { ret.push((f * 100).to_string()); } } Makes a big difference for readability. If you have a complicated conditional, go ahead and give it a name!
- MattPalmer1086 3y agoI have essentially the same story, so I won't repeat it. The big win was when my colleague seized on the idea of self documenting code. That was all he needed to write better structured code.
- gspencley 3y agoSmall functions are not about readable code. It's about single responsibility. Single responsibility is an engineering principle that is not limited to software development. It is the reason that we don't combine the breaking functionality in our car with the am/fm radio. We keep moving parts isolated because the fewer "things" that something does, the less likely it is to break. The less complicated it is. But there are other side effects to creating small, single-purpose functions (or anything for that matter). It is not always obvious when you will have an opportunity to reuse something. And duplication is not always apparent. When you take single-responsibility as far as you can go, you not only isolate all of your moving parts but you maximize the opportunities for reuse. And it goes even further than that. Your large functions likely have a few dependencies, at least. Those dependencies will make your functions more difficult to write tests for. And your test cases will be more complicated if you have larger functions because they are doing more than one thing that needs to be captured. Readability is more about expressing the intent of code. You can do that in "long functions." You can express the intent of code while making it extremely compilcated. Hell, just add lots of verbose comments and your code will be more "readable." Since you seem to be one of those people who has a stick up you about design patterns (your last comment about AstractFactorySingletonViewModel ... who hurt you?) I will offer you this piece of food for thought: the purpose of "best practices" and design patterns is to SIMPLIFY code. If you ever see a misapplication of them in the wild* then what you are witnessing is not "over" engineering ... it is POOR engineering. Consider that before throwing the baby out with the bathwater. * I rarely do, so I often wonder to myself if this is a made up problem by lazy devs who don't want to actually study theory. But I do hear that this occurs from time to so I'll take you at your word that there are people out there that don't know how and when to actually apply design patterns properly. The problem is the misapplication, not the patterns themselves - which are just common solutions to recurring problems. Do you not think DRY is a good idea?
- thatguyknows 3y agoSome links you may find useful https://copyconstruct.medium.com/small-functions-considered-harmful-91035d316c29 https://copyconstruct.medium.com/small-functions-considered-... https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpris...
- bazoom42 3y agoAgree - if a function is otherwise cohesive and doesnt mix independent concerns, I prefer one 100 line fuction to 25 4-line functions. Splitting functions is tempting because it makes each individual function seem simper, but the higher cost in complexity and maintainability is not as directly visible. Shorter functions are fine when appropriate, but length by itself is not an indicator of quality.
- mbrameld 3y agoIt's easy to find lots of clickbaity stuff this author has written about software development. It's hard to find any software they've actually developed.
- hammyhavoc 3y agoWho's to say it isn't under NDA?
- dclowd9901 3y agoI thought you weren’t being earnest or thorough but you’re absolutely right. I can’t even find a GitHub profile from them. While I don’t think you need to live for software engineering or have tons of open source side projects, if you’re going to take a presumptive position as an expert software engineer, you’d better show your hand.
- GTP 3y agoAs he wrote, he's keeping it as a secret :D
- rektide 3y agoThere's a core & real-to-some people feeling from some devs that wanting to do a good job & make things tight is a position that gets you persecuted. Many people want slip, want to just take easy ways a lot. There's a real tension to seeing software as a craft, versus regarding it all as low grade industrial output. I don't think the article does a super job of explaining itself or making visible this conflict, but I think this is one of very few pieces out there that talks to one of the realest most core splits in the field, that causes some of the most tension & agony between different people & different parts of orgs trying to work together. This those of us close to the machine, it is a conflict that sometimes feels like it has few wise, knowing, pro-Craft allies in.
- Cardinal7167 3y agoCounter-point: I’ve dealt with engineers who certainly would’ve considered themselves this article’s brand of “craftsman”. But all it really meant was that they tolerated their own TODOs in the code and no one else’s. Theirs were obviously justified and smart and correct TODOs and yours were just nonsense, trivial, brutish TODOS. Too frequently this attitude is just a bad cover for acting like your shit don’t stink.
- rektide 3y agoThere's plenty of problems. I don't think the presence of other problems (your problems negates/counters the problem I'm describing though. And sure, the two probably cross-paths a lot. Your "counter" seems to imply that my stated problem should be ignored & isn't real, that your problems trumps my problem. I feel we should take a broader look that can accept both problems as perhaps real. Who suffers from each problem? Who has allies as someone suffering under each condition? What are the risks of these problems? What are the pushbacks? Code-tyrants suck, but I think the org generally disfavors them, that they become unpopular on their own accord. Where-as people feeling the org is being short & persecuting craftsmen, they have other devs to gripe with, but they also alienate other devs wanting to just move fast, wanting to prioritize industrial output, and managers who see them as obstructing. In both cases we have devs who get seen as obstruction, and the line of whether there is over-concern tyranny or not shapes the perceived moral arch of their concern. Personally, I think the code-tyrannts often get just-deserts, whereas people with real intents end up victims. Living with code tyrants suck, but I tend to think it's somewhat self-correcting, where-as orgs never have to learn, never have anything actually incentivizing them towards awareness. I'd also say, rarely is there much attempt to actually negotiate with or address code-tyranny; people tend to just suffer, and the hard conversations/honest candor about the code-tyranny often never occur. Where-as developers often wear their heart on their sleeves about their commitment to quality & wanting to do a good job, and their please/cries are often ignored, as the org carries on from it's far-off unseeing place.
- samsquire 3y agoIn my programs there's usually a core insight or mental model that makes the code simple and straightforward to understand. What does someone need to have in their mind to understand this program? Then time happens and then the code is adapted and refactored and more features are added, then the original gem of mental model is hidden by hundreds of files and the algorithm is split into 10s of files for the little bit of wisdom that makes the whole program understandable to be occluded. This is why I like full code listing examples in documentation so much. A small self contained example - with import statements and instructions on how to build it if necessary and dependencies mentioned, I can get started extending the program to do something that I want. Strangely, I find leetcode solutions or algorithms easier to understand than big enterprise systems or codebases where people do things the right way, because the core algorithm is right there and you cannot miss any detail. I've enjoyed using OpenGrok a code indexer and viewer to turn any codebase into a wiki. When I come to a new codebase, I have no clue how people have split up the code into many files. The DWM codebase is fairly straightforward to read because it's all in one file. https://dwm.suckless.org/ https://dwm.suckless.org/ I want to read about your code rather than the code itself if I can help it, I prefer reading documentation or deep dives or tutorials into code than a large github repository with hundreds of files. I really liked the trend for a while in web frameworks where the code was side by side the documentation.
- revskill 3y agoI can give you a "clean" secret: Functional programming thinking. No, i don't talk about the "haskell style FP", i'm talking about FP thinking. It could help you clean your mess in a productive way, and i call it the true craftsmanship.
- Freire_Herval 3y agoYea. The guy is an amateur. Too heavy reliance on testing because he uses error prone design patterns instead of more reliable stateless fp patterns. You need to test but if you're testing on the scale this guy is it's a sign of bad practice.
- preommr 3y ago> No, i don't talk about the "haskell style FP", i'm talking about FP thinking. This distinction is perhaps something we should advertise more. I don't know if things have changed; but a decade ago when I was in uni we had some hardcore academic professors that loved functional programming and tried to teach it to us through languages like haskell. Which was wonderful stuff and interesting, but worlds apart from some of the practical stuff that most devs do. I used to see big names in software advocate for more functional programming and I didn't get "it" because I thought there were talking about haskell, F#, and advanced type theory. It took me a long time to understand they were talking about functions as first class objects where you can pass in a anonymous function or lambda, or whatever your language calls it instead of all this boilerplate for a separate private class like you would in old school java. Or thinking about things in terms of data and pipelines, for parallelization. And balancing this all out to get an intuition for when to use what without being restricted to any one style.
- zubairq 3y agoBrilliant article. I feel the same. But I save my craftmanship for my own hobby projects
- furyofantares 3y agoAlright, show me the code.
- billllll 3y agoDon't you know, code quality is judged on how many blog posts you write and how difficult you are to work with, and not on the code itself. /s
- morpheuskafka 3y agoWhat on earth is the point of this article? It doesn't seem to contain anything other than bragging on the part of the author and a number of buzzwords? And some positions seem quite strange. Not all function names will relate to "the problem the user wants us to solve for them." What does the user know or care about a function like atoi() or malloc()? And is it really unnecessary to ever write comments with readable code?
- deleted 3y ago[deleted]
- billllll 3y agoReads like one of those "what happened to GOOD code" articles, except this time the author plays the victim and pretends like there's a conspiracy among employers against good code. What strikes me with all these articles is that good code is never objectively defined. It's always some arbitrary measure, sprinkled with common wisdom (write tests! Keep functions small!). The author assumes that they write GOOD code and those evil managers and business people actively conspire against them for writing GOOD code. I suspect most people who write these articles aren't as good as they think. Most genuinely good engineers know the value of code, and how to balance their objectives with time. Being difficult to work with by insisting on arbitrary measures (e.g. all functions need to be pure and follow my naming convention!) does not make one a good engineer. There's a reason good communicators advance in their careers while grumpy tech-leads who constantly bring problems stay at their level.
- tkiolp4 3y agoThere is only code that works and code that doesn’t. The best code is no code at all. Everything else is subjective.
- louthy 3y agoThen there’s the code you have to maintain …
- tomcam 3y ago> Most genuinely good engineers know the value of code, and how to balance their objectives with time. In my experience most genuinely good engineers almost never complain, either.
- mirekrusin 3y agoThat's because they gave up on fixing others, not because they agree with them - they just ignore and carry on.
- thelittleone 3y ago
- deleted 3y ago[deleted]
- umvi 3y agoIMO OOP greatly overcomplicates a lot of programming where simple procedural functions would have sufficed.
- allemagne 3y agoAs a power fantasy, I heavily relate to this. I would love to be that archetype of writing amazing cathedrals of code with absolutely no tradeoffs with testability, readability, or (amazingly) time spent on development. To be a misunderstood genius whose only limit to delivering infinite value is the incompetence of my employer. However, this is a fantasy. >I’m obsessed with making my code readable, even to non-programmers This is a plainly impossible goal, because programmers themselves don't agree what "readable code" is. The problem is that sufficiently useful code always exists in a context where tradeoffs are inevitable. When the universe aligns to help us forget this, the success can be intoxicating. Wouldn't it be nice to live in a world where all projects can be like that? Software Craftsmen then get seduced into Software Masturbators.
- peteforde 3y agoFunction shortness is not, in and of itself, a value. There are many obvious examples where it makes excellent sense to refactor a complex function into several smaller functions. I get frustrated with the spirit of this post because I honestly have never seen anyone challenge this. However, I frequently see PRs which appear to be breaking a longer but repetitive function into a large number of mostly single line functions, apparently with the single goal of achieving checklist compliance with the folk wisdom. In these cases, we've devolved from a list of (for example) simple name mappings with the occasional downcase() (for the bold!) to having to jump back and forth between multiple points in the file, which has now grown by 80-150% to account for all of the begin/end sigils (language/lint dependent). If you're converting a JSON string to a dictionary and then mapping a large number of attributes, moving from object.foo = json["foo"] to object.foo = extractFoo(json) with a matching three line getter you have to scroll 2-3 pages down to read and does the exact same thing is not a win. TL;DR context matters and general rules only help when you don't treat them like hammers.
- juancn 3y agoThis smells funny to me... too much dogma. Sometimes the best and clearer way to do something is the "wrong" way. Testing adds some cost, so there's a tradeoff. You want a decent ROI on your testing efforts, otherwise you're wasting time and money. Opportunity should not be ignored. Software doesn't have to be zero defect, it has to be low enough to be useful.
- nathants 3y agolower your cost of living, take regular long vacations, and craft! the solution space of software useful to humans is barely explored. imaginative, unconstrained, passionate builders are for great good. collaborative software implementation for salary in the typical cost center environment is always going to be a tragedy of the commons. this is actually fine.
- dificilis 3y agoDear ChatGPT please write a software application satsifying the following requirements. Write the code in the style of Mohamed Aboelez. ....
- ukuina 3y agoBreak every rule, sometimes. Have a hundred-line function, when it makes sense. Try it out; it won't kill you, or your team, as long as it is well-documented.