1,503 karma · joined April 2, 2010
Also, fingerprinting isn't always "bad" -- any business who takes credit cards online, wants to try to exclude people who will commit fraud (because they might have done it before.) Preventing fingerprinting, means you prevent certain anti-fraud, which means that you see higher prices and more friction doing commerce online, which also affects your experience. The connection is just much less direct.
Keeping email threads for reference is probably plenty data enough, btw; "signatures" sounds like the wrong approach. Maybe even just summarize the direction given in a wiki document with a change log with time stamps and requesting person, which you can review once in a while, and the sheer length of it might be enough to bring the point across.
This is bad.
> It's all require_once. > it doesn't use any framework
This is not necessarily bad.
> no code has ever been deleted
This is bad
> Multiple versions of jQuery
This is bad
> a full rewrite is necessary, but how to balance it?
You never need to fully rewrite something. You can always take an incremental approach. If the code and 3 people generate 20 million dollars of revenue (on their own? or with massive sales support? what is the cost of goods?) then it's got to be doing something right.
I'd start with the source control. Just check everything in, so it's easy to go back. Do that on the server they develop on, even. (But have a script that pushes the checked-in code to offsite.)
Second, make it possible to spin up a second instance of the same application, in some automated fashion, out of bare source control. This may mean dumping schemas and checking them in, and probably figuring out what data in the database are "necessary configuration" versus "user payload data."
Then, you can initiate integration testing on top of the second cluster. You can also turn this into some kind of local sandbox development setup.
Once that is done, you may be able to change the code quicker, because you can do and test it locally, and perhaps have some acceptance tests on top of the mudball. At that point, you can switch over to doing development locally and deploying (and, ideally, having the ability to un-deploy.)
After that, starting to clean up should at least be possible with less risk, because you can test it in isolation. You can then start pulling on threads in the code, such as standardizing library versions, detecting and deleting unused code, putting like modules together, and so on.
You don't need fancy tools for managing this, shell scripts and command-line git are probably plenty enough. Resist the temptation to spend six months engineering the build system of the future!
Of course a lot will depend on details, but from your brief description, this sounds like the path forward -- focus on making it possible and safe and cheap to iterate, and then you can get on with actual iteration. Don't waste time on big rewrites; instead do things incrementally. Don't believe that any one tool will save the day, because it won't.
Meanwhile, an Oracle sales person would love for you to sign a yearly contract, then ignore the license until it's time for the next renewal.
(This is also how Amazon and Azure beats out HP and Dell.)
A game engine has a second, hidden, part of the iceberg: The production pipeline for all the 3D world/art assets.
That's actually where most of the work goes -- hundreds of artists go into a AAA game, and all the art they produce must be technically excellent along a bunch of dimensions that have nothing to do with what it looks like (and in fact, generally make it harder to achieve the look you want.)
Game engines that can wire physics simulation to 3D rendering to window abstractions are easy-ish to make, similar to how web UI frameworks are easy-ish to make.
All the production pipeline stuff is where the real meat is, similar to how in WebUI and, package management and transpiling and bundling and deploying is a hard problem. I think the game side has it even harder than the web side, though, although they usually have the benefit of only needing to work on a defined set of platforms, rather than in "the" browser.
That being said, pull requests / code reviews / merge commits are totally compatible with that. Gerrit, for example, does every commit as a mini-pull-request on top of a branchless HEAD, and when the review finishes, you merge to main/trunk and off to CD it goes.
I know of no experienced C programmer who would expect the compiler to re-order the statements. That sounds very much like a strawman argument to me!
I'd also be OK with a compiler that emitted a warning: "This comparison looks dumb because the rules say it should do nothing." Emitting that warning is helpful to me, the programmer, to understand where I may have made a mistake. Silently hiding the mistake and cutting out parts of code I wrote, is not generally helpful, even if there exist some benchmark where some inner loop will gain 0.01% of performance if you do so.
After all: The end goal is to produce and operate programs that run reliably and robustly with good performance, with minimum programmer cost. Saying that the possible performance improvements of code that nobody will run because it's buggy absolutely trump every other concern in software development, would be a statement I don't think reflects the needs of the software development profession.
It's totally OK to say that an out-of-bounds write may or may not be detectable by reading any particular other local or global variable or heap value. That doesn't in turn translate to compilers being allowed to turn a bug in a SPECint kernel into an empty infinite loop (a case that happened!)
Indeed.
For example: https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.47... (This being a not fully settled / exploited area of computational science, there are plenty of alternative interpretations, too.)
The main challenge here is that extending relational algebra ("key tuple maps to row") into time ("key tuple maps to function from time to row") essentially cross-products two different dimensions, creating a much bigger domain to process and reason about.
Once you have the theory down, you can express some pretty handy relationships.
For you functional folks, you can consider the TRA as the regular RA lifted into the time monad. Except the composition can also go cross-wise; TRA can also be considerd as the narrow timeline lifted into the relational monad. Fun times!
The circuits in the phone may be damaged by excessive spikes. Especially if the spikes happen to be of a frequency that the internal filters / regulators in the phone aren't good at rejecting -- some regulators may only reject 20 dB of noise in certain bands, and > 80 dB in others.
(And it's not all superstition, and it's not all for tube amps -- it's all in the SNRR of your power stages for every piece of equipment in your sound chain.)
RPC is more lightweight for persistent connections to stateful services. RPC makes broadcast easier than HTTP. Individual RPC requests have (much) less overhead than HTTP requests, which is very helpful when tight coupling is acceptable.
Trying to run, say, MMO gaming servers over HTTP is an exercise in always paying double for everything you want to do. (Also, trying to run a FPS gaming server over TCP instead of UDP is equally not the right choice!)
(That being said, the end times may ALSO be upon us, but not because of this particular sign.)