Skip to content

Instantly share code, notes, and snippets.

@reke592
Last active June 11, 2023 09:36
Show Gist options
  • Save reke592/c070d746a917f203d0ead4b3f91ebabf to your computer and use it in GitHub Desktop.
Save reke592/c070d746a917f203d0ead4b3f91ebabf to your computer and use it in GitHub Desktop.

Revisions

  1. reke592 revised this gist Jun 11, 2023. 1 changed file with 74 additions and 52 deletions.
    126 changes: 74 additions & 52 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -32,21 +32,34 @@ identify the application features and create a directory for each, put them insi
    identify all the components needed to fulfill the requirements of certain feature put them inside `features/<the_feature>` folder
    [frontend] - requires refactorization
    eg. /features/auth
    '-- auth_api.dart
    '-- data
    | '-- auth_api.dart
    | '-- AuthUserModel.dart
    '-- presentation
    | '-- /components
    | | '-- login_button.dart
    | | '-- logout_button.dart
    | '-- /dialogs
    | | '-- session_expired_dialog.dart
    | | '-- session_idle_dialog.dart
    | '-- /pages
    | '-- login_page.dart
    | '-- signup_page.dart
    '-- auth_provider.dart
    '-- AuthUserModel.dart
    '-- /components
    /huge_component
    '-- huge_component.dart
    '-- /fragments
    '-- part1_fragment.dart
    '-- part2_fragment.dart

    [backend]
    eg. /api/features/auth
    '-- auth_controller.js
    '-- auth_service.js
    eg. /api
    '-- /controllers
    | '-- /handlers
    | | '-- onUserCreated.js
    | | '-- onUserVerified.js
    | '-- auth_controller.js
    '-- /models
    '-- user_model.js
    | '-- user_model.js
    '-- /services
    '-- auth_service.js

    [below pattern may add complexity in backend]
    while designing the backend folder structure, we normally endup with 3-4 files inside a domain feature folder.
    a model for data source queries,
    a result set mapper to control the domain model structure
    @@ -78,6 +91,53 @@ while designing the backend folder structure, we normally endup with 3-4 files i
    | '-- user_types_model.js
    ...

    Much better to keep the structure simple. Utilize the IDE / code editor fetatures to locate the files that we need.
    /backend
    '-- /database
    | '-- /deployments
    | | '-- /v1
    | '-- /schema
    '-- /logs
    | '-- /rotation
    | | '-- 2023-11-06.rar
    | | '-- 2023-11-05.rar
    | '-- out.log
    | '-- err.log
    '-- /src
    '-- /config
    | '-- default.json
    | '-- prod.json
    | '-- test.json
    '-- /customs
    | '-- /client1_customs
    | '-- /client2_customs
    '-- /startup
    | '-- config_migrations.js
    | '-- customizations.js
    | '-- cron_jobs.js
    | '-- routes.js
    '-- /api
    | '-- controllers
    | | '-- /handlers
    | | | '-- onUserCreated.js
    | | | '-- onUserVerified.js
    | | '-- login_controller.js
    | | '-- signup_controller.js
    | '-- middlewares
    | | '-- auth.js
    | '-- models
    | | '-- user_model.js
    | '-- services
    | '-- login_service.js
    | '-- signup_service.js
    '-- /test
    | '-- test.spec.js
    '-- server.js
    '-- index.js

    Don't worry about the structure of response data, flat JSON struction from SQL query results are fine, use mapper to create nested JSON object response only when needed.
    (eg. third party integrations, expose different endpoint for them, avoid re-using the standard backend controllers. treat them as client customizations)

    Avoid querying database with default parameters in DAL just to avoid parameter errors, it is good to identify the script lapses than to get blinded by fail-safe process.
    eg.
    ```
    @@ -106,44 +166,6 @@ Avoid querying database with default parameters in DAL just to avoid parameter e
    transaction
    });
    ```

    Utilize CQRS (Command, Query Responsibility Segregation), in order to reuse a business logic.
    eg. We are working with document templates
    sample document format:
    {
    form_name,
    contents: [
    section: {
    children: [
    instruction,
    section: {...},
    etc..
    ]
    },
    instruction,
    section: {...},
    etc..
    ]
    }
    ```
    controller/
    contents -> database saveOrUpdate content (stored procedures)
    forms -> database saveOrUpdate form (stored procedures)
    ```
    the client requested a new function to clone an existing template. Doing this in SQL is commonly the way to go,
    but the trade-off is we will lose the control in domain, it will create a hassle if we decided to use different storage technology.
    also another hassle in terms of maintainance because we need to monitor the clone script everytime we have schema adjustments.
    The solution here is to have a medium that interconnects the controller and database. [use-case function]
    instead of directly including the logic in controller, we put them inside a use-case function.
    A use-case function doesnt care about the http response, it only accepts the parameters, return the result or throws an error.
    [the goal is to combine the use-cases]
    ```
    controller/ [use-case]
    contents -> saveOrUpdateContent -> database
    forms -> saveOrUpdateForm -> database
    '-- .clone -> cloneExistingForm -> saveOrUpdateForm [copy] -> saveOrUpdateContent [existing][recursive] -> database
    ```

    Handling dynamic model in SQL storage
    [schema]
    - identify the aggregation, (what the models have in common)
    @@ -154,8 +176,8 @@ Handling dynamic model in SQL storage
    '-- tbl_sections // 2
    '-- tbl_questions // 3
    [saving]
    - save/update per subclass (to properly define the subclass parameter requirements)
    - create a post script to update the commons (for code reuse)
    - save/update per subclass (to maximize the control for subclass parameter requirements)
    - create a post script to update the commons table (aggregate root)
    [querying the final result]
    - use temporary table
    - insert each sub class into temp table, convert the results directly to json (eg. JSON_OBJECT in MySql, FOR JSON in MSSql)
  2. reke592 revised this gist Aug 7, 2022. 1 changed file with 8 additions and 1 deletion.
    9 changes: 8 additions & 1 deletion web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -12,6 +12,14 @@ create commons/errors to contain all the possible application errors we can thro
    eg. /api/commons
    '-- event_bus.js
    '-- errors.js
    identify all common UI components/functionalities, create a wrapper for them, put them in a separate application package, the idea is to lessen the impact of third-party library syntax update in whole application source code.
    eg. commons_package
    '-- /widget
    | '-- data_grid.dart
    | '-- form_page.dart
    '-- /functions
    '-- show_dialog.dart
    '-- show_toast.dart
    identify the application features and create a directory for each, put them inside `features` folder.
    [frontend]
    eg. /features
    @@ -22,7 +30,6 @@ identify the application features and create a directory for each, put them insi
    '-- /auth
    '-- /applicant_masterlist
    identify all the components needed to fulfill the requirements of certain feature put them inside `features/<the_feature>` folder

    [frontend] - requires refactorization
    eg. /features/auth
    '-- auth_api.dart
  3. reke592 revised this gist Dec 30, 2021. 1 changed file with 37 additions and 0 deletions.
    37 changes: 37 additions & 0 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -100,6 +100,43 @@ Avoid querying database with default parameters in DAL just to avoid parameter e
    });
    ```

    Utilize CQRS (Command, Query Responsibility Segregation), in order to reuse a business logic.
    eg. We are working with document templates
    sample document format:
    {
    form_name,
    contents: [
    section: {
    children: [
    instruction,
    section: {...},
    etc..
    ]
    },
    instruction,
    section: {...},
    etc..
    ]
    }
    ```
    controller/
    contents -> database saveOrUpdate content (stored procedures)
    forms -> database saveOrUpdate form (stored procedures)
    ```
    the client requested a new function to clone an existing template. Doing this in SQL is commonly the way to go,
    but the trade-off is we will lose the control in domain, it will create a hassle if we decided to use different storage technology.
    also another hassle in terms of maintainance because we need to monitor the clone script everytime we have schema adjustments.
    The solution here is to have a medium that interconnects the controller and database. [use-case function]
    instead of directly including the logic in controller, we put them inside a use-case function.
    A use-case function doesnt care about the http response, it only accepts the parameters, return the result or throws an error.
    [the goal is to combine the use-cases]
    ```
    controller/ [use-case]
    contents -> saveOrUpdateContent -> database
    forms -> saveOrUpdateForm -> database
    '-- .clone -> cloneExistingForm -> saveOrUpdateForm [copy] -> saveOrUpdateContent [existing][recursive] -> database
    ```

    Handling dynamic model in SQL storage
    [schema]
    - identify the aggregation, (what the models have in common)
  4. reke592 revised this gist Dec 25, 2021. 1 changed file with 16 additions and 0 deletions.
    16 changes: 16 additions & 0 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -100,6 +100,22 @@ Avoid querying database with default parameters in DAL just to avoid parameter e
    });
    ```

    Handling dynamic model in SQL storage
    [schema]
    - identify the aggregation, (what the models have in common)
    - use separate table per subclass, connect them using static value like sub_type_id
    eg. tbl_form_content_types // definitions of subclass
    tbl_form_contents
    '-- tbl_instructions // sub_type_id 1
    '-- tbl_sections // 2
    '-- tbl_questions // 3
    [saving]
    - save/update per subclass (to properly define the subclass parameter requirements)
    - create a post script to update the commons (for code reuse)
    [querying the final result]
    - use temporary table
    - insert each sub class into temp table, convert the results directly to json (eg. JSON_OBJECT in MySql, FOR JSON in MSSql)


    We need to create a separate package for the auth related functions in order to modularize the whole project and customizations.
    this practice will result to a per-scope development, wherein we can create different features and less thinking about the main project source code.
  5. reke592 revised this gist Dec 25, 2021. 1 changed file with 30 additions and 0 deletions.
    30 changes: 30 additions & 0 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -71,6 +71,36 @@ while designing the backend folder structure, we normally endup with 3-4 files i
    | '-- user_types_model.js
    ...

    Avoid querying database with default parameters in DAL just to avoid parameter errors, it is good to identify the script lapses than to get blinded by fail-safe process.
    eg.
    ```
    // will not throw undefined id error
    // hence the procedure validation returns all when id is null
    undefToNull = (value) => value == undefined ? null : value;
    return await DB.query('CALL sp_get_json_replies(:form_id, :question_id, :created_by_user_id, :current_user_id);', {
    replacements: {
    form_id,
    question_id: undefToNull(question_id),
    created_by_user_id: undefToNull(created_by_user_id),
    current_user_id,
    },
    transaction
    });

    // better approach
    strNull = (value) => `${value}` == 'null' ? null : value;
    return await DB.query('CALL sp_get_json_replies(:form_id, :question_id, :created_by_user_id, :current_user_id);', {
    replacements: {
    form_id,
    question_id: strNull(question_id),
    created_by_user_id: strNull(created_by_user_id),
    current_user_id,
    },
    transaction
    });
    ```


    We need to create a separate package for the auth related functions in order to modularize the whole project and customizations.
    this practice will result to a per-scope development, wherein we can create different features and less thinking about the main project source code.

  6. reke592 revised this gist Dec 19, 2021. 1 changed file with 22 additions and 11 deletions.
    33 changes: 22 additions & 11 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -70,33 +70,44 @@ while designing the backend folder structure, we normally endup with 3-4 files i
    | '-- user_types_controller.js
    | '-- user_types_model.js
    ...

    We need to create a separate package for the auth related functions in order to modularize the whole project and customizations.
    this practice will result to a per-scope development, wherein we can create different features and less thinking about the main project source code.

    Handling client custom packages (part 1) [eg. flutter project]
    - as we mention, we are talking about packages, meaning we need to create a separate package per client
    - the client package must require the project commons, this common package contains all the interface exposed by the main project.
    - as we mention, we are talking about packages, meaning we need to create a separate package per client to contain all the customizations.
    - for this we need 2 packages, `projX_commons` and `projX_customs`
    - the client package must require the project commons, this common package contains all the interface exposed by the main project. also works like a bridge to connects the main project to other packages.
    package:projX_commons
    - this package also works like a bridge, it connects the main project to other packages
    '-- interface/
    | '-- IProjectXHttp (interface)
    | | '-- get, post, put, delete
    | '-- IProjectXSession (interface)
    | '-- IProjectXHttp
    | | '-- get
    | | '-- post
    | | '-- put
    | | '-- delete
    | '-- IProjectXSession
    | | '-- getCurrentSession
    | '-- IProjectXModuleRegistry (interface)
    | | '..
    | '-- IProjectXModuleRegistry
    | '-- register(ModuleMetaInf)
    | '..
    '-- models/
    '-- SessionTokenModel (readonly JSON claims)
    | - avoid binding json claims to class property, dependent package does'nt need to know everything
    | - avoid binding json claims to class property, dependent packages does'nt need to know everything
    '-- ModuleMetaInf (module_name, module_icon, module_path, bottom_nav_entry, side_nav_entry, etc.. main proj layout entry)
    - package:projX_customs
    - requires service container package (eg. in dart we can use Get_it service locator)
    - requires service container package (eg. in flutter we can use Get_it service locator)
    - requires package:projX_commons
    - package:projX
    - requires package:projX_commons
    - requires package:projX_customs
    - create a concrete class for IProjectXHttp, commonly this class will inject the session token to each HTTP request, also manage the backend address, put the singleton instace to our service container.
    - create a concrete class for IProjectXHttp, commonly this class will inject the session token to each HTTP request and also manage the backend address. put the singleton instace to our service container.
    - create a concrete class for IProjectXSession, we can initialize the instance when there is auth session or its up to the requirements, again we need to feed this to our service container.
    - create a concrete class implementation of IProjectXModuleRegistry and again feed the class instance to our service container
    - make the projX install the modules inside the concrete implementation of IProjectXModuleRegistry, its like spreading the module meta information to dedicated locations in our projX.
    - finally, if there is client custom, we need to re-create the package projX_customs, and override the main project dependencies
    - finally, if there is client custom, we need to re-create the package projX_customs (MUST have thesame package name)
    - we will use the service locator to access the object instance created by the main projX (eg. GetIt.instance<IProjectXHttp>())
    - and then we override the main project dependency projX_customs
    - as a result, we separate the client custom source codes to the main project source codes.

    Handling client custom packages (part 2) [eg. nodejs backend]
  7. reke592 revised this gist Dec 19, 2021. 1 changed file with 48 additions and 7 deletions.
    55 changes: 48 additions & 7 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -22,18 +22,18 @@ identify the application features and create a directory for each, put them insi
    '-- /auth
    '-- /applicant_masterlist
    identify all the components needed to fulfill the requirements of certain feature put them inside `features/<the_feature>` folder
    [frontend]

    [frontend] - requires refactorization
    eg. /features/auth
    '-- auth_api.dart
    '-- auth_provider.dart
    '-- AuthUserModel.dart
    '-- /components
    '-- login_page.dart
    '-- /huge_component
    '-- huge_component.dart
    '-- /fragments
    '-- part1_fragment.dart
    '-- part2_fragment.dart
    /huge_component
    '-- huge_component.dart
    '-- /fragments
    '-- part1_fragment.dart
    '-- part2_fragment.dart
    [backend]
    eg. /api/features/auth
    '-- auth_controller.js
    @@ -70,6 +70,47 @@ while designing the backend folder structure, we normally endup with 3-4 files i
    | '-- user_types_controller.js
    | '-- user_types_model.js
    ...
    Handling client custom packages (part 1) [eg. flutter project]
    - as we mention, we are talking about packages, meaning we need to create a separate package per client
    - the client package must require the project commons, this common package contains all the interface exposed by the main project.
    package:projX_commons
    - this package also works like a bridge, it connects the main project to other packages
    '-- interface/
    | '-- IProjectXHttp (interface)
    | | '-- get, post, put, delete
    | '-- IProjectXSession (interface)
    | | '-- getCurrentSession
    | '-- IProjectXModuleRegistry (interface)
    | '-- register(ModuleMetaInf)
    '-- models/
    '-- SessionTokenModel (readonly JSON claims)
    | - avoid binding json claims to class property, dependent package does'nt need to know everything
    '-- ModuleMetaInf (module_name, module_icon, module_path, bottom_nav_entry, side_nav_entry, etc.. main proj layout entry)
    - package:projX_customs
    - requires service container package (eg. in dart we can use Get_it service locator)
    - requires package:projX_commons
    - package:projX
    - requires package:projX_commons
    - requires package:projX_customs
    - create a concrete class for IProjectXHttp, commonly this class will inject the session token to each HTTP request, also manage the backend address, put the singleton instace to our service container.
    - create a concrete class for IProjectXSession, we can initialize the instance when there is auth session or its up to the requirements, again we need to feed this to our service container.
    - create a concrete class implementation of IProjectXModuleRegistry and again feed the class instance to our service container
    - make the projX install the modules inside the concrete implementation of IProjectXModuleRegistry, its like spreading the module meta information to dedicated locations in our projX.
    - finally, if there is client custom, we need to re-create the package projX_customs, and override the main project dependencies
    - as a result, we separate the client custom source codes to the main project source codes.

    Handling client custom packages (part 2) [eg. nodejs backend]
    - the main idea is to create a contract / finite format, like each custom index.js entry must have the below properties in module exports
    * name : String - the client custom package name
    * registerRoutes({app}) : Function
    - inside this function we use the app to register the main routes
    * registerMiddlewares({app, login_middlewares:[], logout_middlewares:[]}) : Function
    - inside this function we can add middlewares to the app (eg. to intercept controller function and inject the custom validations)
    - also we have the login_middlewares:[] wherein we can add the third-party hooks on user login, this is to provide the third-party session token to client.
    - finally the logout_middlewares, to destroy the previously created third-party session.
    - in javascript source codes, we will use the `require.main.require` to require the main project related stuff (eg. node_modules installed in main project, api models, commons, etc..)
    - just in case we need to use other node_modules, we can initialize a new package in the client custom folder, so we can install the requirements. for this we will use the normal `require` method to refer in local directory node_modules folder.

    as much as possible choose a Ubiquitous language that anyone can understood, ask the domain experts (the client), seek suggestions from developers, testers, qa. finally everyone must agree.
    eg. given we are working on a domain for Job posting
    JobsProvider.getList() <-- not clear
  8. reke592 revised this gist Nov 19, 2021. 1 changed file with 30 additions and 0 deletions.
    30 changes: 30 additions & 0 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -40,6 +40,36 @@ identify all the components needed to fulfill the requirements of certain featur
    '-- auth_service.js
    '-- /models
    '-- user_model.js
    while designing the backend folder structure, we normally endup with 3-4 files inside a domain feature folder.
    a model for data source queries,
    a result set mapper to control the domain model structure
    a controller to handle the http request, response and event bus subscribers
    and a domain use case file that contains all the validation for domain business logic
    eg. /api/features
    '-- /applicants
    | '-- /work_experiences
    | | '-- work_experience_mapper.js
    | | '-- work_experiences_controller.js
    | | '-- work_experiences_model.js
    | '-- /education_attainments
    | | '-- education_attainment_mapper.js
    | | '-- education_attainments_controller.js
    | | '-- education_attainments_model.js
    | '-- /basic_info
    | | '-- basic_info_controller.js
    | | '-- basic_info_mapper.js
    | | '-- basic_info_model.js
    | '-- applicants_domain_use_case.js
    '-- /user
    | '-- user_mapper.js
    | '-- users_controller.js
    | '-- users_model.js
    | '-- users_domain_use_case.js
    '-- /user-types
    | '-- user_type_mapper.js
    | '-- user_types_controller.js
    | '-- user_types_model.js
    ...
    as much as possible choose a Ubiquitous language that anyone can understood, ask the domain experts (the client), seek suggestions from developers, testers, qa. finally everyone must agree.
    eg. given we are working on a domain for Job posting
    JobsProvider.getList() <-- not clear
  9. reke592 revised this gist Nov 13, 2021. 1 changed file with 42 additions and 1 deletion.
    43 changes: 42 additions & 1 deletion web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,48 @@ identify the configurations that can affect the application restart, put those d
    create server.js (exports app and start function), and index.js (imports start function), so we can use the server.app for unit testing with supertest.
    identify the common functions and store them inside `commons` folder.
    create commons/errors to contain all the possible application errors we can throw, include the http status code.
    avoid returning plain text in api response, much better to use a JSON object eg. { message: 'foo' }.
    [frontend]
    eg. /commons
    '-- debouncer.dart
    '-- errors.dart
    [backend]
    eg. /api/commons
    '-- event_bus.js
    '-- errors.js
    identify the application features and create a directory for each, put them inside `features` folder.
    [frontend]
    eg. /features
    '-- /auth
    '-- /applicant_masterlist
    [backend]
    eg. /api/features
    '-- /auth
    '-- /applicant_masterlist
    identify all the components needed to fulfill the requirements of certain feature put them inside `features/<the_feature>` folder
    [frontend]
    eg. /features/auth
    '-- auth_api.dart
    '-- auth_provider.dart
    '-- AuthUserModel.dart
    '-- /components
    '-- login_page.dart
    '-- /huge_component
    '-- huge_component.dart
    '-- /fragments
    '-- part1_fragment.dart
    '-- part2_fragment.dart
    [backend]
    eg. /api/features/auth
    '-- auth_controller.js
    '-- auth_service.js
    '-- /models
    '-- user_model.js
    as much as possible choose a Ubiquitous language that anyone can understood, ask the domain experts (the client), seek suggestions from developers, testers, qa. finally everyone must agree.
    eg. given we are working on a domain for Job posting
    JobsProvider.getList() <-- not clear
    JobRequisitionProvider.getList() <-- much better
    avoid returning plain text in api response, much better to use a JSON object. create a finite model for plain message response.
    eg. { name: 'error', code: 'ERCODE_XXXX' message: 'foo' }
    centralize the route definitions in one file, so we can see the possible conflicts when using route params.
    when using external libraries always create a wrapper function, so we can inject our custom feature.
    always propagate the error by throwing, centralize the catch so we can easily control the application output.
  10. reke592 revised this gist Nov 7, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -14,7 +14,7 @@ avoid populating the controller, implement a message bus, emit the event after b
    folder by feature is great for low-coupling high cohesion source codes, but we also need to consider how big is the project.
    folder by feature is great for UI development.
    when using flutter, flutter-modular is a great library combined with providers for state handling.
    frontend development requires separation of concerns eg. VIEW - PROVIDER - API
    frontend development requires separation of concerns eg. VIEW - PROVIDER - MODELS - API
    store access token in memory, use cookie for refresh token, on page-reload revalidate using the refresh token
    on specs gathering always ask the client how they want to receive the results, is it immediate (realtime) or eventually (on specific schedule).
    when dealing with repositories, we need an object mapper to freeze the results, also to have a finite domain model schema.
  11. reke592 revised this gist Nov 7, 2021. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -10,9 +10,11 @@ when using external libraries always create a wrapper function, so we can inject
    always propagate the error by throwing, centralize the catch so we can easily control the application output.
    run heavy task in background (separate process), configure (optional) a socket endpoint to monitor the status.
    never include any business logic rules in controller, always have a use-case builder function, it is more readable with DI pattern support.
    never put everything in controller, implement a message bus, emit the event after business logic call to all subscribers.
    avoid populating the controller, implement a message bus, emit the event after business logic call to all subscribers.
    folder by feature is great for low-coupling high cohesion source codes, but we also need to consider how big is the project.
    folder by feature is great for UI development.
    when using flutter, flutter-modular is a great library combined with providers for state handling.
    frontend development requires separation of concerns eg. VIEW - PROVIDER - API
    store access token in memory, use cookie for refresh token, on page-reload revalidate using the refresh token
    on specs gathering always ask the client how they want to receive the results, is it immediate (realtime) or eventually (on specific schedule).
    when dealing with repositories, we need an object mapper to freeze the results, also to have a finite domain model schema.
  12. reke592 revised this gist Nov 7, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -35,7 +35,7 @@ in backend, eval is evil.
    apache,nginx,express,php etc... anything in server configuration, always hide the version / server details.
    use pm2 to monitor nodejs service, it can also run node process in cluster, auto-reload the service when it crash or reached the memory limit.
    always configure log-rotation, archive them properly.
    search for updated list of security headers
    search for updated list of security headers.
    when using reverse proxy setup in nginx/apache, we need to upgrade the connection for websocket endpoints, in normal http it close the connection after transmision, having it not upgraded the client will use http everytime we emit on socket.
    when assigning server hostname, we can use the hosts file to test the name resolution in local eg. 127.0.0.1 sample.domain.com.
    use separate file for each host configuration, store them in directory ./sites-enabled.
  13. reke592 revised this gist Nov 7, 2021. 1 changed file with 0 additions and 36 deletions.
    36 changes: 0 additions & 36 deletions sample-dropdown-option-test.js
    Original file line number Diff line number Diff line change
    @@ -1,36 +0,0 @@
    const request = require('supertest');
    const { app } = require('../server');

    describe('Form input options', () => {

    it('GET /option/regions --> array public list regions', () => {
    return request(app)
    .get('/option/regions')
    .expect('Content-Type', /json/)
    .expect(200)
    .then(response => {
    return expect(response.body).toEqual(expect.arrayContaining([
    expect.objectContaining({
    name: expect.any(String)
    })
    ]))
    });
    });


    it('GET /option/genders --> 200 array public list genders', () => {
    return request(app)
    .get('/option/genders')
    .expect('Content-Type', /json/)
    .expect(200)
    .then(response => {
    return expect(response.body).toEqual(expect.arrayContaining([
    expect.objectContaining({
    id: expect.any(Number),
    name: expect.any(String)
    })
    ]))
    });
    });

    });
  14. reke592 revised this gist Nov 7, 2021. 1 changed file with 36 additions and 0 deletions.
    36 changes: 36 additions & 0 deletions sample-dropdown-option-test.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,36 @@
    const request = require('supertest');
    const { app } = require('../server');

    describe('Form input options', () => {

    it('GET /option/regions --> array public list regions', () => {
    return request(app)
    .get('/option/regions')
    .expect('Content-Type', /json/)
    .expect(200)
    .then(response => {
    return expect(response.body).toEqual(expect.arrayContaining([
    expect.objectContaining({
    name: expect.any(String)
    })
    ]))
    });
    });


    it('GET /option/genders --> 200 array public list genders', () => {
    return request(app)
    .get('/option/genders')
    .expect('Content-Type', /json/)
    .expect(200)
    .then(response => {
    return expect(response.body).toEqual(expect.arrayContaining([
    expect.objectContaining({
    id: expect.any(Number),
    name: expect.any(String)
    })
    ]))
    });
    });

    });
  15. reke592 revised this gist Nov 7, 2021. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,7 @@
    -- Disclaimer: not a standard rule. just a collection of ideas/experience while doing a fullstack development task --

    identify the configurations that can affect the application restart, put those dynamic configuration in database. (eg. email config).
    create server.js (exports app and start function), and index.js (imports start function), so we can use the server.app for unit testing with supertest.
    identify the common functions and store them inside `commons` folder.
    create commons/errors to contain all the possible application errors we can throw, include the http status code.
    avoid returning plain text in api response, much better to use a JSON object eg. { message: 'foo' }.
  16. reke592 revised this gist Nov 7, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -22,8 +22,8 @@ we might get confused sometimes while designing a feature,
    - job_application on the other hand is more likely a service, because it has the business logic that connects the applicant and job_post
    - much better if we have separate controller and repository per each model and service.
    when designing data encryption, each aggregate entity MUST NOT share the same encryption key.
    - eg.
    - store the private key in database, we can also encrypt the private key in database, as a result there is no way to decrypt the data using the plain database record.
    eg. store the private key in database
    - we can also encrypt the private key in database, as a result there is no way to decrypt the data using the plain database record.
    - each user must have a unique key IV for encryption
    - store the decrypted value in result cache
    - just incase the user want to delete all the private details related to his account, we simply remove the key IV and cache entry.
  17. reke592 revised this gist Nov 7, 2021. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -21,6 +21,12 @@ we might get confused sometimes while designing a feature,
    - job_post and applicant can be considered as plain model
    - job_application on the other hand is more likely a service, because it has the business logic that connects the applicant and job_post
    - much better if we have separate controller and repository per each model and service.
    when designing data encryption, each aggregate entity MUST NOT share the same encryption key.
    - eg.
    - store the private key in database, we can also encrypt the private key in database, as a result there is no way to decrypt the data using the plain database record.
    - each user must have a unique key IV for encryption
    - store the decrypted value in result cache
    - just incase the user want to delete all the private details related to his account, we simply remove the key IV and cache entry.
    never use a websocket library alone, always use a redis store so it can run in cluster / load balancers.
    avoid relying too much in SQL ORM libraries, we can use them for normal select and update, but for complex queries, use stored procedure.
    use Postman for API documentation and testing, most of the time we can spot the security issues by testing in plain request.
  18. reke592 revised this gist Nov 7, 2021. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -16,6 +16,11 @@ store access token in memory, use cookie for refresh token, on page-reload reval
    on specs gathering always ask the client how they want to receive the results, is it immediate (realtime) or eventually (on specific schedule).
    when dealing with repositories, we need an object mapper to freeze the results, also to have a finite domain model schema.
    when overriding response value, we need to put them in controller.
    we might get confused sometimes while designing a feature,
    eg. job_post, applicant, job_application.
    - job_post and applicant can be considered as plain model
    - job_application on the other hand is more likely a service, because it has the business logic that connects the applicant and job_post
    - much better if we have separate controller and repository per each model and service.
    never use a websocket library alone, always use a redis store so it can run in cluster / load balancers.
    avoid relying too much in SQL ORM libraries, we can use them for normal select and update, but for complex queries, use stored procedure.
    use Postman for API documentation and testing, most of the time we can spot the security issues by testing in plain request.
  19. reke592 revised this gist Nov 7, 2021. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -29,4 +29,7 @@ when assigning server hostname, we can use the hosts file to test the name resol
    use separate file for each host configuration, store them in directory ./sites-enabled.
    always test the new configuration before restarting any service. unless you want some adrenaline rush. jk. ALWAYS test before restart.
    system batch file / shell script is your friend.


    on team discussion, always consider the posibilities that someone might not yet familiar in the tech-stack that we use.
    google is your friend, avoid mastering everything, they always update the technology, look for the documentation/manual.
  20. reke592 revised this gist Nov 7, 2021. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -18,6 +18,8 @@ when dealing with repositories, we need an object mapper to freeze the results,
    when overriding response value, we need to put them in controller.
    never use a websocket library alone, always use a redis store so it can run in cluster / load balancers.
    avoid relying too much in SQL ORM libraries, we can use them for normal select and update, but for complex queries, use stored procedure.
    use Postman for API documentation and testing, most of the time we can spot the security issues by testing in plain request.
    in backend, eval is evil.
    apache,nginx,express,php etc... anything in server configuration, always hide the version / server details.
    use pm2 to monitor nodejs service, it can also run node process in cluster, auto-reload the service when it crash or reached the memory limit.
    always configure log-rotation, archive them properly.
    @@ -26,3 +28,5 @@ when using reverse proxy setup in nginx/apache, we need to upgrade the connectio
    when assigning server hostname, we can use the hosts file to test the name resolution in local eg. 127.0.0.1 sample.domain.com.
    use separate file for each host configuration, store them in directory ./sites-enabled.
    always test the new configuration before restarting any service. unless you want some adrenaline rush. jk. ALWAYS test before restart.
    system batch file / shell script is your friend.
    on team discussion, always consider the posibilities that someone might not yet familiar in the tech-stack that we use.
  21. reke592 revised this gist Nov 7, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -11,9 +11,9 @@ run heavy task in background (separate process), configure (optional) a socket e
    never include any business logic rules in controller, always have a use-case builder function, it is more readable with DI pattern support.
    never put everything in controller, implement a message bus, emit the event after business logic call to all subscribers.
    folder by feature is great for low-coupling high cohesion source codes, but we also need to consider how big is the project.
    folder by feature is great for UI development
    folder by feature is great for UI development.
    store access token in memory, use cookie for refresh token, on page-reload revalidate using the refresh token
    on specs gathering always ask how the client want to receive the results, is it immediate (realtime) or eventually (on specific schedule).
    on specs gathering always ask the client how they want to receive the results, is it immediate (realtime) or eventually (on specific schedule).
    when dealing with repositories, we need an object mapper to freeze the results, also to have a finite domain model schema.
    when overriding response value, we need to put them in controller.
    never use a websocket library alone, always use a redis store so it can run in cluster / load balancers.
  22. reke592 revised this gist Nov 7, 2021. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -21,3 +21,8 @@ avoid relying too much in SQL ORM libraries, we can use them for normal select a
    apache,nginx,express,php etc... anything in server configuration, always hide the version / server details.
    use pm2 to monitor nodejs service, it can also run node process in cluster, auto-reload the service when it crash or reached the memory limit.
    always configure log-rotation, archive them properly.
    search for updated list of security headers
    when using reverse proxy setup in nginx/apache, we need to upgrade the connection for websocket endpoints, in normal http it close the connection after transmision, having it not upgraded the client will use http everytime we emit on socket.
    when assigning server hostname, we can use the hosts file to test the name resolution in local eg. 127.0.0.1 sample.domain.com.
    use separate file for each host configuration, store them in directory ./sites-enabled.
    always test the new configuration before restarting any service. unless you want some adrenaline rush. jk. ALWAYS test before restart.
  23. reke592 created this gist Nov 6, 2021.
    23 changes: 23 additions & 0 deletions web-notes.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    -- Disclaimer: not a standard rule. just a collection of ideas/experience while doing a fullstack development task --

    identify the configurations that can affect the application restart, put those dynamic configuration in database. (eg. email config).
    identify the common functions and store them inside `commons` folder.
    create commons/errors to contain all the possible application errors we can throw, include the http status code.
    avoid returning plain text in api response, much better to use a JSON object eg. { message: 'foo' }.
    centralize the route definitions in one file, so we can see the possible conflicts when using route params.
    when using external libraries always create a wrapper function, so we can inject our custom feature.
    always propagate the error by throwing, centralize the catch so we can easily control the application output.
    run heavy task in background (separate process), configure (optional) a socket endpoint to monitor the status.
    never include any business logic rules in controller, always have a use-case builder function, it is more readable with DI pattern support.
    never put everything in controller, implement a message bus, emit the event after business logic call to all subscribers.
    folder by feature is great for low-coupling high cohesion source codes, but we also need to consider how big is the project.
    folder by feature is great for UI development
    store access token in memory, use cookie for refresh token, on page-reload revalidate using the refresh token
    on specs gathering always ask how the client want to receive the results, is it immediate (realtime) or eventually (on specific schedule).
    when dealing with repositories, we need an object mapper to freeze the results, also to have a finite domain model schema.
    when overriding response value, we need to put them in controller.
    never use a websocket library alone, always use a redis store so it can run in cluster / load balancers.
    avoid relying too much in SQL ORM libraries, we can use them for normal select and update, but for complex queries, use stored procedure.
    apache,nginx,express,php etc... anything in server configuration, always hide the version / server details.
    use pm2 to monitor nodejs service, it can also run node process in cluster, auto-reload the service when it crash or reached the memory limit.
    always configure log-rotation, archive them properly.