| ▲ | Lovesong 3 days ago |
| I understand and I agree with the author points, specially looking to distance yourself from the dependencies these systems are usually entangled with, however: >But the code examples are in Java and C++ and I do python/JavaScript/ruby/ The problem with real legacy code is that sometimes it's not even in those languages. It's VB.NET, COBOL, AS400, BASIC, FORTRAN...and these may not have a chance to "wrap around your class", or "think about all the ORM code that you use". None! I use none of that!. And I can't even call any tests because I can't extend a non existant class, there's no objects in here!. The author also says: >You need feedback. Automated feedback is the best. Thus, this is the first thing you need to do: write the tests. I don't need automated feedback. I need to untangle this deep business layer that everything is wrapped around in a 40 years old codebase, with practically no documentation and having to modify one of the core systems of the company. Sometimes I can't even trust the feedback the program outputs. In this kind of scenarios where the code is so messy and limited by technical factors, the best approach I have found is to debug. And that's it. Follow the trail, find the "seam", and then start your kingdom in the little space you can. Because if you tell your boss that you are implementing Unit tests in a 40 years old codebase, the first question he is gonna hit you with is "Why?", and the article doesn't give any compelling argument to answer this. |
|
| ▲ | MarkSweep 3 days ago | parent | next [-] |
| Would you be so lucky if your legacy code was written in a well-known language. At a previous employer we had a big pile code in a “macro” language. It could interface with the main C++ code base. It was similar to assembly language in that it had no loops (just gotos) and register-like local variables (no custom names, just L0, L1, L2,…). The semantics were weird, something like unexpected pass-value-value versus pass-by-reference behavior when calling functions. One customer required lengthy qualification processes when changing the software. But “configuration changes” had a lower bar and somehow these “macros” counted as config. So eventually all the interesting business logic and RPC processing end up in a giant macro file. |
| |
| ▲ | bitwize 3 days ago | parent [-] | | Sounds similar to, but not as bletcherous as, BANCStar, a famed "esolang" that was really the output of a form generation tool used in the finance industry in the 90s. Some engineers figured out that the form generator's output was actually expressed in a Turing-complete, though very arcane, notation replete with opcodes and operands, reverse-engineered it, and started working directly in this language without using the tool to do more sophisticated things than the tool enabled on its own. The boss man probably said "Great! When can we put this into production?" and it's been downhill since. https://esolangs.org/wiki/BANCStar https://github.com/jloughry/BANCStar Relatedly, a long time ago I discovered that Zenographics Mirage—a vector graphics/illustration program originally designed to run on like, VAXen, with both a text terminal and a graphics terminal with a digitizing tablet (similar to this setup seen on Reading Rainbow: https://www.youtube.com/watch?v=b_zYaIxb6dY&t=965s), but later ported to PCs—ran on a sort of bytecode. There were a number of sample scripts shipped with the package that allowed you to automate things in Mirage's command language. Some of them had statements like DO 62,2,32472,32476,0 and comments that read "Don't worry about this, this is just Mirage assembly language." Intrigued, I discovered in the manual a feature you could enable called Op Code Monitor that flashed similar numbers whenever you entered a command. It was mentioned but not documented in detail, nor what the numbers meant, but from that and the scripts I could make some pretty good guesses. I figured out how to make Mirage prompt for a point and store it in a register; and with that I made a command to draw a rectangle that could be rotated. A rectangle in Mirage was defined by its corner points, so when you attempted to rotate it it just rotated the corner points and drew an axis-aligned rectangle with the new corner points. My command accepted two corner points and drew a polyline, so that when you rotated it, the whole rectangle rotated. |
|
|
| ▲ | strken 3 days ago | parent | prev | next [-] |
| > the article doesn't give any compelling argument to answer this Is "[w]hen code is not tested, how do you know you didn’t break anything?" not a compelling argument to your boss? |
| |
| ▲ | drzaiusx11 3 days ago | parent [-] | | From personal experience with bosses: no, often times it's not a sufficient argument. If the choice is thought to be between: * delivering value directly to the customer to justify a company's existence * or adding tests to things that already work (shore up) in an effort to make more correct changes in the future Will anyone be surprised how often it's the former that management will go for? I've found the appetite for this type of testability/observability improvement work increases proportionally with the number of support calls being made from customers complaining about the current feature set being unstable and buggy. This work is less palatable when customers really are just looking for that next new feature you promised instead and everything else is a-ok. The exception being things like orbital navigation systems etc.. | | |
| ▲ | tonyedgecombe 3 days ago | parent [-] | | >Will anyone be surprised how often it's the former that management will go for? I don't think I have ever asked permission to do make what I thought was the correct change. | | |
| ▲ | dotancohen 3 days ago | parent [-] | | That's because you're not opening Jira tickets titled Refactor Foobar. You're just doing it as a consequence of resolving real business issues. I have seen developers, and once been the developer, suggesting a refactor to the PM. That rarely works: it does not (directly) address a business goal. |
|
|
|
|
| ▲ | kens 3 days ago | parent | prev | next [-] |
| I read the book shortly after it came out, when I was working on an enormous system of legacy code. Unfortunately, I didn't find the book particularly helpful in terms of strategies for understanding or modifying legacy code. Yes, tests are a good thing, but I expected the book to provide a lot more. I agree with the parent comment that it is useful to follow the "trail" through the code. It can be a big effort just to figure out how the pieces are connected. Figuring out the data structures and files is another important thing. Also, write documentation as you go; this will help others understand the big picture. If you can just jump in and start writing meaningful unit tests, your legacy system is kinda trivial :-) Overall, there are people who view testing as a useful tool and people who view testing as an ideology. This book falls into the latter category. |
| |
| ▲ | osigurdson 3 days ago | parent [-] | | >> Yes, tests are a good thing, but I expected the book to provide a lot more It is strange, actually, how much value we place on any information that sits between two pieces of cardboard. | | |
| ▲ | hiatus 3 days ago | parent [-] | | Wait till you hear about how much we value information stored in meat! |
|
|
|
| ▲ | th0ma5 3 days ago | parent | prev | next [-] |
| I've skimmed the source material and it doesn't either except for the general advice of putting it all in some kind of conceptual box and slowly move parts to modern or better managed solutions as you try to reverse engineer it all. The underlying subtext was that it is all probably worse than you think and there isn't much good news... But "containment" in various forms is the direction forward mostly unfortunately. |
| |
| ▲ | eschneider 3 days ago | parent [-] | | TBF, that approach works and you won't go years w/o any deliverables with that approach. |
|
|
| ▲ | bitwize 3 days ago | parent | prev | next [-] |
| > VB.NET *laughs in VBA* |
| |
| ▲ | jaggederest 3 days ago | parent [-] | | I got started professionally in ASP/JScript. That's right, ADO through JScript, backend programming in javascript circa 2001. (If you've never heard of JScript, be thankful. It was microsoft's very-slightly-modified ECMAscript variant) |
|
|
| ▲ | arkh 3 days ago | parent | prev [-] |
| > And I can't even call any tests because I can't extend a non existant class, there's no objects in here!. I'm gonna preach for the church of "away with unit tests": so what? You don't want to test code. Code is not what the user care about. You want to test behavior. And for this you don't need to extend classes. You should not have to rewrite any code from your application. Like you say: write tests at the seam. Automate user inputs and checking outputs. A good test suite should not need to be rewritten during refactoring. It should even allow you to change language or replace for an off-the-shelf solution you did not write. If a unit test suite does not allow that, unit tests are an impediment. And I don't care about the "test pyramid", like the IRL ones, it is just a relic; from an age when launching all your tests in parallel was unfathomable. |
| |
| ▲ | SideburnsOfDoom 3 days ago | parent [-] | | > You don't want to test code. You want to test behavior. A good test suite should not need to be rewritten during refactoring. 100% agreed. > I'm gonna preach for the church of "away with unit tests" I disagree with the semantics here. From the article: "In short, your test is not unit if it doesn’t run fast or it talks to the Infrastructure (e.g. a database, the network" This says _nothing_ about what part of the app structure you test. It's not always a class-method test. Outside-in, behaviour centric tests that are not close-coupled to structure, can also be unit tests. And most of the time, it's a better kind of unit test. Kent Beck said many times: "tests should be coupled to the behavior of code and decoupled from the structure of code." "test behavior" was the original intent of unit tests. The idea that unit tests are only close-coupled class-method tests, or that testing 2 collaborating classes from the same app at once counts as an "integration test" is a latter-day misconception. A dumbing down. |
|