6 ms·
I've come to realise that the size of a code base measured by it's features and components is very different to the kind of "size" which you might measure by li
by kypro 4y ago
I've come to realise that the size of a code base measured by it's features and components is very different to the kind of "size" which you might measure by line numbers.
It's generally a good thing to write code which takes up more space if it's clearer to understand what's going on. However the size of a codebase in terms of its features and components is almost always directly correlated to the numbers of bugs you're likely to find and the difficulty you'll have maintaining it.
A problem I have at my current place is that the dev team in my opinion is far too happy to add new features whenever they're requested. You know those kinds of requests that go something like, "I basically want something that does exactly the same as [x] expect with this one small difference". When that happens few times it's fine, but when it happens 100 times suddenly you're managing a code base which is many times more complex than it needs to be with very marginal benefits.
And you might argue, "well why don't you abstract more". And that's a lesson that took me about a decade of software engineering to learn - if you can avoid abstraction you should. Writing, $a = 2 + 2; is far easier to understand than, $a = math.sum($num1, $config->get('num2')); The need for abstraction should be seen as a code smell. That's not to say you shouldn't abstract when it's the right thing to do, but if you find yourself needing to create abstraction on top of abstraction your feature set is probably needless complex.
A good engineer in my opinion isn't one who can build things well, but one who is willing to say, "no I'm not building that at all" and even remove features that are being used if the cost of maintaining those feature are not worth the benefits they provide.
- statictype 4y agoThis. The best codebases I’ve seen have an abstraction layer at the foundation and the rest is just dumb repetitive code built on top of that layer. It’s tempting to look at that and think we can abstract it out a bit more, but then you cross the line pretty quickly and your abstractions now mean you have 20 parameters to control how the abstraction should work.
- tstrimple 4y agoI agree with you to some degree, but I've built an abstracted data layer in literally every project I've worked on since I learned it was a good practice around 20 years ago and I still have yet to be on a project where we actually needed to replace the database. I've moved plenty of databases from on-prem to PaaS, but never switching DB technology itself through an abstraction layer. That's not to say I haven't had to replace data storage, but they were never built as layers and inevitably it happens when moving from mainframes to more modern systems. At this point at least some of my abstraction feels like a waste of time. Maybe when we start moving to Quantum Databases someone will benefit from my extra due diligence from a decade ago.
- portsnadaptors 4y agoI don't think building an abstraction over the data layer is just to make it easier to change your database. The abstraction can define the data access patterns upfront and minimize bespoke data access code. I've spent a lot of hours trying to untangle ORMs and other data access code from business logic. I've found that extending an abstraction to support a new access pattern (that you really need) is much easier.
- rlabrecque 4y agoThis is one of the bigger discussions I've been involved with lately; and I agree it really comes down to "bespokeness". When you have a 'system' which is 500 LOC, and 10 usages of that system totaling 10 lines each; compared to 10 bespoke implementations of 50-100 LOC each... you get into a spot where the system is battlehardened because of all the users, while the bespoke implementation have issues all over. Then when someone goes to add the 11th use-case of this; they are going to learn from and copy/paste the other version, probably exposing some latent bug in the bespoke version.
- scotty79 4y agoI don't think MS built Entity Framework so that you can switch away from MS SQL Server in any other way than "potentially".
- SkyPuncher 4y agoIMO, it's a lot like building a house. It's okay to have someone else manufacture the bricks for you. However, you still have to lay them by hand. It's tedious, repetitive, and labor intensive, but gets you the exact result you want. The second you try to pre-cast bricks, you end up with something harder to work with.
- ilyt 4y agoI think the main problem is "pre-abstracting", "this looks like it might be used often, lets write quick layer of abstraction on top of that so there is less repetition". Then you end up calling it once, maybe twice in code, and need to bounce thru 3-4 files to even get to see what the code is actually doing. Also makes anyone new to the code have to go thru same dance.
- oxfordmale 4y agoThere is a much simpler reason big code bases have less bugs. The size of the codebase is correlated with the investment a company is making into this codebase A larger code base will have seen many peer reviews from different Engineers over its lifetime, and as it is likely of the companies core products, a lot of testing, both internally by the test team, and externally by customers. On the other hand my hacky script, put together on a sunny summer afternoon, has zero love from senior management as they probably don't even know it exists.
- candiddevmike 4y agoFunny, everything you wrote can be applied to functions and classes too. Almost like software development can be summarized as "the balancing of WET and DRY". For me, I follow the principle of three: if it's repeated three times with minor tweaks, I should probably make some kind of abstraction for it. I try not to start with abstractions, as they tend to distract from solving the initial problem.
- twobitshifter 4y agoWET has negative connotations people have used AHA instead for avoid hasty abstractions.
- cxr 4y agoTRY: Try Repeating Yourself (as in, "Try repeating yourself first, and if that works, then good! If it doesn't, then okay, fix it then—but not before trying first.")
- deleted 4y ago[deleted]
- suprjami 4y ago> It's generally a good thing to write code which takes up more space if it's clearer to understand what's going on. Eskil Steenberg has talked about *width* of code as a more likely quality indicator. Consider the difference between: func(int i, void* p) And: modulename_objectname_operation(int count, void *ptr) Reference: https://youtube.com/watch?v=443UNeGrFoM https://youtube.com/watch?v=443UNeGrFoM
- didibus 4y agoI agree with you except on the topic of abstractions. Everything in software is an abstraction. Source code is an abstract representation of the running program. Functions are abstract representations of various execution that differ only in their parameters. Classes are abstract representations of stateful concepts of various instantiations that vary only in the information each instance contains. Etc. You cannot "not use" abstractions when you program, you can simply design poor abstractions or design good abstractions. And a lot of people underestimate the second degree impact of even the smallest of abstraction design choices, like what is and isn't factored into its own function, what parameters the function takes and return, what classes we have, how big they become, etc. And while saying no to new use cases that are almost same but slightly different is a good way to avoid needing to abstract more things (or avoid needing more code in general), and good engineers push back when necessary here, you will eventually have to deliver what the users want, and you cannot always convince them that all users want the same exact behavior as all other users, there will sooner or later be good business justifications for it. That's when if you don't introduce good abstractions to tackle the problem, you'll end up in an unmaintainable mess which will turn your velocity to a crawl. But it's important to understand abstractions have to be designed in tandem between product and tech, because how the user feature is exposed is also an abstraction, both the feature abstraction and the tech abstractions have to be well designed and must help each other out to remain manageable and coherent and work well with other features. In my opinion this is where really great engineers distinguish themselves, it's the ones who can figure out the good way to abstract that delivers that business international expansion where each region has slight variations yet feature parity can be maintained accross region, as an example of when you won't be able to push back and the abstractions will become critical to success. Normal engineers brute force their way through this slowly, each new region taking longer to expand too then the previous took, and with new features being impossible to launch globally anymore. While great engineers figure out the right set of abstractions alongside the product to enable fast expansions with judicious configuration/plugins to handle per-region variations, etc. They invest in tooling, frameworks and platforms that create those kind of abstractions, and just have the good instinct around balancing tradeoffs to deliver simple yet powerful abstractions that actually makes you faster and the system more maintainable. Bottom line, I find abstractions are critical to success, saying to avoid them I believe is misleading, you cannot avoid them, you need to get good at them instead.
- officehero 4y ago> No I'm not building that at all My guess is most devs learn this the hard way. You are liable for bugs in code you write, regardless of project quality and how much you complain to management about it. Apart from the examples you describe, I'd like to also emphasize cognitive load VS size/complexity. After a certain threshold, you shouldn't add more features but become a maintainer/tester of the ones you previously added (until you let go of responsibility/ownership).
- curiousgal 4y ago> no I'm not building that at all Oof. I work in finance and if you say that to a trader/business manager you'll be out of a job. Rightfully so.
- vanviegen 4y agoIndeed, "I'm not building that" doesn't sound good. You can of course discuss the True Cost (TM) of an impractical feature request with the client, and propose a less expensive alternative.
- ilyt 4y agoThe magic statement is "it will cost this and that in immediate and ongoing cost of keeping such thing in codebase"
- gregmac 4y ago> A problem I have at my current place is that the dev team in my opinion is far too happy to add new features whenever they're requested. > And you might argue, "well why don't you abstract more". A place I work was acquired by a company that owned our main competitor. When we were comparing them, I used to joke that the team had spent 10 years saying "yes!" to literally every feature request. They of course did it with abstractions, so it "wasn't that much more complicated". Feature-for-feature, our software could only maybe 15% of what theirs did, while theirs could do 95% of ours. The difference was the features we picked were the only ones 80% of the customer base actually used. Worse, because everything was abstracted, setting up those simple use cases was usually an order of magnitude more complex for the users: something that was a checkbox in ours was 15 different toggles and inputs, and very easy to screw up. Sure it could also be setup to handle hunderds more scenarios.. but in reality only there were just a few that only a tiny fraction of users even cared about. That, to me, is the danger of abstractions - at least it they make it up to the UI layer. QA (and automated testing, if it was written) still has to test the hunderds of scenarios because they're possible. Support has to understand. Dev has to maintain. It was interesting to compare the approaches, at least, and I came away with the conclusion: I never want to build that way. I'm all for internal abstraction: build the capability and flexibility to expand in, but have a very concrete and constrained UI that only exposes what actually has real value. And make it dirt simple to do the most popular use cases.
- keybored 4y agoI could die a happy person if I never have to hear programmers user the word “abstraction” again. Exposing more switches is the opposite of an abstraction. > , but have a very concrete and constrained UI that only exposes what actually has real value. This is an abstraction.
- furypt 4y ago> However the size of a codebase in terms of its features and components is almost always directly correlated to the numbers of bugs you're likely to find and the difficulty you'll have maintaining it. Fully agree. In addition, I find there's also the time component. Because requirements for existing functionality change over time, both code and data become inaccurate and a mess if they are not refactored. This leads to more bugs and to less trust in the data model (e.g. when can something be null).
- h0l0cube 4y ago> A good engineer in my opinion isn't one who can build things well, but one who is willing to say, "no I'm not building that at all" and even remove features that are being used if the cost of maintaining those feature are not worth the benefits they provide. I'm not sure what domain you work in, but in mine, the feature set is determined by the business requirements. e.g., if you're writing an app, you can't say to the client, "Don't add this potentially revenue-generating feature because it'll introduce bugs." What the article is suggesting, is that writing the same feature set with less code is likely to lead to a more correct implementation.
- zasdffaa 4y agoI think you misunderstand, some stuff has to go in but it is absolutely necessary as a dev to push back[1] on bad requirements, or at least that's my take. [1] admittedly in some cases you can't for various reasons, including bosses that won't listen.
- Too 4y agoIt’s the developers responsibility to question the feasibility and risk of the clients business requirements. The ones in charge are of course taking the final decision in the end anyway, but the flag should at least have been raised.
- iveqy 4y agoYou rarely see business requirements. You see an interpretation of them. Your job as an engineer is to understand the actual business requirements so you can question the interpretation of them and then simplify it. With that said, many requirements are technical and then you've even bigger freedom.
- h0l0cube 4y ago> You rarely see business requirements. You see an interpretation of them. At the end of the day, you answer to the bottom line. If you can achieve what is needed of your program (i.e., the business requirements) with less code, it seems you're less likely to have as many bugs - the point of the article. I think here, a good choice of expressive language/framework can pay dividends, moreso than trifling over the product owner over what functionality should go.
- KronisLV 4y ago> And you might argue, "well why don't you abstract more". And that's a lesson that took me about a decade of software engineering to learn - if you can avoid abstraction you should. Writing, $a = 2 + 2; is far easier to understand than, $a = math.sum($num1, $config->get('num2')); The need for abstraction should be seen as a code smell. That's not to say you shouldn't abstract when it's the right thing to do, but if you find yourself needing to create abstraction on top of abstraction your feature set is probably needless complex. On a technical level, I fully agree with this. Someone recently asked me why I didn't use an overengineered abstraction that they made for a feature request, which was not only complex, but also had no documentation or other usage examples. Actually even discovering that it was there wasn't something you'd naturally do when working on that codebase, given that the discoverability isn't exactly excellent and people don't communicate that much. Explaining to them that using it would have slowed me down, just how working with some other of their abstractions in the past has, was an uphill battle (and many of which weren't precisely the right abstractions and needed further refactoring to be useful), despite the fact that the current implementation without the abstraction does what's necessary and works without issues in prod, as well as is simple to refactor/throw away when necessary. In the end I simply conceded to do some refactoring and use their abstraction... but probably much later, since I have other things to do. I find myself caring less about the codebase and intricate mechanisms in it with time, because on a technical level it's boring and there really is little to no value added by bunches of complexity in it. Of course, there are a few cases where abstractions make sense, but in my experience developers (myself included) love to overengineer things and feel clever - they build their own castles atop big balls of mud. > A good engineer in my opinion isn't one who can build things well, but one who is willing to say, "no I'm not building that at all" and even remove features that are being used if the cost of maintaining those feature are not worth the benefits they provide. In regards to features, however, in many environments out there you won't get the ability to say "no". Someone who uses whatever the system you're developing is will have some requirements. A business analyst will turn those into a user story with acceptance criteria. You'll have to implement everything for it to be considered resolved, otherwise QA will throw the ticket back at you and indicate that some of the requirements haven't been met. I'm not saying that that's how we should build software, but rather that in many places that is simply the reality of building software and it's not like you can always quit and work elsewhere, when you need the money (not every place is as well paid as the US) or when the development culture is like that in the entirety of your country/time zone.
- kqr 4y ago> I've come to realise that the size of a code base measured by it's features and components is very different to the kind of "size" which you might measure by line numbers. How different is it, really? Any time I've done the research, it turns out line count correlates pretty strongly with feature complexity. Not perfectly, of course, but given how cheap line count is to produce compared to a quantification of feature complexity (remember function points? that don't even consider complex interactions between features!), it's a pretty damn good metric in my book. (Fun thing you can do: first try to estimate how much a software solution you're intimately familiar with has grown in feature complexity the past year (about 60 % for one project I work with), then look at how much it's line count has increased the same period (exactly 79 %). Previous year I had a project with a 30 % × 15 % pair. The numbers won't match exactly, but they will most likely be in the ballpark. You won't find a project with no complexity growth double its line count, or vice versa.)
- GuB-42 4y agoI really think that the best metric is size, as in lines of code, like the article seems to to suggest. Personally I may even be tempted to use bytes. For obvious reasons, number of features correlate with size, but I also noticed that bad code tends to be too big for the little it does. Dead code, repetition, rewriting functions that are already available because you don't know your API, etc... Note that it is a metric, not a goal. Making your code smaller won't necessarily make it better (ex: minification), but big code is more likely to be bad and successful efforts to make it better will most likely make it smaller.
- SergeAx 4y agoThe code is as complex as your business is. If your clients want these tweaks, you cannot get back to your sales department and say "no, we will not do it, it will make our code base too complex". You either introduce some abstractions, or lose that $Nmm contract.