{"id":26155651,"url":"https://github.com/programmer-network/programmer-network-defensive-programming","last_synced_at":"2025-07-24T03:06:16.772Z","repository":{"id":264976852,"uuid":"830179842","full_name":"Programmer-Network/Programmer-Network-Defensive-Programming","owner":"Programmer-Network","description":"Defensive Programming \u0026 Guard Clause Hell repository shared in a YouTube video","archived":false,"fork":false,"pushed_at":"2025-05-01T00:34:26.000Z","size":71,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-07-18T13:51:40.018Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Programmer-Network.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-17T18:52:51.000Z","updated_at":"2024-07-17T20:05:42.000Z","dependencies_parsed_at":"2024-11-27T06:34:31.542Z","dependency_job_id":null,"html_url":"https://github.com/Programmer-Network/Programmer-Network-Defensive-Programming","commit_stats":null,"previous_names":["programmer-network/programmer-network-defensive-programming"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Programmer-Network/Programmer-Network-Defensive-Programming","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Programmer-Network%2FProgrammer-Network-Defensive-Programming","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Programmer-Network%2FProgrammer-Network-Defensive-Programming/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Programmer-Network%2FProgrammer-Network-Defensive-Programming/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Programmer-Network%2FProgrammer-Network-Defensive-Programming/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Programmer-Network","download_url":"https://codeload.github.com/Programmer-Network/Programmer-Network-Defensive-Programming/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Programmer-Network%2FProgrammer-Network-Defensive-Programming/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266786798,"owners_count":23983871,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-24T02:00:09.469Z","response_time":99,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-11T08:58:08.853Z","updated_at":"2025-07-24T03:06:16.750Z","avatar_url":"https://github.com/Programmer-Network.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Defensive Programming \u0026 Guard Clause Hell\n\n1. **Defensive Programming**:\n   - **Definition**: Writing code that anticipates and handles potential errors and edge cases, often through numerous checks and validations.\n   - **Problem**: While necessary, it can lead to verbose and hard-to-maintain code, commonly referred to as \"defensive code bloat\".\n\n2. **Guard Clause Hell**:\n   - **Definition**: Overusing guard clauses or conditionals to check for null or undefined values.\n   - **Problem**: Can make functions cluttered with checks, leading to decreased readability and increased cognitive load for future maintainers.\n\n3. **Nullish Coalescing and Optional Chaining**:\n   - **Optional Chaining (`?.`)**: Allows you to safely access nested properties.\n     ```javascript\n     const value = obj?.property?.nestedProperty;\n     ```\n   - **Nullish Coalescing (`??`)**: Provides a default value if the left-hand side is null or undefined.\n     ```javascript\n     const value = obj.property ?? 'default';\n     ```\n\n4. **Data Validation and Schema Libraries**:\n   - Tools like Joi, Yup, and Zod can be used to validate incoming data structures and ensure required properties are present.\n   - Example with Joi:\n     ```javascript\n     const schema = Joi.object({\n       x: Joi.string().required()\n     });\n     const { error, value } = schema.validate(data);\n     if (error) throw new Error('Validation failed');\n     ```\n\n5. **TypeScript and Type Safety**:\n   - Using TypeScript can help by providing compile-time checks and ensuring that objects conform to expected shapes.\n   - Example with TypeScript:\n     ```typescript\n     interface Data {\n       x: string;\n     }\n     const data: Data = fetchData();\n     ```\n\n### Example Scenario and Solutions\n\nImagine an API response where you expect an object with a property `x`.\n\n#### Without Proper Handling\n```javascript\nfunction processData(response) {\n  if (response \u0026\u0026 response.x) {\n    console.log(response.x);\n  } else {\n    console.log('Property x is missing');\n  }\n}\n```\n\n#### Using Optional Chaining and Nullish Coalescing\n```javascript\nfunction processData(response) {\n  const x = response?.x ?? 'default value';\n  console.log(x);\n}\n```\n\n#### Using a Schema Validation Library (e.g., Joi)\n```javascript\nconst schema = Joi.object({\n  x: Joi.string().required()\n});\n\nfunction processData(response) {\n  const { error, value } = schema.validate(response);\n  if (error) {\n    console.log('Validation failed');\n  } else {\n    console.log(value.x);\n  }\n}\n```\n\n#### Using TypeScript for Type Safety\n```typescript\ninterface ApiResponse {\n  x: string;\n}\n\nfunction processData(response: ApiResponse) {\n  console.log(response.x);\n}\n```\n\n\n### Example Scenario with BigQuery\n\nYou have a scenario where BigQuery returns rows as an array or `undefined`, which can lead to unstable code when accessing properties of the response.\n\n### Current Code\n\n```javascript\nconst [response] = await bigquery.runQuery(query);\nreturn response?.processed_at;\n```\n\n### Problems with the Current Code\n1. **Unstable Response**: `response` could be `undefined`, leading to potential runtime errors if not checked.\n2. **Optional Chaining Overuse**: Repeated use of optional chaining can make the code less readable and harder to maintain.\n3. **Lack of Consistent Contract**: The response object structure is not guaranteed, making it less predictable.\n\n### Solution: Abstracting the Function to Ensure Consistent Contract\n\nYou can create a wrapper function that ensures the response always has a consistent structure. This function can provide a default object if the response is `undefined`.\n\n### Improved Code\n\n#### Step 1: Create a Wrapper Function\n\n```javascript\nasync function runQueryWithDefaults(query) {\n  const [response] = await bigquery.runQuery(query);\n  return {\n    processed_at: response?.processed_at ?? null,\n    // Add other properties as needed with default values\n  };\n}\n```\n\n#### Step 2: Use the Wrapper Function\n\n```javascript\nconst result = await runQueryWithDefaults(query);\nreturn result.processed_at;\n```\n\n### Full Example\n\nLet's create a full example to demonstrate this concept:\n\n```javascript\nconst { BigQuery } = require('@google-cloud/bigquery');\nconst bigquery = new BigQuery();\n\nasync function runQueryWithDefaults(query) {\n  try {\n    const [response] = await bigquery.query(query);\n    return {\n      processed_at: response?.processed_at ?? null,\n      // Add other properties as needed with default values\n    };\n  } catch (error) {\n    console.error('Query failed:', error);\n    return {\n      processed_at: null,\n      // Add other properties with default error values\n    };\n  }\n}\n\nasync function main() {\n  const query = 'SELECT processed_at FROM your_table LIMIT 1';\n  const result = await runQueryWithDefaults(query);\n  console.log(result.processed_at);\n}\n\nmain();\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprogrammer-network%2Fprogrammer-network-defensive-programming","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprogrammer-network%2Fprogrammer-network-defensive-programming","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprogrammer-network%2Fprogrammer-network-defensive-programming/lists"}