CSE 331: Coding Conventions
We will adhere to the rules described below when writing code in CSE 331. These rules should help prevent mistakes when learning JavaScript. They are not intended to represent the style used most often in industry or elsewhere.
If you write code like you've seen in class, your code should meet our code quality expectations as our code satisfies these conventions. (And if you do notice any mistakes in our code aligning with these conventions, let us know, so we can get it fixed!) If you choose to use features/methods/etc. outside of course content, make sure they follow these conventions as you could receive deductions (variable in severity), otherwise.
Types
Numbers
- Use
bigint
(notnumber
) for values that are always integers.- Correctness matters a lot more than performance to us.
Strings
- Do not use
charAt
to access characters of strings. Use the[]
notation instead (e.g."abc"[1]
is"b"
).- (
[]
is cleaner notation and has a more intuitive out-of-bounds result:undefined
instead of""
.)
- (
Records
- Do not access fields using
obj['name']
syntax. Useobj.name
instead.- The
obj.name
notation better indicates that "name" is an attribute of the "obj" record. Theobj['name']
notation implies that you're trying to access an element of "obj", which is not the case. If you want to represent a collection of (key, value) pair relationships, aMap
is more appropriate.
- The
- Do not destructure records. Always refer to records with their declared field names.
Tuples
- Do not use tuple indexing:
tuple[0]
. Use a destructuring assignment to access elements with a variable name:const [a, b] = tuple;
.
Declarations
- Do not use
var
keyword. Uselet
orconst
instead. - Variables that are not intended to be changed should be declared
const
.
Expressions
- Do not use
==
or!=
. Use===
and!==
instead.
Conditionals
- The condition of an
if
statements should evaluate to aboolean
.- Do not use non-boolean typed variables as condition to check if they're
truthy (e.g. use
if(x !== undefined)
instead ofif(x)
) - Do not use numbers,
undefined
,null
,NaN
, etc. as conditions.
- Do not use non-boolean typed variables as condition to check if they're
truthy (e.g. use
&&
should only ever be used between booleans in a conditional. Do not use&&
between a boolean and some operation or result to replace anif
statement.
Functions
- Do not use the
function
keyword. Declare a function withconst f = (..) => { .. }
syntax instead. - Anonymous functions should not be more than 1 (simple) line. If you need
to use
{}
to contain the contents (() => { ... }
), or write a 1-liner that exceeds 100 characters, create a named function instead. map
andfilter
should only be used only in simple cases. If the function you provide is more than 1 line, meaning you need to use{}
to contain the contents (map(() => { ... })
or passing a reference to a named function), you should write your own loop.- Do not use functions that require adding new package imports
(adding/changing
package.json
).
Classes
- Do not declare methods with
f(..) { .. }
syntax. Usef = (..) => { .. }
syntax instead. - Do not use
.prototype
.
Comments
- Remove unused (including commented-out) code and lingering debugging
console.log
s. - Write explanatory inline (
//
) comments when they're helpful. Generally these should be brief. Below are guiding ideas for what is "helpful" though you're welcome to add more as long as they don't clutter your code.- Variable descriptions, if it's not obvious how it's used
- A counter variable is likely obvious
- A priority queue with a custom comparator that holds paths in a pathfinding algorithm is not obvious
- State and Props descriptions in React apps
- Complex operation descriptions. When the code isn't self documenting.
- A comment for the line:
for (const item of arr) {}
that says "Iterate through every item of the array" is not helpful. The code syntax itself tells a reader the exact same thing.
- A comment for the line:
- Bug-fix history descriptions. These serve as good reminders to avoid making the same mistake twice.
- Variable descriptions, if it's not obvious how it's used
More on comments to come...
Web Dev
React
- Do not place server requests in the
constructor
orrender
. If a request is required on component start-up, usecomponentDidMount
instead. -
Avoid a cluttered
render
method.- Factor out distinct portions of the UI into helper methods.
- Factor out event handlers into their own methods. Do not use inline anonymous functions except to pass arguments to a handler.
-
State update conventions:
- Never trigger a state update from inside
render
. State updates trigger a rerender, which then triggers the state to update again, causing an infinite cycle. - Do not use consecutive
setState
s in a method.setState
is not immediate, so this may cause bugs, and makes it less clear how a method effects the state. - Pass a record containing only changed states to
setState
.
- Never trigger a state update from inside
-
Do not use React hooks. We teach the class-based components approach because it's fundamental and (believe it or not) easier to debug in many cases because state is more explicit.
- Do not directly access and modify the DOM (using Vanilla JS methods); do it
the React way.
- Do not use
window.location.reload
,document.getElementById
,element.innerHTML
, etc.
- Do not use
- Do not use
bind
.
Servers
- Error responses should always be a
string
error message with a40X
status code. Make sure error messages are descriptive. - Successful responses should always be a record with a
200
(default) status code. - Check that every expected query and body parameter exists and is of the correct type before using it and assigning it a type.
Fetch Requests
(If you follow the fetch function structure shown in class, you will meet these requirements and your code will be well organized and readable.)
- Every promise (
fetch
,json
,text
) you create should have acatch
handler.- In the
catch
, log out a descriptive error message.
- In the
- Check the status code of a server response before trying to access the record or error message data it contains.
- Validate type of all data received from server before using it and assigning it a type.
Naming
Consistent, descriptive naming improves readability and removes the need for some comments because they can convey what a function/variable does immediately. We expect you to generally follow these conventions, but if your names add detail, that's likely okay.
-
Event handler and callback naming ("X" being a name/descriptor for the HTML element that fires the event and "Y" being the type of action ("click" or "change")):
- Name props that store callbacks with the format "
onY
".- Notice this aligns with
onChange
oronClick
as in standard HTML components.
- Notice this aligns with
- Name functions that implement/handle events with the format "
doXY
".
- Name props that store callbacks with the format "
-
Fetch request naming ("X" being the name of the endpoint accessed.):
- Name functions that check the status codes of a server response
"
doXResp
". - Name functions that parse the JSON data from a response "
doXJson
". - Name functions that log error messages related to fetching "
doXError
".
- Name functions that check the status codes of a server response
"
File Organization
- Indent consistently after using 2 or 4 spaces per level.
- Utilize white space to group related operations and separate unrelated ones.
- If a piece of HTML has more than a couple CSS rules, factor out CSS into its own file.
- Modularize code by separating distinct portions into separate files.