{"id":21301742,"url":"https://github.com/funbox/clean_mixer","last_synced_at":"2025-07-11T20:31:23.634Z","repository":{"id":48955337,"uuid":"227112383","full_name":"funbox/clean_mixer","owner":"funbox","description":"Tools for code architecture analysis and linting","archived":false,"fork":false,"pushed_at":"2022-07-25T22:14:03.000Z","size":7467,"stargazers_count":91,"open_issues_count":5,"forks_count":5,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-06T08:35:29.741Z","etag":null,"topics":["clean-architecture","elixir","elixir-library"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/funbox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-12-10T12:14:28.000Z","updated_at":"2024-11-21T14:30:35.000Z","dependencies_parsed_at":"2022-09-02T02:12:50.199Z","dependency_job_id":null,"html_url":"https://github.com/funbox/clean_mixer","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/funbox/clean_mixer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/funbox%2Fclean_mixer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/funbox%2Fclean_mixer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/funbox%2Fclean_mixer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/funbox%2Fclean_mixer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/funbox","download_url":"https://codeload.github.com/funbox/clean_mixer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/funbox%2Fclean_mixer/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264892204,"owners_count":23679252,"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":["clean-architecture","elixir","elixir-library"],"created_at":"2024-11-21T15:50:39.882Z","updated_at":"2025-07-11T20:31:18.619Z","avatar_url":"https://github.com/funbox.png","language":"Elixir","readme":"# Clean Mixer\n\n[![Build Status](https://travis-ci.org/funbox/clean_mixer.svg?branch=master)](https://travis-ci.org/funbox/clean_mixer)\n[![Coverage Status](https://coveralls.io/repos/github/funbox/clean_mixer/badge.svg?branch=master)](https://coveralls.io/github/funbox/clean_mixer?branch=master)\n[![Module Version](https://img.shields.io/hexpm/v/clean_mixer.svg)](https://hex.pm/packages/clean_mixer)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/clean_mixer/)\n[![Total Download](https://img.shields.io/hexpm/dt/clean_mixer.svg)](https://hex.pm/packages/clean_mixer)\n[![License](https://img.shields.io/hexpm/l/clean_mixer.svg)](https://github.com/funbox/clean_mixer/blob/master/LICENSE)\n[![Last Updated](https://img.shields.io/github/last-commit/funbox/clean_mixer.svg)](https://github.com/funbox/clean_mixer/commits/master)\n\nTools for code architecture analysis and validation.\nHeavily inspired by Bob Martin's “Clean Architecture” and to some extent ArchUnit library.\n\n## Usage\n\nAdd `:clean_mixer` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:clean_mixer, \"~\u003e 0.2\", only: [:dev, :test], runtime: false}\n  ]\nend\n```\n\nTo generate [PlantUML](https://plantuml.com/) diagrams you need to have [Graphviz](https://graphviz.gitlab.io/) and JRE installed.\n\nConfigure components of your codebase in `.clean_mixer.exs`\n\n```elixir\n[\n  components: [\n    {\"some-component\", \"lib/clean_mixer/path-to-files-of-some-component\"},\n    {\"some-component/sub-component\", \"lib/clean_mixer/path-to-files-of-some-component/sub-component\"},\n    {\"some-umbrella-app-component\", \"apps/some-app/lib/some-app/path-to-files-of-some-component\"},\n    {\"some-grouped-component\", \"lib/clean_mixer/path-to-files-of-some-grouped-component\", group:\n  \"core_domain\"},\n  ]\n]\n```\n\nEach component is just an arbitrary folder with code and name. You can model components as umbrella apps or just subfolders of lib directory.\n\nNote that components can be nested in each other, although architecturally it is not recommended and in some cases might yield confusing results.\n\nComponents can have optional arbitrary tags. But the only currently used tag is `:group` which is used to optionally group components in PlantUML diagram.\n\n## Visualization and analysis\n\n```\ncd clean_mixer\nmix clean_mixer.plantuml -v\n```\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"578\" height=\"704\" src=\"https://raw.githubusercontent.com/miros/clean_mixer/master/clean_mixer_example.png\"\u003e\n\u003c/p\u003e\n\n**Render component dependencies in PlantUML:**\n\n```\nmix clean_mixer.plantuml\n```\n\n```\nmix clean_mixer.plantuml --help\n```\n\nYou can hide some components from diagram:\n```\nmix clean_mixer.plantuml --except=\"some-component,other-component\"\n```\n\nAlso render Hex dependencies of your components:\n```\nmix clean_mixer.plantuml --include-hex\n```\n\nRender metrics of links between components:\n```\nmix clean_mixer.plantuml -v\n```\n\nYou can group components by `:group` tag:\n```\nmix clean_mixer.plantuml --group\n```\n\nYou can filter list by source and target components:\n```\nmix clean_mixer.plantuml --sources=\"some/component\" --targets=\"other/component\"\n```\n\nYou can use wildcard:\n```\nmix clean_mixer.plantuml --sources=\"*some-pattern*\"\n```\n\nYou can filter by several components:\n```\nmix clean_mixer.plantuml --sources=\"some-component,other-component\"\n```\n\n**Metrics provided:**\n\nFor in depth description of metrics (in, out, I, A, D) and principles please refer to Bob Martin's “Clean Architecture” book (Chapter 14).\n\n* in = number of incoming dependencies on current component files\n* out = number of outgoing dependencies on other components files\n* I = instability = out / (in + out)\n* A = files_with_behaviours / total_files\n* D = Distance = |A + I - 1| (Distance from the Main Sequence)\n* Tf = total files = total number of files of current component\n* Pf = public files = number of files of current component used by others\n* Ain = Abstract in = number of incoming dependencies on current component behaviours\n* Aout = Abstract in = number of dependencies on other components behaviours\n* U = Usage = percent of current component files that are public (used by others)\n\nComponent links are coloured red on a diagram if the Stable Dependencies Principle (Depend in the direction of stability) is violated.\n\n**List all project components and their dependencies:**\n\n```\nmix clean_mixer.list\n```\n\n```\nmix clean_mixer.list --help\n```\n\nYou can include hex dependencies of your components:\n```\nmix clean_mixer.list --include-hex\n```\n\nYou can filter list by source and target components:\n```\nmix clean_mixer.list --sources=\"some/component\" --targets=\"other/component\"\n```\n\nYou can use wildcard:\n```\nmix clean_mixer.list --sources=\"*some-pattern*\"\n```\n\nYou can filter by several components:\n```\nmix clean_mixer.list --sources=\"some-component,other-component\"\n```\n\nYou can filter list by source and target dependencies between files:\n```\nmix clean_mixer.list --file-sources=\"*/file1.ex\" --file-targets=\"*/file2.ex\"\n```\n\n**List all project component usages:**\n\nShow components public files:\n```\nmix clean_mixer.list_usages\n```\n\nShow components public files and who uses them:\n```\nmix clean_mixer.list_usages -v\n```\n\n**List cycles in component dependencies:**\n\n```\nmix clean_mixer.component_cycles\n```\n\n**List cycles in all files:**\n\n```\nmix clean_mixer.file_cycles\n```\n\n**List behaviours and their implementations:**\n\n```\nmix clean_mixer.behaviours\n```\n\nYou can filter by behaviour:\n```\nmix clean_mixer.list -b \"*.Inspect\"\n```\n\nYou can filter by component:\n```\nmix clean_mixer.list -c \"some-component\"\n```\n\n## Validation\n\nYou can use `clean_mixer` internal API to make some basic assertions about projects architecture:\n\n```elixir\nExUnit.start(capture_log: true, trace: true)\n\ndefmodule ArchTest do\n  use ExUnit.Case\n\n  alias CleanMixer.Workspace\n\n  setup_all do\n    workspace = CleanMixer.workspace()\n    %{ws: workspace}\n  end\n\n  test \"there are shall be no cyclical dependencies between components\", %{ws: ws} do\n    assert Workspace.component_cycles(ws) == []\n  end\n\n  @adapters [\n    \"http-api\",\n    \"kafka-downstream\"\n  ]\n\n  for adapter \u003c- @adapters do\n    test \"domain shall not depend on adapter #{adapter}\", %{ws: ws} do\n      refute Workspace.dependency?(ws, \"app-domain\", unquote(adapter))\n    end\n  end\n\n  test \"`utils` shall have no dependencies\", %{ws: ws} do\n    assert Workspace.dependencies_of(ws, \"utils\") == []\n  end\n\nend\n```\n\nRun tests:\n\n```\nmix run --no-start test/arch_test.exs\n```\n\n## Copyright and License\n\nCopyright (c) 2019 Miroslav Malkin\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n[![Sponsored by FunBox](https://funbox.ru/badges/sponsored_by_funbox_centered.svg)](https://funbox.ru)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffunbox%2Fclean_mixer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffunbox%2Fclean_mixer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffunbox%2Fclean_mixer/lists"}