Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Monorepo w Allegro

Monorepo w Allegro

Prezentacja opowie o ewolucji projektu Allegro na platformę iOS. Historia zaczyna się ponad 6 lat temu od małego projektu w jednym repozytorium. Z czasem aplikacja rozrosła się i projekt rozbito na wiele repozytoriów. Dzisiaj, przy jeszcze większej skali, ponownie używamy jednego repozytorium. Podczas prezentacji poznacie strukturę projektu aplikacji Allegro, proces jej budowania i testowania. Dowiecie się o plusach i minusach stosowanych rozwiązań oraz naszych planach na przyszłość.

F993dbeef6dcba513da6f1acc04098ee?s=128

Aleksander Grzyb

September 24, 2018
Tweet

More Decks by Aleksander Grzyb

Other Decks in Programming

Transcript

  1. Monorepo w Allegro Allegro Tech Talks #12, Poznań Aleksander Grzyb,

    iOS Developer
  2. 2

  3. 3

  4. 4 Poznań 8 osób

  5. 5 Poznań 8 osób Wrocław 5 osób

  6. 6 Poznań 8 osób Wrocław 5 osób Warszawa 9 osób

  7. 7 github.com/AlDanial/cloc -------------------------------------------------------------------------------- Language             Files        Lines        Blank      Comment         Code -------------------------------------------------------------------------------- Objective-C           3939       397898        81232        31898      

    284768 C/C++ Header          3813       232674        39049        43800       149825 JSON                   838       137764          770            0       136994 Swift                 2538       178624        33677        15496       129451 Markdown               104        13464         3899            0         9565 Bourne Shell            48         3633          453          302         2878 Plain Text              14         1123          192            0          931 PHP                      1          849          182            6          661 Ruby                     5          608           74           15          519 Python                   6          440          101           27          312 CSS                      1          425           85          161          179 Awk                      1           60            4           13           43 YAML                     1           29            5            0           24 HTML                     2           23            3            0           20 -------------------------------------------------------------------------------- Total                11311       967614       159726        91718       716170 -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- Language             Files        Lines        Blank      Comment         Code -------------------------------------------------------------------------------- Objective-C           3939       397898        81232        31898       284768 C/C++ Header          3813       232674        39049        43800       149825 Swift                 2538       178624        33677        15496       129451
  8. 8 Separacja i reużywalność Produktywność Odpowiedzialność ⛓

  9. 9 Separacja i reużywalność ⛓ Produktywność Odpowiedzialność

  10. 10 Produktywność Separacja i reużywalność ⛓ Odpowiedzialność

  11. 11 Odpowiedzialność Separacja i reużywalność Produktywność ⛓

  12. 12 Stopień realizacji Czas

  13. 13 // // main.m // Allegro // // Created by

    Jakub Kuzimski on 22.08.2012. // Copyright (c) 2012 Jakub Kuzimski. All rights reserved. // #import <UIKit/UIKit.h> #import "APAppDelegate.h" int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([APAppDelegate class])); } } 22.08.2012
  14. 14

  15. 15 Separacja i reużywalność ❌ Produktywność Odpowiedzialność ❌ ❌

  16. 16 Separacja i reużywalność Produktywność ❌ ❌ Odpowiedzialność ❌

  17. 17 Separacja i reużywalność Produktywność Odpowiedzialność ❌ ❌ ❌

  18. 18 Allegro Strona oferty Strona główna Proces zakupowy Networking UI

  19. 19 Strona oferty

  20. 20 Strona oferty

  21. 21 Strona oferty

  22. 22 Strona oferty

  23. 23 Strona oferty

  24. 24 Strona oferty

  25. 25 OfferDetails.podspec Pod::Spec.new do |spec| spec.name = "OfferDetails" spec.version =

    "2.0.0" spec.summary = "Module is presenting offer details and related information." spec.source_files = ["OfferDetails/OfferDetails/**/*.{h,m,swift}"] spec.resource_bundle = { "Resources" => ["OfferDetails/OfferDetails/**/*.{xib,storyboard,lproj,xcassets}"] } spec.dependency "CoreModule", ">= 1" spec.dependency "AllegroCommons", ">= 2.4.0" spec.dependency "AllegroDynamicText", ">= 1.1.1" spec.dependency "NYTPhotoViewer", ">= 1.0.1" spec.dependency "JGProgressHUD", "1.4" spec.dependency "INSPullToRefresh", "1.1.5" spec.dependency "AllegroNetworking", ">= 2.6.0" spec.dependency "Metrum", ">= 0.22.0" end
  26. 26 OfferDetails.podspec Pod::Spec.new do |spec| spec.name = "OfferDetails" spec.version =

    "2.0.0" spec.summary = "Module is presenting offer details and related information." spec.source_files = ["OfferDetails/OfferDetails/**/*.{h,m,swift}"] spec.resource_bundle = { "Resources" => ["OfferDetails/OfferDetails/**/*.{xib,storyboard,lproj,xcassets}"] } spec.dependency "CoreModule", ">= 1" spec.dependency "AllegroCommons", ">= 2.4.0" spec.dependency "AllegroDynamicText", ">= 1.1.1" spec.dependency "NYTPhotoViewer", ">= 1.0.1" spec.dependency "JGProgressHUD", "1.4" spec.dependency "INSPullToRefresh", "1.1.5" spec.dependency "AllegroNetworking", ">= 2.6.0" spec.dependency "Metrum", ">= 0.22.0" end spec.source_files = ["OfferDetails/OfferDetails/**/*.{h,m,swift}"] spec.resource_bundle = { "Resources" => ["OfferDetails/OfferDetails/**/*.{xib,storyboard,lproj,xcassets}"] }
  27. 27 Pod::Spec.new do |spec| spec.name = "OfferDetails" spec.version = "2.0.0"

    spec.summary = "Module is presenting offer details and related information." spec.source_files = ["OfferDetails/OfferDetails/**/*.{h,m,swift}"] spec.resource_bundle = { "Resources" => ["OfferDetails/OfferDetails/**/*.{xib,storyboard,lproj,xcassets}"] } spec.dependency "CoreModule", ">= 1" spec.dependency "AllegroCommons", ">= 2.4.0" spec.dependency "AllegroDynamicText", ">= 1.1.1" spec.dependency "NYTPhotoViewer", ">= 1.0.1" spec.dependency "JGProgressHUD", "1.4" spec.dependency "INSPullToRefresh", "1.1.5" spec.dependency "AllegroNetworking", ">= 2.6.0" spec.dependency "Metrum", ">= 0.22.0" end spec.dependency "CoreModule", ">= 1" spec.dependency "AllegroCommons", ">= 2.4.0" spec.dependency "AllegroDynamicText", ">= 1.1.1" spec.dependency "NYTPhotoViewer", ">= 1.0.1" spec.dependency "JGProgressHUD", "1.4" spec.dependency "INSPullToRefresh", "1.1.5" spec.dependency "AllegroNetworking", ">= 2.6.0" spec.dependency "Metrum", ">= 0.22.0" OfferDetails.podspec
  28. 28 Pod::Spec.new do |spec| spec.name = "OfferDetails" spec.version = "2.0.0"

    spec.summary = "Module is presenting offer details and related information." spec.source_files = ["OfferDetails/OfferDetails/**/*.{h,m,swift}"] spec.resource_bundle = { "Resources" => ["OfferDetails/OfferDetails/**/*.{xib,storyboard,lproj,xcassets}"] } spec.dependency "CoreModule", ">= 1" spec.dependency "AllegroCommons", ">= 2.4.0" spec.dependency "AllegroDynamicText", ">= 1.1.1" spec.dependency "NYTPhotoViewer", ">= 1.0.1" spec.dependency "JGProgressHUD", "1.4" spec.dependency "INSPullToRefresh", "1.1.5" spec.dependency "AllegroNetworking", ">= 2.6.0" spec.dependency "Metrum", ">= 0.22.0" end spec.version = "2.0.0" OfferDetails.podspec
  29. 29 Allegro/Podfile source "https://allegro_git/pods.specs.git" source "https://github.com/CocoaPods/Specs" target "Allegro" do pod

    "Registration", "1.5.0" pod "Cart", "3.1.2" pod "OfferDetails", "2.0.0" (...) end ➕ pod update OfferDetails pod "OfferDetails", "2.0.0"
  30. 30 Allegro/Podfile source "https://allegro_git/pods.specs.git" source "https://github.com/CocoaPods/Specs" target "Allegro" do pod

    "Registration", "1.5.0" pod "Cart", "3.1.2" pod "OfferDetails", "2.0.0" (...) end ➕ pod update OfferDetails source "https://allegro_git/pods.specs.git"
  31. 31 Separacja i reużywalność Produktywność Odpowiedzialność ✅ ✅ ✅

  32. 32 Separacja i reużywalność Produktywność Odpowiedzialność ✅ ✅ ✅

  33. 33 Separacja i reużywalność Produktywność Odpowiedzialność ✅ ✅ ✅

  34. 34 Separacja i reużywalność Produktywność Odpowiedzialność ❌ ✅ ✅

  35. 35 Allegro Strona oferty Proces zakupowy Networking 1.0.0

  36. 36 Allegro Strona oferty Proces zakupowy Networking 1.0.1 Networking 1.0.0

  37. 37 Allegro Strona oferty Proces zakupowy Networking 1.0.1

  38. 38 Allegro Strona oferty Proces zakupowy Wyszukiwanie Rejestracja Networking 1.0.0

    Networking 1.0.5 UI 2.0.0 UI 2.2.0 UI 2.1.0 Networking 1.1.0
  39. 39

  40. 40 1. Przenieść kod z modułu strony oferty do AllegroCommons.

  41. 41 1. Przenieść kod z modułu strony oferty do AllegroCommons.

    2. Założyć PR do repozytorium AllegroCommons.
  42. 42 1. Przenieść kod z modułu strony oferty do AllegroCommons.

    2. Założyć PR do repozytorium AllegroCommons. 3. Wydać nowe AllegroCommons.
  43. 43 1. Przenieść kod z modułu strony oferty do AllegroCommons.

    2. Założyć PR do repozytorium AllegroCommons. 3. Wydać nowe AllegroCommons. 4. Uaktualnić AllegroCommons w module oferty.
  44. 44 1. Przenieść kod z modułu strony oferty do AllegroCommons.

    2. Założyć PR do repozytorium AllegroCommons. 3. Wydać nowe AllegroCommons. 4. Uaktualnić AllegroCommons w module oferty. 5. Uaktualnić AllegroCommons w module procesu zakupowego.
  45. 45 (...) <<<<<<< HEAD PODFILE CHECKSUM: 15f6bd662808121403ea733c7263b90e7b912840 ======= PODFILE CHECKSUM:

    4c795d243895a6e7905e0606b06679090f723b4a >>>>>>> develop └── Allegro ├── Allegro ├── Allegro.xcodeproj ├── Allegro.xcworkspace ├── AllegroStubbedUITests ├── AllegroTests ├── Podfile ├── Podfile.lock ├── Pods.xcodeproj ├── Pods │ ├── ... │ ├── Manifest.lock │ └── ... └── fastlane Allegro/Podfile.lock ├── Podfile.lock ├── Pods.xcodeproj │ ├── Manifest.lock
  46. 46

  47. 47 Konflikty w plikach CocoaPods ⚔ Piekło wersjonowania Wydzielenie reużywalnego

    kodu ♻
  48. 48 Konflikty w plikach CocoaPods ⚔ Piekło wersjonowania Wydzielenie reużywalnego

    kodu ♻
  49. 49 Konflikty w plikach CocoaPods ⚔ Piekło wersjonowania Wydzielenie reużywalnego

    kodu ♻
  50. 50 Konflikty w plikach CocoaPods ⚔ Piekło wersjonowania Wydzielenie reużywalnego

    kodu ♻
  51. 51

  52. 52

  53. 53

  54. 54 ├── Allegro │ ├── Allegro │ ├── Allegro.xcodeproj │

    ├── Allegro.xcworkspace │ ├── AllegroStubbedUITests │ ├── AllegroTests │ ├── Podfile │ ├── Podfile.lock │ ├── Pods │ └── fastlane ├── AllegroModules │ ├── Cart │ ├── Comments │ ├── CrossSell │ ├── ListingModule │ ├── LoyaltyProgram │ ├── MyOrders │ ├── Networking │ ├── Observed │ ├── OfferComparison │ ├── OfferDetails │ ├── Opbox │ ├── Origami │ ├── Registration │ ├── Routings │ └── Search └── fastlane └── Fastfile
  55. 55 ├── Allegro │ ├── Allegro │ ├── Allegro.xcodeproj │

    ├── Allegro.xcworkspace │ ├── AllegroStubbedUITests │ ├── AllegroTests │ ├── Podfile │ ├── Podfile.lock │ ├── Pods │ └── fastlane ├── AllegroModules │ ├── Cart │ ├── Comments │ ├── CrossSell │ ├── ListingModule │ ├── LoyaltyProgram │ ├── MyOrders │ ├── Networking │ ├── Observed │ ├── OfferComparison │ ├── OfferDetails │ ├── Opbox │ ├── Origami │ ├── Registration │ ├── Routings │ └── Search └── fastlane └── Fastfile ├── Allegro │ ├── Allegro │ ├── Allegro.xcodeproj │ ├── Allegro.xcworkspace │ ├── AllegroStubbedUITests │ ├── AllegroTests │ ├── Podfile │ ├── Podfile.lock │ ├── Pods │ └── fastlane
  56. 56 ├── Allegro │ ├── Allegro │ ├── Allegro.xcodeproj │

    ├── Allegro.xcworkspace │ ├── AllegroStubbedUITests │ ├── AllegroTests │ ├── Podfile │ ├── Podfile.lock │ ├── Pods │ └── fastlane ├── AllegroModules │ ├── Cart │ ├── Comments │ ├── CrossSell │ ├── ListingModule │ ├── LoyaltyProgram │ ├── MyOrders │ ├── Networking │ ├── Observed │ ├── OfferComparison │ ├── OfferDetails │ ├── Opbox │ ├── Origami │ ├── Registration │ ├── Routings │ └── Search └── fastlane └── Fastfile ├── AllegroModules │ ├── Cart │ ├── Comments │ ├── CrossSell │ ├── ListingModule │ ├── LoyaltyProgram │ ├── MyOrders │ ├── Networking │ ├── Observed │ ├── OfferComparison │ ├── OfferDetails │ ├── Opbox │ ├── Origami │ ├── Registration │ ├── Routings │ └── Search
  57. 57 git remote add MODULE-origin https://allegro_git/iosmodules/MODULE.git git fetch MODULE-origin git

    merge --allow-unrelated-histories MODULE-origin/develop git remote remove MODULE-origin git push origin
  58. 58 git remote add MODULE-origin https://allegro_git/iosmodules/MODULE.git git fetch MODULE-origin git

    merge --allow-unrelated-histories MODULE-origin/develop git remote remove MODULE-origin git push origin --allow-unrelated-histories
  59. 59 (...) target :OfferDetails do project '../AllegroModules/OfferDetails/OfferDetails.xcodeproj' workspace 'Allegro' pod_OfferDetailsDependencies

    target :OfferDetailsTests do inherit! :search_paths pod_FBSnapshotTest pod_CommonPodsForTargetsWithTests end end (...) ├── Allegro │ ├── Allegro │ ├── Allegro.xcodeproj │ ├── Allegro.xcworkspace │ ├── AllegroStubbedUITests │ ├── AllegroTests │ ├── Podfile │ ├── Podfile.lock │ ├── Pods │ └── fastlane ├── AllegroModules │ ├── ... │ ├── OfferDetails │ │ ├── OfferDetails │ │ ├── OfferDetails.xcodeproj │ │ ├── OfferDetailsTests │ │ └── fastlane │ ├── ... └── fastlane └── Fastfile Allegro/Podfile │ ├── Podfile
  60. 60

  61. 61

  62. 62 sh "git fetch origin -u +#{destination_branch}:#{destination_branch}" destination_branch_commit = sh("git

    ls-remote https://allegro.git #{destination_branch} | awk '{print $1;}'") branch_commit = sh("git rev-parse HEAD") changed_files_paths = sh("git diff --name-only #{diff_range}").split("\n") changed_files_paths.each do |changed_file_path| projects_list.each do |project| project.diff_detection_paths.each do |diff_detection_path| if changed_file_path.start_with? diff_detection_path projects_to_test.add(project) end end end end projects_to_test.each do |project_to_test| Dir.chdir(project_to_test.path) do runner.execute(project_to_test.test_action, :ios) end end fastlane/Fastfile
  63. 63 sh "git fetch origin -u +#{destination_branch}:#{destination_branch}" destination_branch_commit = sh("git

    ls-remote https://allegro.git #{destination_branch} | awk '{print $1;}'") branch_commit = sh("git rev-parse HEAD") changed_files_paths = sh("git diff --name-only #{diff_range}").split("\n") changed_files_paths.each do |changed_file_path| projects_list.each do |project| project.diff_detection_paths.each do |diff_detection_path| if changed_file_path.start_with? diff_detection_path projects_to_test.add(project) end end end end projects_to_test.each do |project_to_test| Dir.chdir(project_to_test.path) do runner.execute(project_to_test.test_action, :ios) end end fastlane/Fastfile sh "git fetch origin -u +#{destination_branch}:#{destination_branch}" destination_branch_commit = sh("git ls-remote https://allegro.git #{destination_branch} | awk '{print $1;}'") branch_commit = sh("git rev-parse HEAD")
  64. 64 sh "git fetch origin -u +#{destination_branch}:#{destination_branch}" destination_branch_commit = sh("git

    ls-remote https://allegro.git #{destination_branch} | awk '{print $1;}'") branch_commit = sh("git rev-parse HEAD") changed_files_paths = sh("git diff --name-only #{diff_range}").split("\n") changed_files_paths.each do |changed_file_path| projects_list.each do |project| project.diff_detection_paths.each do |diff_detection_path| if changed_file_path.start_with? diff_detection_path projects_to_test.add(project) end end end end projects_to_test.each do |project_to_test| Dir.chdir(project_to_test.path) do runner.execute(project_to_test.test_action, :ios) end end fastlane/Fastfile changed_files_paths = sh("git diff --name-only #{diff_range}").split("\n")
  65. 65 sh "git fetch origin -u +#{destination_branch}:#{destination_branch}" destination_branch_commit = sh("git

    ls-remote https://allegro.git #{destination_branch} | awk '{print $1;}'") branch_commit = sh("git rev-parse HEAD") changed_files_paths = sh("git diff --name-only #{diff_range}").split("\n") changed_files_paths.each do |changed_file_path| projects_list.each do |project| project.diff_detection_paths.each do |diff_detection_path| if changed_file_path.start_with? diff_detection_path projects_to_test.add(project) end end end end projects_to_test.each do |project_to_test| Dir.chdir(project_to_test.path) do runner.execute(project_to_test.test_action, :ios) end end fastlane/Fastfile changed_files_paths.each do |changed_file_path| projects_list.each do |project| project.diff_detection_paths.each do |diff_detection_path| if changed_file_path.start_with? diff_detection_path projects_to_test.add(project) end end end end
  66. 66 sh "git fetch origin -u +#{destination_branch}:#{destination_branch}" destination_branch_commit = sh("git

    ls-remote https://allegro.git #{destination_branch} | awk '{print $1;}'") branch_commit = sh("git rev-parse HEAD") changed_files_paths = sh("git diff --name-only #{diff_range}").split("\n") changed_files_paths.each do |changed_file_path| projects_list.each do |project| project.diff_detection_paths.each do |diff_detection_path| if changed_file_path.start_with? diff_detection_path projects_to_test.add(project) end end end end projects_to_test.each do |project_to_test| Dir.chdir(project_to_test.path) do runner.execute(project_to_test.test_action, :ios) end end fastlane/Fastfile changed_files_paths.each do |changed_file_path| projects_list.each do |project| project.diff_detection_paths.each do |diff_detection_path| if changed_file_path.start_with? diff_detection_path projects_to_test.add(project) end end end end
  67. 67 sh "git fetch origin -u +#{destination_branch}:#{destination_branch}" destination_branch_commit = sh("git

    ls-remote https://allegro.git #{destination_branch} | awk '{print $1;}'") branch_commit = sh("git rev-parse HEAD") changed_files_paths = sh("git diff --name-only #{diff_range}").split("\n") changed_files_paths.each do |changed_file_path| projects_list.each do |project| project.diff_detection_paths.each do |diff_detection_path| if changed_file_path.start_with? diff_detection_path projects_to_test.add(project) end end end end fastlane/Fastfile changed_files_paths.each do |changed_file_path| projects_list.each do |project| project.diff_detection_paths.each do |diff_detection_path| if changed_file_path.start_with? diff_detection_path projects_to_test.add(project) end end end end ["AllegroModules/OfferDetails", "AllegroModules/Origami", "AllegroModules/CrossSell", "Allegro/Pods/Metrum", "AllegroModules/Networking", "Allegro/Pods/AllegroCommons"]
  68. 68 sh "git fetch origin -u +#{destination_branch}:#{destination_branch}" destination_branch_commit = sh("git

    ls-remote https://allegro.git #{destination_branch} | awk '{print $1;}'") branch_commit = sh("git rev-parse HEAD") changed_files_paths = sh("git diff --name-only #{diff_range}").split("\n") changed_files_paths.each do |changed_file_path| projects_list.each do |project| project.diff_detection_paths.each do |diff_detection_path| if changed_file_path.start_with? diff_detection_path projects_to_test.add(project) end end end end projects_to_test.each do |project_to_test| Dir.chdir(project_to_test.path) do runner.execute(project_to_test.test_action, :ios) end end fastlane/Fastfile projects_to_test.each do |project_to_test| Dir.chdir(project_to_test.path) do runner.execute(project_to_test.test_action, :ios) end end
  69. 69

  70. 70

  71. 71

  72. 72 ├── Allegro ├── AllegroModules ├── Toolset │ ├── SwiftFormat

    │ │ ├── run_swiftformat.sh │ │ ├── run_swiftformat_in_modules.sh │ │ └── swiftformat-0.30.2 │ ├── SwiftLint │ │ ├── run_swiftlint.sh │ │ └── swiftlint-0.25.0 │ └── clang-format │ ├── clang-format │ ├── reformat_all.sh │ └── run_clang_format.sh └── ... github.com/nicklockwood/SwiftFormat github.com/realm/SwiftLint clang.llvm.org/docs/ClangFormat.html
  73. 73 ├── Allegro ├── AllegroModules ├── Configuration │ ├── Project-Debug.xcconfig

    │ ├── Project-Lab.xcconfig │ ├── Project-Release.xcconfig │ └── Project-Shared.xcconfig └── ...
  74. 74

  75. 75 Allegro/Podfile post_install do | installer | Dir["../AllegroModules/*/"].map { |a|

    File.basename(a) }.each do |filePath| Dir.glob(File.join("Pods", "**", "Pods-#{filePath}.debug.xcconfig")).each do |file| File.open(file, 'a') { |f| f.puts "\n#include \"../../Configuration/Project-Debug.xcconfig\" " } end (...) end (...) end
  76. 76 (...) PODS_PODFILE_DIR_PATH = ${SRCROOT}/../../Allegro PODS_ROOT = ${SRCROOT}/../../Allegro/Pods #include "../../Configuration/Project-Debug.xcconfig"

    Allegro/Pods/Target Support Files/Pods-OfferDetails/Pods-OfferDetails.debug.xcconfig #include "../../Configuration/Project-Debug.xcconfig" #include \"../../Configuration/Project-Debug.xcconfig\" Allegro/Podfile post_install do | installer | Dir["../AllegroModules/*/"].map { |a| File.basename(a) }.each do |filePath| Dir.glob(File.join("Pods", "**", "Pods-#{filePath}.debug.xcconfig")).each do |file| File.open(file, 'a') { |f| f.puts "\n#include \"../../Configuration/Project-Debug.xcconfig\" " } end (...) end (...) end
  77. 77 + ,

  78. 78

  79. 79

  80. 80 Separacja i reużywalność Produktywność Odpowiedzialność ✅ ✅ ✅

  81. 81 Separacja i reużywalność Produktywność Odpowiedzialność ✅ ✅ ✅

  82. 82 Separacja i reużywalność Produktywność Odpowiedzialność ✅ ✅ ✅

  83. 83

  84. 84 https://engineering.shopify.com/blogs/engineering/mobile-tophatting-at-shopify-1

  85. 85

  86. 86 Ciekawe źródła • Faster Together: Uber Engineering’s iOS Monorepo

    • Why Google Stores Billions of Lines of Code in a Single Repository • µFeatures Guidelines
  87. 87 Q&A aleksander.grzyb@allegro.pl