13 ms·
It's not a hack to satisfy known requirements
- deleted 1y ago[deleted]
- mouse_ 1y agoI think I needed this right now, thank you.
- michalc 1y agoYou’re very welcome! Have to admit I am curious: what’s the context / how has it helped you more specifically?
- mouse_ 1y agoIt's going to take me some time to come to terms with what you have to say; I'm probably not going to be able to internalize it today, and my gut reaction to it is, "I hate it; I'm over-engineering for a reason! I'm going to be better for it and my output is going to be better for it!" but this kind of thing has had me hung up on simple things at every turn. A present example is, I'm going through Chapter 1 of ANSI K&R as a refresher (I'm not a programmer) and I've been stuck on exercise 1-21, "entab", which is presented as follows: /* 1-21. Write a program entab that replaces strings of blanks by the minimum number of tabs and blanks to achieve the same spacing. Use the same tab stops as for detab. When either a tab or a single blank would suffice to reach a tab stop, which should be given preference? */ When confronted with a problem like this, I begin to think, "Well what's the most robust way of going about this task? What's a simple, good, and useful rule that will accomplish the stated goal?" And I'm not quite sure what happens next - figuring that out might require some deeper introspection, but I end up with the proposed solution: "Any time we encounter consecutive whitespace characters, including spaces, tabs and newlines, ignore the literal characters and instead simply add up exactly how many columns of whitespace they are going to take up, and then, find the smallest number of newlines, tabs and spaces we can print to the screen to match that amount of whitespace. This way we accomplish the stated goal and also end up with a nice text sanitizer." I'm still mulling all of this over but I'm pretty confident this goes so far beyond the stated problem that it could be considered self sabotage. There's a lot of moving parts to my solution and I don't have the cognitive tools to break up a problem like that yet. (I'd like to eventually of course, but I have to stay focus on what I'm doing!) Tangentially related maybe? Witches' Loaves https://www.littlefox.com/hk/supplement/org/C0002439 https://www.littlefox.com/hk/supplement/org/C0002439
- AndrewKemendo 1y ago> We're not here to write code, but to solve problems. In my opinion having had multiple technical job roles (car stereo/alarm installer, website builder, military officer, CEO, CTO etc…) this is always the job. The job is *always* to make the organization more effective and efficient full stop. Your role in that is what you choose and negotiate with your team throughout your life; boundaries change pre/during/post employment. When you join a company you usually (not always) have a niche role, to fill in a gap that is preventing effective organizational execution. If you’re mentally flexible to understand that your narrow focus is not the actual output, that is a temporal means to an output, then you transform how you view the concept of work and relationships
- wouldbecouldbe 1y agoIn most companies your job is to solve tickets. And the only creative freedom a developer has is how that ticket is solved. Quick fix, properly done, rework etc. Maybe that’s why certain smart developers over engineer, because that’s the only place they can create ownership
- linuxdude314 1y agoMaybe if you’re a junior engineer, but this absolutely not what most SWEs do.
- AndrewKemendo 1y agoAs long as you think like this then you’ll always stay in that niche
- wouldbecouldbe 1y agoThat’s not how I work. I live from my own saas. But I worked for a long time as a freelancer in big name corporates in the Netherlands and other large software companies. And that’s just how it is everywhere. Also in house senior devs have little to say. Hope other companies/countries are different
- inerte 1y agoI have an engineer on my team that's always asking "what if this or that happens in the future?" to which I've started to reply "what if it does NOT?" I know, I know... wow. Not much insightful. But for some reason with this particular engineer this is the starting point to talk about actual requirements. This question in particular triggers the conversation of going back to product to figure out what they truly know they want right now, not in a maybe future. What are the actual hard, known requirements, instead of wishful thinking and "if everything goes well we will need this" type of mentality of ~hopeful~ optimistic PMs.
- Otek 1y agoThe question “what if it happens” is important but useless without “how likely is that to happen” and “if it will happen how much time we need to cover for it”
- the_af 1y agoAgreed. This is well studied in software engineering though, I think I've read papers from the 70s/80s addressing this about risk mitigation: what is the impact of the risk if it materializes vs how likely it is to materialize? When people argue about the rigor of software engineering (i.e. "is it really engineering?") they often forget an important part: we are doomed to repeat mistakes or reinvent the wheel because nobody ever reads the existing research, nobody learns from the past, we're always blogging about the trendy latest thing withour asking ourselves "maybe someone in the 70s already explored this and drew valuable lessons?".
- Swizec 1y ago> we are doomed to repeat mistakes or reinvent the wheel because nobody ever reads the existing research, nobody learns from the past We do. There’s dozens of us! Here’s the thing though, the number of programmers in the world has been doubling every 5 years or so for the past few decades. If you have been doing this for 5 years, you have more experience than half the industry. It’s a young field and information only propagates so fast. You too have the power to help it spread.
- mattv8 1y agoThis is a great article, and I largely agree but I feel like we're giving ourselves an excuse to be lazy. Because I've absolutely seen this principle swing in the opposite direction, where someone writes slop code, without ever having had a real conversation with the end user(s) and consequently the software goes out the door without having considered top 5 most common edge cases that would have been so obvious if a little more effort had been put in.
- add-sub-mul-div 1y agoIt's easier to fix underengineering than overengineering so I still err on the side of the former.
- michalc 1y agoHave to admit the lazy thing threw me, but I can see how the “doing less” I’m arguing for could be taken that way. The “less” is not about avoiding handling edge cases that are possible now, but about avoiding putting in layers of code to handle cases possible only in some future versions of the code (with some limited exceptions that I mention at the bottom of the post) In fact, it’s crossing my mind that people might not want to be accused of being lazy, and that is a motivation to over-engineer solutions.
- jfengel 1y agoI find that strong typing often obviates the need for unit tests. Software breaks when data transforms in a way that typing can't solve. When data goes across a wire, or into a database, it leaves your space. Anything you do to your code risks breaking it. Integration tests solve that, but at a very high cost. I don't have a great solution for that. It just comes down to experience: how do things change over time? You take guesses. You try to be flexible, but not so flexible that you aren't solving the problem at hand. (It doesn't do you any good to hand the user a C compiler and say "this is flexible enough to handle all of your future needs.") Experience is, unfortunately, the worst teacher. It gives the lesson after it gives the test.
- the_af 1y agoAgreed about strong typing being a valuable tool, especially static typing. We've come full circle with coworkers telling me that "the best thing" about LLMs is that they can tell you when you have a typo in your function invocation or you forgot a mandatory parameter. This always leaves me dumbfounded, mouth open. If only we had a system to prevent this, from before LLMs!
- fn-mote 1y ago> strong typing often obviates the need for unit tests Do languages like Java have strong typing? I thought so, but I can’t reconcile that with the belief that unit tests in Java would be unnecessary.
- marcosdumay 1y agoIt's reasonably strong, so that on practice you can trust it to verify the properties it verifies. (Though, it's not completely flawless in theory.) It's also static, so your types declarations will replace tests. But it's extremely inexpressive, so you can declare very few properties, and so it will replace very few tests. And it's inflexible, so it will get on your way all the time while you program. Anyway, I can almost guarantee you the GP wasn't talking about Java.
- darksaints 1y agoThere's no single definition of strong with respect to typing, but I would probably put Java into the weaker of type systems, though it has gotten better over time. You can usually tell by how many casts you see in the code, and with most java codebases I see them everywhere. The pervasive nulls and untyped arrays are also huge red flags.
- wredcoll 1y agoIt's all pretty solid except for the part about OO. Inheritance almost never works in "the real world" but I find being able to tie functions to the data they're expected to work on to be pretty helpful. It's sort of like typing, really, functionX can only take FooBar variables vs making methodX on class FooBar. Like everything else you can "do it wrong" and you shouldn't be a slave to any particular software ideology.
- parpfish 1y agoi've been beating the drum for a long time that we teach OO programming wrong. we always start with inheritance (Car is subtype of Vehicle; Cat is subtype of Animal). we need to teach encapsulation as the primary use for OO. ime, the most effective way of using "OO" in practice is that you define data classes for different entities and then affix a few fancy constructors that let you build entities out of other entities. inheritance rarely gets used.
- stavros 1y agoThis is my experience as well. I use encapsulation so often that to me it seems that that's the "point" of OOP, whereas inheritance I use extremely rarely.
- 1718627440 1y agoI think the reason for this is, that encapsulation is not at all specific to OOP, that was already common before. What OOP adds really is inheritance and RTTI. Even polymorphism was already standard.
- makeitdouble 1y agoBut then the function x data mapping isn't 1 to 1 in most cases, which is often why inheritance is used. IMHO sperating data formats and functions works decently enough, interface/protocol/duck typing are more elegant than OO classes. As a real world image, a barcode scanner could be applied to anything that has a barcode, regardless of what that thing is. And I'd wager 99% of what we're trying to do fits that mold. When authentifying a user, the things that matter will be wether it's a legitimate call, and whether the user is valid. Forcing that logic I to classes or filtering by use type quicky becomes noise IMHO.
- parpfish 1y agoThis piece of advice: > Remember you can still add in that complication tomorrow is directly undermiend later with: > When should you create stuff just in case? > ... > 1. There is a reasonable chance it will be useful later > 2. It will be difficult to add in later > 3. It won't meanginfully slow down the meeting of more likely requirements whenever i've pushed to overengineer its because i've developed a strung hunch that points 1 and 2 are true and i'm being defensive about my time and effort next week. and if you're not allowed to push back because of 1 and 2 it's a sign of some sort of organizational problems where product folks sit at the top of the hierarchy and hand down dictates to builders without consulting with builders as equal partners.
- philippta 1y ago> Remember that code that clearly solves just those problems is in no way a hack. I think you can’t stress this point enough. In my experience anything that is not implemented by any norm or „clean“ or in an unusual way is considered a hack. Even if it perfectly solves the problem with the least amount of cruft to it. That makes me sad.
- crazygringo 1y ago> One of the worst pieces of advice that I ever received was that every function should be unit tested. Obviously not every function should be -- many are so obvious and straightforward that there's nothing to test -- but every function that does anything vaguely "algorithmic" should be. Unit testing is really important for catching logic errors. > Instead, write higher level tests close to the client/user facing behaviour that actually give you protection against breaking things unintentionally Yes, these are good. But they're a different kind of test. There are tests for correctness, and tests that the program runs. You need both. In fact, sometimes you even need to split up functions smaller than they otherwise would be, just so you can test an inner logic portion independently.
- RHSeeger 1y ago> Yes, these are good. But they're a different kind of test I've had this exact same discussion with people before. The same people that say "unit tests are worthless because the implementation could change, then the test gets thrown away". Honestly, it drives me bonkers because that entire argument makes no sense to me.
- crazygringo 1y agoSeriously. Yes, it goes without saying that if you throw out the old implementation and write a new one, you throw out the old tests and write new ones as necessary. It's as banal as saying that when you change a function definition, you have to go change all the places that call it. What do you expect?
- 1dom 1y ago> Yes, these are good. But they're a different kind of test. There are tests for correctness, and tests that the program runs. You need both. Why do you need both? Some software is so small and simple that it's possible to write a high level running/integration test that covers all the practical correctness tests that application might need too. You can say "yeah, but they'd be better if they had unit test" but that's the point being made: eventually you reach a place where more tests, even those recommended as best practice, don't actually deliver any more _real world_ value, and even make the code harder and slower to maintain.
- raincole 1y ago> Avoid Object-Oriented Programming Yeah, no. Every time I saw code written by someone who attempted to avoid OOP it ended up with passing a huge 'context' parameter to most functions, effectively reinventing Python's OOP but worse. Use pure functions as the starting point, but when you find yourself start passing complex structure around (any abstract word in parameter names, like 'context', 'data', 'fields' is a sign for that) just use OOP.
- chamomeal 1y agoI think of context parameters being a replacement for dependency injection. What parts of OOP are replaced by context params? State?
- gugagore 1y agoI think of context parameters as a replacement for dynamic scoping. I think it can be all of these things, which in my opinion partially undermines the GP's point. Recommended related musings: https://wiki.c2.com/?ClosuresAndObjectsAreEquivalent https://wiki.c2.com/?ClosuresAndObjectsAreEquivalent
- palata 1y agoI am amazed by the number of articles like this, that essentially say "you should not write bad code, you should write good code", while somehow implying "listen to me, I know better" (otherwise I wouldn't write the article...). The truth is that writing good code takes experience. Those who live by the rule "thou shalt not over-engineer" risk writing bad code. Those who live by the rule "thou shalt know all the patterns and use them" risk writing bad code. You should strive to write code that others can understand and maintain, period. If you need to justify your lack of "something" ("It's not a hack because..." or "I don't use OOP because..." or "I duplicated this code because..."), then it feels like it says something about your opinion of your own code, IMHO.
- prerok 1y agoCould not agree more. It's perfectly ok to not use a software pattern if it's not useful. It's ok to duplicate code if you know it will likely diverge in the future. Small and simple is the way.
- OutOfHere 1y agoYes. One either develops systems that work well and scale reasonably, or brittle ones without basic foresight, that keep failing and keep bad engineers employed. Especially if one is putting out open source software, one should take the time to engineer them well, not under-engineer them.
- motorest 1y ago> . If you need to justify your lack of "something" ("It's not a hack because..." or "I don't use OOP because..." or "I duplicated this code because..."), then it feels like it says something about your opinion of your own code, IMHO. I feel this sort of opinion is simplistic. "Explaining" is a need that is sparked by both sides. Just because someone is having doubts or questioning your work that doesn't mean they are automatically right and you are automatically bounded to introduce changes. Sometimes you do get questions from people who don't even have context on the problem domain and why you are taking path A instead of path B. Also, sometimes your choices can be questioned by opinionated peers who feel compelled to bikeshed over vague and subjective styles instead of objective technical issues. Is this something that should cause churn in your PRs? To give an example, once I had the displeasure of working with an opinionated junior developer who felt compelled to flag literally white spaces as critical problems in a PR because said junior developer instead of onboarding a source code formatter decided to write a personal markdown file with their opinions on style, and was trying to somehow force that as a reference. Is this sort of demand for justifications something you think should be accommodated?
- daxfohl 1y agoIts easy to mix up "what seems easier to work with" vs "what's actually easier to work with". Pulling things out to config, splitting into microservices, additional layer of abstraction, rules engines, etc., they seem like they'll be easier to work with at a high level because it gets logic out of the core, but then when you're actually working with them, or worse, when someone else is working with them and doesn't have your context, now there are five places to go look for logic and deciding which piece needs changed, instead of just one obvious place.
- Waterluvian 1y agoI wish more engineers I worked with had a stronger personal belief that design and planning is a favour they do for themselves. Defining clear requirements and resolving unknowns (or at least identifying them) is the foundation that if you don’t build, you’ll be building your project many times.