Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Imperative vs Declarative: Weathering the storm

Imperative vs Declarative: Weathering the storm

You’ve no doubt heard the terms “imperative” and “declarative” before, and you probably know that developers strongly prefer the latter whenever possible. But just how clear are you on what these really mean, when it comes to writing lines of code in your app? Most of us probably just wing it or feel “I know it when I see it.”

Debates have raged for decades on this topic. In this talk, I’ll drive straight into the eye of the storm and try to sift through what it all means for our apps, specifically for the readability and maintainability of our code bases. We’ll look at how these concepts play out in a variety of webdev technologies, from HTML, to CSS, to JS… and more along the way. I hope you’ve brought your raincoat!

Kyle Simpson

October 15, 2023
Tweet

Resources

Video

https://youtu.be/Z71xJX9O9IU?si=B-wtYOLpupoSdD5D

FITC Web Unleashed 2023

More Decks by Kyle Simpson

Other Decks in Technology

Transcript

  1. As soon as you write some code, you can no

    longer accurately judge its readability…
  2. let age = 43 console.log(`I am ${age} years old`) #include

    <stdio.h> int main() { int age = 43; printf("I am %d years old\n", age); return 0; }
  3. .model small .stack 100h .data age db 43 ; Byte-sized

    variable named "age" initialized with 43 msg db "I am %d years old", 0 ; Null-terminated string for printf .code mov ax, @data ; Load the data segment address into AX mov ds, ax ; Set DS to the data segment mov al, age ; Move the value of "age" into AL register mov ah, 0 ; Clear AH to prepare AX for printing lea dx, msg ; Load effective address of the message into DX mov ah, 09h ; Function 09h - Display string int 21h ; Call DOS interrupt mov ax, 4C00h ; DOS function to exit the program int 21h ; Call DOS interrupt end DISCLAIMER: CHATGPT
  4. const total = x + y const addTwoNums = (x,

    y) => x + y // .. const total = addTwoNums(x, y)
  5. SELECT id, (CASE WHEN firstName ISNULL THEN 'Customer' ELSE firstName

    END) AS 'customerName' FROM Customers WHERE enabled = 1
  6. <img src="cats.jpg" width="300" height="200" alt="cats eating cake"> <input type="text" placeholder="First

    name, please"> <canvas width="300" height="200"> <img src="sad-face.gif" alt="Sorry this content is missing."> </canvas> <noscript> This page works best with the new JScript 3.0 in IE4. </noscript>
  7. <tr hx-trigger="cancel" class="editing" hx-get="/contact/${contact.id}" > <td> <input name="name" value="${contact.name}"> </td>

    <td> <input name="email" value="${contact.email}"> </td> <td> <button class="btn btn-danger" hx-get="/contact/${contact.id}" > Cancel </button> <button class="btn btn-danger" hx-put="/contact/${contact.id}" hx-include="closest tr" > Save </button> </td> </tr> </> htmx <button hx-trigger="click, keyup[altKey&&shiftKey&&key=='D'] from:body" hx-post="/doit" > Do It! (alt-shift-D) </button>
  8. FatalErrorBoundary( { page: FatalErrorPage }, RedwoodProvider( Routes() ) ) //

    vs compose( partial(FatalErrorBoundary, { page: FatalErrorPage }), RedwoodProvider, Routes )() // vs Routes() |> RedwoodProvider(%) |> FatalErrorBoundary({ page: FatalErrorPage }, %)
  9. @media (orientation: portrait) and (prefers-color-scheme: dark) { .my-list { --base-font-size:

    min(max(3vw, 1.3rem), 2.2rem); font-size: var(--base-font-size); } } @supports (display: grid) { section h1 { background-color: green; color: white; } } input[type=radio]:checked { margin-left: 20px; }
  10. .bar { --value-abs: max( -1 * var(--cfg-value), var(--cfg-value) ); --value-sign:

    calc( var(--cfg-value) / max(0.001, var(--value-abs)) ); --bar-width: max( 1px, var(--bar-scale-factor) * var(--value-abs) ); --bar-translate-x: min( 0px, var(--value-sign) * var(--bar-width) ); --bar-left-rounding: calc( -1 * min( 0px, var(--value-sign) * var(--bar-rounding) ) ); --bar-right-rounding: max( 0px, var(--value-sign) * var(--bar-rounding) ); /* .. */ }
  11. x == 3 // vs x === 3 || x

    === '3' // vs Number(x) === 3 // vs +x === 3
  12. switch (customer.type) { case 'guest': printCustomer('Guest'); break case 'subscriber': printSubscriber(customer.name);

    break case 'vendor': printVendor(customer.name) } // vs const actions = { guest: () => printCustomer('Guest'), subscriber: customer => printSubscriber(customer.name), vendor: customer => printVendor(customer.name) } actions[customer.type]?.(customer)
  13. let names = '' for (const record of records) {

    if (!!record.enabled) { const upperName = record.name.toUpperCase() names = ( (names == '') ? upperName : `${names}, ${upperName }` ) } } // vs const names = ( records .filter(record => !!record.enabled) .map(record => record.name.toUpperCase()) .join(', ') )
  14. function HomePage() { const [ locState, updateLocState ] = useState({

    reset: false, canceled: false }) const locCanceled = locState.canceled const [ searchText, setSearchText ] = useState(null) const [ weatherCanceled, setWeatherCanceled ] = useState(false) const [ loc, locFound ] = useGetLocation({ searchText, ...locState }) const [ selectedLoc, setSelectedLoc ] = useState(null) const searchInputRef = useRef() locState.reset = locState.canceled = false return // .. }
  15. function resetLocState() { setLocState({ reset: false, canceled: false }) }

    function setLocState({ reset = false, canceled = false } = {}) { // hack: new object inserted to change the // state-slot value and force a re-render updateLocState({ reset, canceled }) }