Apropos of nothing, and anecdotally: 2 years seems to be about the length of time it takes for a solution to become the next problem.
HN user
desc
It depends how you count the unit/integration tests, really.
If you've got a general rule which must apply across an entire system, generate the necessary tests so that they fail granularly and don't require messing around to find the exact case which breaks. IMO that's one test, just applied to a range of cases.
An example might be mappings for Entity Framework (or similar ORMs, etc). Auto-generated migrations simply do not work if you need to limit migration downtime and maintain certain data invariants (which can't be specified in the schema, and yes, those always exist). So you need to write database migrations manually. This introduces risk of desync of entity mappings and schema.
So don't just spot-test roundtripping entities (a nontrivial system will have hundreds and something always gets missed). Instead, write a tool to introspect the DB schema and the Framework's mappings, and check that they match sufficiently closely. Every time someone adds an entity or property or something, it's already covered.
Similar cases exist when dealing with any interface between separate systems, especially when you don't control one of them. If you're regularly mapping between two models, use something like Automapper which can be asked to verify its mappings to check that every property is handled in some way.
(Granted, Automapper doesn't catch everything, but it builds a model that could probably be introspected over to spot encountered bugs and check that other possible examples of those bugs don't exist. Doing so generatively catches future additions of possible cases for free. If you're really paranoid, define some means of marking manually-written tests which cover each case, and test that a test exists for each case.)
Computers are really good at force-multiplication. They should trivially be capable of spotting other instances of known categories of bug. This is not hard to do and doesn't require wooly nebulous machine-learning shit: we've had introspectable ASTs since the dawn of compilers.
Silver bullets. They don't exist.
Code review. Read the results of someone thinking through a process. Spot more than they will, simply by throwing more eyes at it. Actually fairly effective: getting a senior dev to cast even a lazy eye over everything gives more opportunities to discuss Why It's Done This Way and Why We Don't Do That and Why This Framework Sucks And How To Deal With It with specific concrete examples which the other dev is currently thinking about. But it's still easier to write the code yourself than review it, and things still get missed no matter how careful you try to be, so it's still just another layer.
Unit tests. They cover the stuff we think to check and actually encountered in the past (ie. regressions). Great for testing abstractions, not so great for testing features, since the latter typically rely on vast amounts of apparently-unrelated code.
Integration tests. Better for testing features than specific abstractions, and often the simplest ones will dredge up things when you update a library five years later and some subtle behaviour changed. Slow sanity checks fit here.
UI-first automation (inc. Selenium, etc). Code or no-code, it's glitchy as hell for any codebase not originally designed to support it; tends to get thrown out because tests which cry wolf every other day are worse than useless. Careful application to a few basics can smoke-test situations which otherwise pass internal application sanity checks, and systems built from the start to use it can benefit a lot.
Manual testing. Boring, mechanical, but the test plans require less active fiddling/maintenance because a link changed to a button or something. Best for exploratory find-new-edge-cases, but throwing a bunch of students at a huge test plan can sometimes deliver massive value for money/coffee/ramen. Humans can tell us when the instructions are 'slightly off' and carry on regardless, distinguishing the actual important breakage from a trivial 2px layout adjustment or a CSS classname change.
So that's the linear view. Let's go meta, and combine techniques for mutual reinforcement.
Code review benefits from local relevance and is hampered by action at a distance. Write static analysers which enforce relevant semantics sharing a lexical scope, ie. if two things are supposed to happen together ensure that they happen in the same function (at the same level of abstraction). Encourage relevant details to share not just a file diff, but a chunk. Kill dynamic scoping with fire.
Unit and Integration tests can be generated. Given a set of functions or types, ensure that they all fit some specific pattern. This is more powerful than leveraging the type system to enforce that pattern, because when one example needs to diverge you can just add a (commented) exception to the generative test instead of rearchitecting lots of code, ie. you can easily separate sharing behaviour from sharing code. Write tests which cover code not yet written, and force exceptions to a rule to be explicitly listed.
UI testing is rather hard to amplify because you need to reliably control that UI in abstractable ways, and make it easy to combine those operations. I honestly have no idea how to do this in any sane way for any codebase not constructed to enable it. If you're working on greenfield stuff, congratulations; some of us are working on stuff that's been ported forwards decade by decade... Actual practical solutions welcome!
That's my best shot at a 2D (triangular?) view: automated tests can enforce rules which simplify code review, etc. The goal is always to force errors up the page: find them as early as possible as cheaply as possible and as reliably as possible.
The machine can't check complex things without either missing stuff or crying wolf, but it can rigidly enforce simple rules which let humans spot the outliers more easily.
And it is amazing how reliable a system can become just by killing, mashing and burning all that low-hanging error-fruit.
This.
Jira is a framework for building something which approximates your actual processes.
Justin said “I wish Atlassian would sit down with real-world developers and design this product the way we need it to work.”
The way 'you' need it to work. The process 'you' use. I suppose it's possible to build a business on creating a completely bespoke ticketing system for each company which uses one. Over time, that business might gravitate towards building a general toolkit which can be configured for each use case...
Oh look! Jira!
I'd bet that everyone's got their own distinct idea of where subtasks, ticket relations, etc actually fit in their workflow.
The article clearly exists to sell LinearB's product, which will of course work great for people who have the specific problems LinearB are solving with their product.
The rest of us will configure Jira within epsilon of 'works', then spend an afternoon reading about APIs and bash out our own automation service to update X different management tools appropriately for our workflows, and then go down the pub to bitch about management.
Some other commenters have mentioned environment variables as input.
IMO there are broadly two types of command: plumbing and porcelain. There's a certain amount of convention and culture in distinguishing them and I'm not going to try to argue the culture boundary...
For the commands which are plumbing (by whatever culture's rules), the following apply:
* They are designed to interact with other plumbing: pipes, machine-comprehension, etc
* Exit code 0 for success, anything else for error. Don't try to be clever.
* You can determine precisely and unambiguously what the behaviour will be, from the invocation alone. Under no circumstances may anything modify this; no configuration, no environment.
For the commands which are porcelain (by the same culture's rules, for consistency), the following apply:
* Try to be convenient for the user, but don't sacrifice consistency.
* If plumbing returns a failure which isn't specifically handled properly, either something is buggy or the user asked for something Not Right; clean up and abort.
* Environment and configuration might modify things, but on the command line there must be the option to state 'use this, irrespective of what anything else says' without knowing any details of what the environment or configuration currently say.
To make things more exciting, some binaries might be considered porcelain or plumbing contextually, depending on parameters... (Yes, everyone sane would rather this weren't the case.)
I meant that 'creating' is rather the wrong tense, and that this is probably a symptom that it's pretty well entrenched by now.
88. If the signaling value of a college degree is its most valuable part, then we are creating a society that values the appearance of success more than actual success.
Someone might be a bit confused about where the causality arrow is pointing.
I prefer to internalise useful ways of thinking rather than leaning too much on tools, on the grounds that the latter are easy-come-easy-go while the former can last a lifetime.
Learn to explain what you're building, why, and more-or-less how it works in a context appropriate to the listener.
(Related: write things down. Again and again, differently, until you understand them.)
Problems and their solutions usually have similar structures.
Any fix right now might save a lot of money. The right fix next week could save years. Often both are appropriate, but the latter is nearly always most valuable.
The world does not change nearly as fast as your competitors want everyone to believe it does, but people's beliefs can.
A tool which warns you of possible mistakes before consequences occur is always more valuable than a tool which tries to guess what you meant and does that instead.
This, most of all. Substitute native language if not English; the important thing is that the project be defined and developed in both a human language and a computer language, so that mismatches can be identified and resolved.
* Start by describing what you are trying to do.
* Specifically.
* Not 'build a web business to enable users to achieve their
potential', not 'create another library for X but simpler'
but *specifically what the software will do* and, most
importantly, the priorities of scope increase (it'll happen
anyway; just get the priorities and their order down in
text ASAP).
* Put it in a readme.txt or something.
* For any given subsystem of the code (meaning: any section
which can sort-of stand on its own) write another such file,
in more detail.
* Let these files guide your tests too.
* Keep them up to date. If priorities change, *start* by
updating the readmes. The code isn't immutable; nor is the
plan. But the plan comes first.
* When unsure how a new subsystem or feature is going to work,
write out your ideas and thought processes in text. Don't
start coding at all for a day or two after you sketch out the
basics. *Append* to this file instead of replacing large
parts.
[edit] Wasn't intended to quote that part (sorry to mobile users) but I can never remember how to get bulleted lists on this site...You mean like the OS is supposed to be?
1. Our customers run our software on their own machines for security and data-control reasons. As soon as something's running on someone else's hardware, the data is out of your control. Unless you're going to accept the (often massive) cost of homomorphic encryption, AND have a workload amenable to that, it's a simple fact.
2. Everything we do in house is small enough that the costs of running it on our own machines is far less than the costs of working out how to manage it on a cloud service AND deal with the possibility of that cloud service being unavailable. Simply running a program on a hosted or local server is far far simpler than anything I've seen in the cloud domain, and can easily achieve three nines with next to no effort.
Most things which 'really need' cloud hosting seem to be irrelevant bullshit like Facebook (who run their own infrastructure) or vendor-run workflows layered over distributed systems which don't really need a vendor to function (like GitHub/Git or GMail/email).
I'm trying to think of a counterexample which I'd actually miss if it were to collapse, but failing.
https://stackoverflow.com/questions/898489/what-programming-...
Most languages have context-free syntax, which is what the article refers too. There really is no reason to sacrifice that. Even modern PHP recognises the value of having a parse tree independent of an entire compiler.
Context-free semantics is an entirely different matter, and I'm not even sure what it'd mean...
Hmm, so the reusable bit is the straightforward inject-everything component, driven by an app-specific, app-aware hook-using part?
I can see how that can work for simple cases. Nesting components is going to get tricky though if the classes don't operate exactly the way the hooks expect.
Of course that's the problem: someone built hooks for their trivial cases and now they're the 'preferred' approach...
Edit: To clarify, 'simple' is going to be context-dependent since hook behaviour is. If your 'driving skeleton' of hook-based components is in the direct uninterrupted ancestry chain of every class component, you're probably using hooks in a near-ideal case.
I'm going to express something a lot of people are thinking and are being far too diplomatic about.
React Hooks are a fucking stupid idea and always were.
They're basically just adding dynamic scoping to a language and framework which doesn't need it, in one of the most 'magical' and confusing ways possible. You have to care about execution order to understand exactly how they'll all work and that will bite you eventually if you're building anything without knowledge of all the contexts in which it's called.
There's a reason that most languages stick to lexical scoping: you can see the dependencies, in the same file.
And a large portion of the value of functional languages is that they avoid state, making magic-at-a-distance impossible.
Boilerplate is not the problem. Magic is the problem.
Bad shit happens to a minority of people every day, permanently disrupting their lives and forcing them to abandon long-term plans. The majority remain oblivious and see an enduring status quo.
Suddenly a Black Swan craps on everyone at once, and a great many people are whining 'why is this happening to me' and 'when will someone fix this so I can go back to my routine'.
Guess what? Your routine is probably fucked. Throw it out, get used to the new normal, and accept that no one knows how to fix this (yet?), just like every other time we get hit by a context-changing problem.
Of course some people get too attached to their context, and those who come later and find their remains might label such events as 'out-of-context problems'...
Then you charge a reasonable price. You don't put a 'free' sticker on it with an unknowable 'ad revenue' cost in the background.
One might argue that the customer should know the price they pay in advertising data-scraping before logging in, these days, but we still convict people of fraud for taking advantage.
Advertising revenue is fraud.
"People don't consider my games worth what I spent to make them, so I'll sneak in adverts too so I don't have to charge them more and pop their little bubble, so they can continue thinking games are this cheap because the sticker price is still low."
No, this is not acceptable, and holding it up as a Good Thing that it's being perpetuated is stupid.
Microsoft have seen the writing on the wall (because it's been there for, I dunno, at least a decade?) and are saying 'you have to have an actual workable fucking business model now, k?'
Indeed, and this was measured, and the improvement was worth it. Profiling! :P The cost isn't always where we think it is.
Still, 'turn off exceptions because exceptions are slow' is a daft rule of thumb for the majority of software, where the slowness probably has more to do with choice of data structures, etc than compiler/platform implementation of language features.
Always measure first, last, and in between.
sigh If your application is slow, odds are it's not because you used exceptions.
If you're throwing enough exceptions for this to matter it'll show up on a profiler, and then you can change that specific chunk of code to avoid treating that particular case as 'exceptional'.
Because we wouldn't want mere icons distracting the user from being distracted by all the other stupid animations in the average UI.
The 'someone' in question probably wasn't the engineer.
I'd bet the engineer was listening to the 'someone' saying things like 'why don't you just' or 'it just needs to do this', or other things including the word 'just'.
I'd bet the engineer tried to explain the realities of how this stuff works, to 'someone' who's job didn't involve understanding what they were asking for, and reacted by demanding with the word 'just' instead of pretending to ask.
This could be done, if everyone involved were willing to accept massive risk to the lives of the astronauts (including the astronauts, obviously).
By which I mean, after hurriedly building rockets and testing them, finally going ahead with a backup rocket and crew to meet the deadline if the first one blows up on the pad.
With the risk of the backup doing the same...
If they're simply gambling on technology and engineering these days 'being faster', they're doomed to failure and I hope the individuals involved don't wind up killing anyone.
I know why this happens.
It happens because someone doesn't understand that search rankings vs. queries have to have a 'smooth' solution, and thinks they can tweak a few weightings here and there to get the results they think are 'correct' for the very specific cases they have in mind, without realising that this has a knock-on effect on the entire scoring space and you get odd singularities and stuff popping up as a result.
The people in question should not be touching anything even distantly related to a computer in any professional context.
Can't say I ran into this particular bug, but I tend not to trust the search on Windows much anyway. I myself have implemented better text/prefix matching and ranking using a very simple SQLite database schema, on a far larger dataset than 'the local machine', yet Microsoft repeatedly fail at a task which should succumb easily even to brute-force approaches.
They don't get to claim that it's a harder problem than indexing a hard disk without first explaining why they think they should retain the use of their fingers for continuing to send search terms over a network after I, as the owner of the hardware and 'owner' of the OS instance have made a concerted effort to turn that shit off.
The problem is that this is a bunch of bollocks. But at the same time, that might actually resolve my problem with it as the pain gets fed back.
If one is very very lucky, a library will have accurate changenotes explaining what the version increment actually means, distinguishing between security updates and wanking-over-new-subdependency-for-shiny-irrelevant-features updates.
However, if people are penalised for not wasting their time chasing the latest version of leftpad-with-custom-characters-except-in-locations-which-are-prime-or-square.0.4.3-beta.butnotreally, maybe we'll see shallower dependency trees in the important stuff.
Where 'important' ends up being defined as 'the packages which everyone else gravitates to, and therefore can't be avoided'.
Ideally we'd see security updates for previous major versions of things, for those of us without feature addiction, but that would demand more of the devs producing this crap.
And all the new bugs introduced in the process.
Yes, that's why these cost me a few weekends... if it's done in my Free Time(TM) they don't have to know about the unsuccessful ones.
I agree with this. One of the best changes we ever made was embracing a branch-heavy merge-centric workflow for literally everything. There was considerable pushback initially because it was perceived as 'complicated' but that dried up after a month because people were no longer fighting to push their hurriedly-rebased work to the canonical master branch any more.
It also means we can put an extra layer of QA testing between dev branch and master, which works nicely as a means of forcing communication between devs and QA too, and helps with onboarding (because the product featureset is huge).
Automated tests are great, but having a person read the feature ticket description and testing steps and then check that the functionality actually makes sense before it hits the master branch...
One more tool in the box, and it's a great culture correction mechanism too. Devs who don't test their work before submitting it get it sent back for fixing and feel less productive, so doing things thoroughly the first time feels quicker than rushing it. Doesn't even require management to monitor rates of reopening tickets, etc: people just don't like having to redo things.
This.
When something needs doing, I just get it done. If you wait for everyone to agree that it needs planning to be done at some point in the future, it'll never get done because the feature firehose never relents.
This has cost me a few weekends, but a) it meant that I kept my sanity in the long run and b) despite said fixes reducing the company's dependency on me (ie. supposedly damaged the job security) taking the initiative has allowed me to demonstrate a different and entirely more significant kind of value.
I actually invested some time a while back in building a nicer API for C# to invoke shell commands and process the results. The only downside IMO is the Rx library dependency for STDOUT/STDERR; I personally try to avoid depending on libraries which themselves have extra dependencies.
Since I did this at work it belongs to my employer, so I can't currently publish it freely, but it's not part of our core product so they may be open to publishing it under MIT licence or similar at some stage.
So it can be done, and has been done, but I guess most people are sufficiently happy with Powershell, Python, etc to not bother bridging the gap for C# too.