Our code should be as easy to read as possible. People should be able to jump into it and understand it straight away. To achieve this weāll need simpler code. And to achieve that weāll need guidance on code readability that we can point to.
This is a list of topics/rules around which I want to draft this guidance. Will elaborate/explain these later. This is just a brain dump at the moment.
button-element if usage of the button-role is otherwise irrelevant to the example)component-part not componentPart or component_partWritten out text for the above topics.
If you watch Effortless Style by Heydon and read my Cool Semantic Styles article and apply what is said in those you should be pretty close to what we want.
tbw
tbw
@ZoeBijl, please add any new guidance to this wiki page:
@mcking65 I will add it to those wiki pages. But Iāll first draft things in this thread so they can be more easily discussed.
@ZoeBijl
In the examples I have developed I used prototype functions, so they would be easy to convert to using classes.
The prototype functions are typically named for the ARIA role they correspond to, to help people see the properties and interaction of an ARIA role.
@ZoeBijl thatnks so much for opening this, it looks great! Also +1 to classes and es6 syntax :)
Would you be interested in using prettier/https://github.com/prettier/prettier to help maintain a consistent (and likely familiar) js code style? I personally prefer it to eslint or jslint because:
My other thought was it might be nice to include some guidance on good comments to add in addition to comments to avoid. I noticed there are some @param/@desc comments on a few examples, though not consistently -- are those the ones you'd like to remove as unnecessary and for docs tools/code editors? I don't have much of an opinion either way on those, although I personally like having human-readable comments that describe the type of parameters accepted and return value (if applicable). On the other hand, I also like Typescript, so take my opinions with a grain of salt š.
(small example, but maybe requiring this would be too much of a burden on authors. I also don't really have an opinion on the formatting/template)
/*
* Function to determine if a given option is selected
* @param option: HTMLElement
* @returns boolean
*/
function isOptionSelected(option) {
return true/false;
}
@jongund is this something we could automate? Happy to do it manually tho.
@smhigley I stan a thing that automatically fixes things on save/build. I think we currently use eslint tho? And we should totes include examples of good comments. As far as I know the @param things are mainly useful for IDEs. Since weāre not writing production code those seem unnecessary to me. If our code is unreadable without such comments then I think we should change our code. Meaning, it shouldnāt much matter what kinda thing is sent to a function for the reader to understand what the function does (for our example).
@ZoeBijl I used this type documentation pattern (e.g. @param and @returns ) in early examples I wrote and people thought it was more distracting than helpful, especially if the function and prototype names are descriptive as possible and having the code be as self documenting as possible. But like all groups they some times change their minds and I am open to other ideas, but less is more in most coding.
I agree some of the @param and @returns can get too verbose and unnecessary. One thing I really appreciate from Typescript is being able to tell at a glance the types of the arguments and return value, which lets you see something and immediately know e.g. "oh, this isSameDay function accepts two Date or null arguments and returns a boolean."
I find it also makes code much easier to refactor, because you can do anything to the internals of a function so long as you still accept and return the same types, or be more confident updating other logic if you know e.g. "I need to always give this function either a Date object or a null value, but not undefined"
I don't disagree with anything in here really, but I'm not terribly concerned about _what_ our opinions are as much as I am about how we can enforce and maintain them in a way that is both flexible and forgiving to would-be contributors. We're seeing feedback about outdated and unreadable code not because we don't have clear guidelines—the code guide covers quite a bit—but because simply having reference documentation isn't enough.
Echoing @smhigley but maybe with a bit more force, I feel rather strongly that we should outsource most of our code style to more opinionated and more well-backed styles that exist for each given language, and only maintain rules when we feel strongly that they should differ. Most modern code quality tools allow us to override existing rules so that we can effectively say, "use <some idiomatic style> but with tabs instead of spaces."
I like Prettier as well and I _really_ like TypeScript, but I do question whether they are the right tools for this job. TypeScript seems like an especially big hurdle—even the JSDoc comment syntax (@param/@returns) seems like too much to me.
Here are some of the tools that I often use and some rulesets that I recommend for each:
I'm not super opinionated on linters, or even on code style, as long as there's one consistent rule set for the entire codebase. I think my only two preferences would be:
eslint --fix in aria-practices, but perhaps it would do better with es6 rules? (at least there seem to be more wrenches there: https://eslint.org/docs/rules/)I agree with @sh0ji on Typescript as well -- as much as I like it, I don't think it's a great fit here. If there's some author-friendly way of noting down argument and return types I think that would capture some of the benefits of typescript, though it's quite manual and may degrade over time and with many authors.
Another possibility might be to use Flow with no explicit type annotations -- it would provide in-editor type hints and type checking but without sacrificing vanilla JS syntax
We could write TypeScript declaration files after-the-fact without touching the original JavaScript if someone's feeling ambitious...
The current eslint rules are rather minimal, which is in fact why --fix doesn't do too much. stylelint --fix did quite quite a lot when I ran it a while back (b552069db6dabc00ade37b6b19dccffd71845763). You may also not notice some of the things that are getting fixed because both stylelint and eslint run with --fix on staged files when you make a commit.
@nschonni, not sure if you saw this thread but I thought you may be interested!
Taking a look to see how much needs to change for the ESLint "extends": "eslint:recommended" or "extends": "airbnb-base"
Took a shot with the "eslint:recommended" in #1207 and it looks like it actually caught a few things that could be bugs. There are ~250 unresolved issues for unused and undefined variables that I just ignored for now.
Thank you all for the discussion, thereās some interesting things in here. For me though, I think most things Iād like to see changed arenāt really things a linter/formatter would catch. How for example would either of those catch whether a function name is readable or makes sense? How would those catch unneeded classes? How would those check if the order of CSS declaration blocks makes sense?
To me automation isnāt the solution for this issue. This will require human interpretation of the code. Which is kinda fine since we only have 27 design patterns. Sure there are some variation. But even if we totalled 40 code examples that would still be fine.
May I suggest we move further linter/formatter rules to another issue? Or would yinz prefer we keep that in this thread since thereās already quite a bit of information here?
I fully agree that we should focus on the human review. I just feel strongly that a big part of doing that is to automate as much as possible, allowing us humans to focus on the tougher aspects of code design, like naming things.
It's not always clear what can be automated and what can't, which is an argument for waiting to split off the automation discussion. For instance, you can ensure that CSS declaration order always increases in specificity with stylelint/no-descending-specificity, which is how I read "the order of CSS declaration blocks makes sense." That's a rule that's currently enabled in this repo, in fact.
I rather meant the order of the declaration blocks, not the properties within them.
And Iām all for automated things. I would like this thread focused on the human aspect š.
I rather meant the order of the declaration blocks, not the properties within them.
That's what the Stylelint rule I referenced addresses.
That canāt look at the DOM order to see if it makes sense / matches up. Iād rather not automate something a human is much better at.
Here is an attempt to summarize the discussion on this PR about best practices for example code:
The purpose of the example code is to provide an easy to read implementation of the JavaScript logic necessary to correctly set aria attributes on an interactive widget. Using best practices for code design in a production environment is not always applicable in this case.
All of an example widgetsā logic should be contained in a single class with rare exceptions. For example, if a component in one example widget would best be used as is in another example widget. If the widget has been split up into multiple classes for this reason, communication between classes should be done via events.
@ZoeBijl do you want to take the relevant feedback and your original suggestions and write a draft? Do you want more feedback on anything?
@maschad96 Welcome to the APG team. This is your first issue.
Hi all, Iāve drafted a small markdown document simply to start some discussion, everything noted in it is up for discussion and nowhere near final. š
i <= n + 1 or i <= n - 1 where possibleis, has, are or similar keywords distinguish the return value, (e.g: isVisible, areEqual, hasEncryption)diff
<ul>
<li>function buttonLabel(label) {</li>
<li>...</li>
<li>}</li>
<li>function applyButtonLabel(label) {</li>
<li>...</li>
<li>}<br />
allowMultiple may require a comment to explain. allowOpeningMultipleAccordions is long, but I understand what it does when reading through if logicsetFocusAndDoStuff. Calling setFocus and doStuff from handleFocus explains the logic well when viewing handleFocus definition. Ideally this reduces refactor thoughts about the callee's namediff
<ul>
<li>function getResult() {</li>
<li>let result;</li>
<li>if (A) {</li>
<li>result = resultA();</li>
<li>} else {</li>
<li>if (B) {</li>
<li>result = resultB();</li>
<li>} else {</li>
<li>if (C) {</li>
<li>result = resultC();</li>
<li>} else {</li>
<li>result = resultD();</li>
<li>}</li>
<li>}</li>
<li>}</li>
<li>return result;</li>
<li>}<br />
-</li>
<li>function getResult() {</li>
<li>if (A) return resultA();</li>
<li>if (B) return resultB();</li>
<li>if (C) return resultC();</li>
<li>return resultD();</li>
<li>}<br />
Hey @maschad96 -- this is such a great start, and in line with the direction we are already going in and somethings we've discussed in the past.
I have a few suggestions about where to go from here, I'm hoping you can carry this project through :)
What is the though about external helper functions in examples, like select only example?
I have included helper functions as a part of the prototype:
Also what about the use of case statements in the keyboard event handler to make it easy to see which keys are used in a particular pattern example. I feel people being able to easily identify the keyboard support in the code should be a top priority of the APG examples, since this is one of the biggest problems is keyboard support when people try to using ARIA.
Sorry for the delay, I was trying to finish some wiki updates (in a branch) to preview before the meeting, but for now here's an outline of what I was thinking (with @maschad96's work integrated):
Please refer to the AirBnB Javascript Style Guide for all basic javascript syntax and code style rules.
is, has, are or similar keywords distinguish the return value, (e.g: isVisible, areEqual, hasEncryption).render, for example:
function renderButton(label) {
return `<button type="button">${label}</button>`;
}
on, e.g. onKeyDown. If the event handler is specifically for one element within a complex widget, include the element name as well: onButtonClick.update, or a verb that describes the state change. The full function name should be in the format of "verb + name of state" For example, openListbox or updateFilterString.diff
<ul>
<li>function buttonLabel(label) {</li>
<li>...</li>
<li>}</li>
<li>function applyButtonLabel(label) {</li>
<li>...</li>
<li>}<br />
Opened https://github.com/w3c/aria-practices/pull/1553 with to show what the change would be to use primarily the Prettier defaults with the existing ESLint setup
Opened https://github.com/w3c/aria-practices/pull/1554 to show the Prettier defaults for CSS, based off the existing Stylelint config.
I've got HTML and MD over in a combined branch https://github.com/nschonni/aria-practices/tree/prettier, but it caused an issues with 2 tests, so stopped with submitting the JS and CSS for now
I wasn't able to find a good way to create a PR or preview link for the wiki's git setup, so I put the new file in a markdown gist here: https://gist.github.com/smhigley/2064dc84b5bbd2b653f2d8a6ed87ae60.
Could anyone interested leave reviews/comments directly on the markdown file? The changes include the entire "Javascript" section, and nothing else.
Would it make sense to put that in the https://github.com/w3c/aria-practices/blob/master/CONTRIBUTING.md instead of the wiki?
The group will add code documentation wiki link to contributing.md upon your suggstion, @nschonni
Wiki updated :)
@smhigley thanks! can you also fix the reference to npm run lint:fix, as it should be npm run fix without the lint: prefix (in https://github.com/w3c/aria-practices/wiki/APG-Infrastructure)
@nschonni
Would you add code documentation wiki link to contributing.md once Sarah fix the reference or should I? Just let me know.
@a11ydoer go for it! I haven't dug through the wiki much, so you probably know what links should be included
@nschonni I just updated the npm run fix line, thanks for catching that :)
@a11ydoer thanks for doing the link update in the main repo š
This looks so great, thanks @smhigley ! Seems like it's time to close this issue :)
Most helpful comment
@nschonni I just updated the
npm run fixline, thanks for catching that :)@a11ydoer thanks for doing the link update in the main repo š