{"id":21058574,"url":"https://github.com/schemar/party-invitations","last_synced_at":"2025-03-14T00:29:17.252Z","repository":{"id":41980065,"uuid":"510403918","full_name":"schemar/party-invitations","owner":"schemar","description":null,"archived":false,"fork":false,"pushed_at":"2022-07-04T22:38:52.000Z","size":180,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-06T00:08:00.143Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","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/schemar.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}},"created_at":"2022-07-04T15:05:18.000Z","updated_at":"2022-07-04T15:06:23.000Z","dependencies_parsed_at":"2022-09-01T15:43:33.539Z","dependency_job_id":null,"html_url":"https://github.com/schemar/party-invitations","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schemar%2Fparty-invitations","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schemar%2Fparty-invitations/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schemar%2Fparty-invitations/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schemar%2Fparty-invitations/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/schemar","download_url":"https://codeload.github.com/schemar/party-invitations/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243503148,"owners_count":20301187,"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","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":"2024-11-19T17:08:25.989Z","updated_at":"2025-03-14T00:29:17.223Z","avatar_url":"https://github.com/schemar.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Party Invitations\n\nTL;DR:\n\n```shell\ngit clone git@github.com:schemar/party-invitations.git\ncd party-invitations\nnpm ci\nnpm run build\n./party_invitations\n```\n\nSample output:\n\n```\nThe following warnings were encountered while processing the data:\nInvalid customer id: 'e6ee6861'\nIncomplete customer won't be considered: {\"position\":{\"latitude\":55.08068312,\"longitude\":12.86196247}}\nGiven longitude is not a number: 'x.26537009'\nIncomplete customer won't be considered: {\"position\":{\"latitude\":50.41642815},\"id\":\"e187aea0-95a6-41a7-b75c-3956a48c558d\"}\n\nCustomer IDs within 100 km of 52.493256 lat, 13.446082 lon (in alphabetical order):\n02335e27-e152-4771-9a6b-5b88c3b29eb9\n05d07502-b345-4133-b6b0-668ca44a5e95\n129b3b89-1b29-4aaa-a30c-b7e1a1dd46a0\n1a3b6dca-a1c9-4b9b-b280-007a040cc4da\n27051d0b-6476-4794-bb5d-27e7db8e29d5\n2cce11c3-6979-42a5-b501-ace4d5e598ec\n4013ac11-6d4a-41c5-94e4-abc4bb931e80\n469dc15d-6726-4e7d-8da4-d2e10e5a7669\n517ea41d-be50-4c2c-ba49-59a4de03842b\n6536a868-b83e-47b0-9462-7448a93b9827\n839e0ebc-4bce-4d2d-93d8-a1201b31c496\n841d0654-9971-4c84-a5a5-d3e5b5dbc77e\nadd9c5a5-65d6-49a1-a260-c984905a9745\nb86d6784-7b41-4e3c-971a-5ca2ce8ee895\nbbccc9e8-5cee-439a-a00c-0088b88bc327\ncab0ebd3-149b-4bd7-9862-e3e11a9273d5\nceaa3ede-1805-4c41-a2d1-79b1c74c033b\nd3b64719-3b9a-40b7-81e6-56dd94a5a794\nd5c05bd3-76d4-4c3c-9985-deb82751c611\n```\n\nExample data is located in the `./data` directory.\n\nI finished the exercise in less than 6 hours. I didn't have time to work on it\nfurther. I think it is in a good state to show my skills and discuss some of the\ndecisions that I made and how to further improve the code.\n\nSee some explanations below. Please also see the in-line comments in the code.\n\n## Design, Decisions, etc.\n\nI followed [12 Factor](https://12factor.net/),\n[SOLID](https://en.wikipedia.org/wiki/SOLID), etc. with the implementation.\n\nWhen looking at the size of the application, I overdid it with the abstractions.\nI did so on purpose in order to illustrate how clean code would use abstractions\nto be composable and extendable.\n\nFor example, the `Distance` class is overkill in the current code base, but can\nbe useful in a larger code base. A class for the `id` of a customer could make\nsense as well (or at least a type).\n\nI added the units to some of the variable names, for example `radiusInKm`. I\nthink this is a good practice to prevent bugs, especially in international\nteams.\n\nI didn't test `./src/main.ts`. It is trivial, but some tests might be good\nnevertheless. I simply ran out of time for the exercise.\n\nOnly `main.ts` interacts with the environment (`process.env`, `stdout`,\n`stderr`, and so on). This allows the classes that implement the business logic\nto not be cluttered with process or input/output handling.\n\nFor exception management, I only used `Error`. In a production system, it can\nmake sense to create custom errors instead. I didn't have the time to add those.\n\nI decided to postfix (most) interfaces with `...Interface`. I like the\ndistinction, but I completely understand the reasoning for avoiding it as well.\nIn the end, with all things \"opinions\" (tabs/spaces, naming, etc.), I care a lot\nmore about consistency than about the actual choice.\n\nWhen it comes to testing, the code only contains unit tests. A production\ncode-base would also include integration tests and end-to-end tests. I didn't\nhave the time to add those.\n\nSome libraries could be added to improve usability. For example:\n\n- [`commander`](https://www.npmjs.com/package/commander) for set-up and options\n  parsing. For example, `commander` provides utilities to get command options\n  from the environment, but also allow flags to override them on the command\n  line.\n- [`winston`](https://www.npmjs.com/package/winston) for logging.\n- [`chalk`](https://www.npmjs.com/package/chalk) to terminal output.\n- [`esbuild`](https://www.npmjs.com/package/esbuild) (or an alternative) to\n  package the application and its dependencies into a contained file.\n\nHowever, dependencies shouldn't be added without a good reason, as they require\nmore maintenance effort. For a small program like this one, it probably makes\nsense to have the fewest dependencies possible.\n\nI decided to go with `npm`, as it is the default. However, I have experience\nwith `yarn` as well.\n\nIf I had more time, I would set up\n[lefthook](https://www.npmjs.com/package/lefthook) so that prettier and eslint\nrun before every code commit. Unit tests (and potentially other tests) would\nprobably run before pushing to the remote. However, these settings depend on how\nthe team wants to work. My experience with `lefthook` is much better than my\nexperience with husky.\n\n## Running\n\n### Initially\n\n```shell\ngit clone git@github.com:schemar/party-invitations.git\ncd party-invitations\nnpm ci\n```\n\n### Running\n\nThe build process also lints and tests the code.\n\n```shell\nnpm run build\nnpm start\n```\n\nFollowing [The Twelve-Factor App](https://12factor.net/), you configure the\napplication through the environment. The following environment variables are\nrequired to run Party Invitations:\n\n```shell\nPI_RADIUS_IN_KM=\"100\" # The radius from within which the customers should be invited.\nPI_LATITUDE=\"52.493256\" # Latitude of the location of the host.\nPI_LONGITUDE=\"13.446082\" # Longitude of the location of the host.\nPI_CUSTOMERS_FILE=\"./data/Customers_Martin.txt\" # Path to a file containing customer details.\n```\n\nAfter you built the application, you can also run the wrapper script if you want\nto run it with an example configuration and example data. See the script for\ndetails.\n\n```shell\n./party_invitations\n```\n\n### Development\n\nTesting:\n\n```shell\nnpm run test:watch\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschemar%2Fparty-invitations","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fschemar%2Fparty-invitations","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschemar%2Fparty-invitations/lists"}