{"id":18638304,"url":"https://github.com/dehasi/n26","last_synced_at":"2025-11-04T15:30:38.151Z","repository":{"id":98305957,"uuid":"138570120","full_name":"dehasi/n26","owner":"dehasi","description":null,"archived":false,"fork":false,"pushed_at":"2018-06-25T19:28:25.000Z","size":63,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-12-27T09:24:51.936Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","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/dehasi.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":"2018-06-25T09:06:36.000Z","updated_at":"2018-06-25T19:28:26.000Z","dependencies_parsed_at":null,"dependency_job_id":"2811eb9a-d43b-4e17-85bb-7d3afc5ce6b4","html_url":"https://github.com/dehasi/n26","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/dehasi%2Fn26","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dehasi%2Fn26/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dehasi%2Fn26/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dehasi%2Fn26/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dehasi","download_url":"https://codeload.github.com/dehasi/n26/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239435567,"owners_count":19638161,"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-07T05:40:26.515Z","updated_at":"2025-11-04T15:30:38.071Z","avatar_url":"https://github.com/dehasi.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"### Solutions description\n\nThere are two branches now:\n* master (with naive solution)\n* remove_stat (with multithreading approach)\n\nThere is also a general assumption that there are no transactions from the future.\n\n### Naive solution\n\nIt uses a fact that we don't need to keep transactions\nto calculate statistics. It updates `min`, `max`, `sum` and `count` every transaction.\nThen, when a statistic requested, counts `avg` as `sum / count`. \nThere is also a scheduled job, which resets statistics every minute. \nThat's why we have `O(1)` time and memory.\n\n### Multithreading approach\nThe scheduled the job, which was described above, removes all statistics, that's why it's not a proper solution.\nInstead of job, I create a thread for every request, which updates statistic, then waits a counted time (see below)\nand the updates the statistics again. \n \nWe have `timestamp` it's possible to find how long have a transaction been living. `now - timestamp`.\nThere is no need to keep the transaction more than minute. That's why the thread has to wait `minute - (now - timestamp)`.\n\nIt's easy to update `sum` and `count`, we add value to `sum` and increment `count`. Then the thread will \nsubtract `sum` and decrement `count`. For `min` and `max` we need to know the previous values, that's why\n`MinMaxPriorityQueue` from Google Guava was used. By this approach the statistics are always up to date,\nwe still count `avg` as `sum / count`. \nThis approach gives as `O(1)` time but not the memory because queues were used. But technically, we can predefine queues size\nand it gives as `O(1)` on average.\n\n### How to\n#### Build\n```\nmvn clean install\n```\n#### Run\n```\nmvn spring-boot:run -DskipTests\n```\nThe app will start on port: 8080 by default \n\n### Used technologies\n\n#### Spring boot\nas a general framework to build the web application.\n\n#### Spring Cloud Contract \nto generate stubs and API unit tests. See `test/resources/contracts`. \nTo turn the contracts generation off, set `false` to `turn-contract-on` maven property.\n  \n#### Spring Rest Docs \nto generate up to date documentation form unit-tests.\nAll generated documentation is packed to the jar and can be found on `/docs/index.html` URL.\n\n#### Maven dependency plugin\nto avoid transitive dependencies.\n\n#### Maven sort-pom plugin\nto keep a standard pom structure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdehasi%2Fn26","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdehasi%2Fn26","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdehasi%2Fn26/lists"}