Najlepsze rozwiązania dotyczące dużych rozwiązań w programie Visual Studio (2008) [zamknięte]

87

Mamy rozwiązanie z ponad 100 projektami, większość z nich C #. Oczywiście zarówno otwieranie, jak i budowanie zajmuje dużo czasu, dlatego szukam najlepszych praktyk dla takich bestii. Wśród pytań, na które mam nadzieję uzyskać odpowiedzi, są:

  • jak najlepiej radzić sobie z odwołaniami między projektami
    • czy „kopiuj lokalnie” powinno być włączone czy wyłączone?
  • czy każdy projekt powinien być kompilowany do własnego folderu, czy też wszystkie powinny być kompilowane do tego samego folderu wyjściowego (wszystkie są częścią tej samej aplikacji)

  • Czy foldery rozwiązań to dobry sposób na porządkowanie rzeczy?

Wiem, że podzielenie rozwiązania na wiele mniejszych jest opcją, ale wiąże się to z własnym zestawem refaktoryzacji i problemów związanych z budowaniem, więc może możemy to zapisać na osobny wątek :-)

Eyvind
źródło
2
Czy mogę zapytać, dlaczego jedno rozwiązanie wymaga ponad 100 projektów? Czy każdy z nich tworzy swój własny zespół?
Neil N,
1
Tak, są, a każdy z nich reprezentuje logicznie odrębną część funkcjonalności.
Eyvind,
2
@Eyvind - Czy nie po to są klasy i przestrzenie nazw? Jakie korzyści przynoszą oddzielne zespoły? Przychodzą mi na myśl niektóre, takie jak potencjalnie mniejsze aktualizacje i użycie pamięci (jeśli niektóre nie są załadowane), ale z pewnością istnieje koszt posiadania ponad 100 zestawów do kompilacji i zarządzania.
si618
1
@Mark, czuję twój ból. Mamy tu do 94 projektów. Nie mogę teraz wiele z tym zrobić, ponieważ musielibyśmy zatrzymać rozwój wielu zespołów w celu restrukturyzacji. Mamy 3 projekty EXE, które odwołują się do innych 91. Eksperymentuję z jednym wspólnym folderem wyjściowym, jak dotąd zyski są imponujące.
Kevin
2
Mężczyzna, ponad 100 lat? To nic z tego, co mamy ... popychamy teraz prawie 600 ...
C Johnson,

Odpowiedzi:

41

Możesz być zainteresowany tymi dwoma artykułami MSBuild, które napisałem.

MSBuild: najlepsze praktyki tworzenia niezawodnych kompilacji, część 1

MSBuild: najlepsze praktyki tworzenia niezawodnych kompilacji, część 2

W szczególności w części 2 znajduje się sekcja Budowanie dużych drzew źródłowych , której warto się przyjrzeć.

Aby jednak krótko odpowiedzieć na pytania tutaj:

  • CopyLocal? Na pewno to wyłącz
  • Skompilować do jednego lub wielu folderów wyjściowych? Kompiluj do jednego folderu wyjściowego
  • Foldery rozwiązań? To kwestia gustu.

Sayed Ibrahim Hashimi

Moja książka: Inside the Microsoft Build Engine: Korzystanie z MSBuild i Team Foundation Build

Sayed Ibrahim Hashimi
źródło
Dzięki stary, na pewno je sprawdzę!
Eyvind
1
Powiem, że mam tę książkę i jest niesamowita. Pomogło mi to zautomatyzować moje kompilacje TFS i bardzo intensywnie kompilacje lokalnego dewelopera. Pracuję teraz nad kompilacjami przyrostowymi i książka bardzo dogłębnie zagłębia się w ten temat. Wart ceny. Dziękuję. Kontynuuj wspaniałą pracę.
irperez
Dzięki irperez za komentarze
Ibrahim Hashimi
2
-1 dla UNCONDITIONAL zalecenia, aby wyłączyć CopyLocal. Ustawienie CopyLocal = false może powodować różne problemy w czasie wdrażania. Zobacz mój post na blogu „Nie zmieniaj odniesień do projektu„ Kopiuj lokalnie ”na fałsz, chyba że rozumiesz podciągi.” ( Geekswithblogs.net/mnf/archive/2012/12/09/… )
Michael Freidgeim,
Czy „kompilacja do jednego folderu wyjściowego” może powodować problemy podczas kompilowania z wieloma wątkami?
BrunoLM
9

+1 za oszczędne korzystanie z folderów rozwiązań, które ułatwiają porządkowanie rzeczy.

+1 za tworzenie projektu do własnego folderu. Początkowo próbowaliśmy wspólnego folderu wyjściowego, co może prowadzić do subtelnych i bolesnych znalezienia nieaktualnych odniesień.

FWIW, używamy referencji projektowych do rozwiązań i chociaż nuget jest obecnie prawdopodobnie lepszym wyborem, odkryliśmy, że svn: externals działa dobrze zarówno w przypadku zespołów zewnętrznych, jak i wewnętrznych (typu framework). Po prostu nabądź nawyku używania określonego numeru wersji zamiast HEAD podczas odwoływania się do svn: externals (winny za opłatą :)

si618
źródło
2
+1 Mam również problemy ze wspólnym rozwiązaniem folderu wyjściowego. Nie rozumiem, co oznacza „referencje projektu dla rozwiązań”, proszę wyjaśnić trochę więcej ...
Mauricio Scheffer
Tak jak w używamy VS-> Dodaj odniesienie-> Projekty, zamiast VS-> Dodaj odniesienie-> Przeglądaj. Mała kwestia, którą znam, ale niektórzy ludzie robią to inaczej (i myślę, że powoduje to więcej bólów głowy). Jeśli spojrzysz na tekst MSBuild csproj, zobaczysz właściwość ProjectReference zamiast Reference.
si618
Ciekawa odpowiedź! Myślę, że szliśmy zygzakiem w miejscu, w którym się poruszałeś. W ogóle nie mamy folderów rozwiązań i polegamy na nazewnictwie projektów (projekty są nazywane tak samo, jak przestrzeń nazw). Wszystkie nasze dane wyjściowe trafiają do jednego folderu, co sprawia, że ​​konfiguracja programisty jest znacznie bliższa konfiguracji wdrożenia. Jeśli zależności są ustawione poprawnie, nie mamy nieaktualnych odniesień.
Thomas Bratt
tak, wspólny katalog wyjściowy prowadzi do wielu problemów, szczególnie podczas używania resharper. Rzeczywiście nieaktualne odniesienia.
Florian Doyon
1
@Kevin, minęło już kilka lat, ale z pamięci jeden przykład to dwa projekty odwołujące się do tego samego zestawu, powiedzmy, że biblioteka zewnętrzna nie jest przywoływana do projektu. Wszystko w porządku, gdy są w tej samej wersji, ale potem pojawia się nowe wydanie tej biblioteki, ale tylko jeden projekt aktualizuje ich odniesienie, która wersja jest używana we wspólnym folderze wyjściowym?
si618
8

Zwolnij projekty, których nie używasz często, i kup dysk SSD. Dysk SSD nie skraca czasu kompilacji, ale program Visual Studio dwukrotnie szybciej otwiera / zamyka / kompiluje.

Nicolas Dorier
źródło
3
Warto zauważyć, że zwalnianie projektu jest ustawieniem na użytkownika, więc programiści w Twoim zespole mogą ładować tylko te projekty, na których im zależy. To naprawdę pomogło naszemu zespołowi.
Strona
Możesz użyć rozszerzenia Solution Load Manager visualstudiogallery.msdn.microsoft.com/…, aby zdefiniować, czego nie ładować domyślnie
Michael Freidgeim,
6

Mamy podobny problem, ponieważ mamy do rozwiązania 109 oddzielnych projektów. Aby odpowiedzieć na oryginalne pytania oparte na naszych doświadczeniach:

1. Jak najlepiej radzić sobie z odniesieniami między projektami

Używamy opcji menu kontekstowego „dodaj odniesienie”. W przypadku wybrania opcji „projekt” zależność zostanie dodana do naszego pojedynczego, globalnego pliku rozwiązania.

2. Czy „kopiuj lokalnie” powinno być włączone czy wyłączone?

Z naszego doświadczenia. Dodatkowe kopiowanie po prostu wydłuża czas kompilacji.

3. Czy każdy projekt powinien być kompilowany do własnego folderu, czy też wszystkie powinny budować do tego samego folderu wyjściowego (wszystkie są częścią tej samej aplikacji)

Wszystkie nasze wyniki są umieszczane w jednym folderze o nazwie „bin”. Chodzi o to, że ten folder jest taki sam, jak podczas wdrażania oprogramowania. Pomaga to uniknąć problemów, które występują, gdy konfiguracja dewelopera różni się od konfiguracji wdrożenia.

4. Czy foldery rozwiązań to dobry sposób na porządkowanie rzeczy?

Nie z naszego doświadczenia. Struktura folderów jednej osoby jest koszmarem innej osoby. Głęboko zagnieżdżone foldery tylko wydłużają czas potrzebny na znalezienie czegokolwiek. Mamy całkowicie płaską strukturę, ale tak samo nazywamy nasze pliki projektu, zestawy i przestrzenie nazw.


Nasz sposób tworzenia struktury projektów opiera się na jednym pliku rozwiązania. Budowa tego zajmuje dużo czasu, nawet jeśli same projekty się nie zmieniły. Aby w tym pomóc, zwykle tworzymy kolejny plik rozwiązania „aktualnego zestawu roboczego”. Wszelkie projekty, nad którymi pracujemy, są do tego dodawane. Czasy kompilacji uległy znacznej poprawie, chociaż jednym z problemów, które widzieliśmy, jest to, że Intellisense nie działa w przypadku typów zdefiniowanych w projektach, które nie znajdują się w bieżącym zestawie.

Częściowy przykład układu naszego rozwiązania:

\bin

OurStuff.SLN

OurStuff.App.Administrator
OurStuff.App.Common
OurStuff.App.Installer.Database
OurStuff.App.MediaPlayer
OurStuff.App.Operator
OurStuff.App.Service.Gateway
OurStuff.App.Service.CollectionStation
OurStuff.App.ServiceLocalLauncher
OurStuff.App.StackTester
OurStuff.Auditing
OurStuff.Data
OurStuff.Database
OurStuff.Database.Constants
OurStuff.Database.ObjectModel
OurStuff.Device
OurStuff.Device.Messaging
OurStuff.Diagnostics
...
[etc]
Thomas Bratt
źródło
Czy „kompilacja do jednego folderu wyjściowego” może powodować problemy podczas kompilowania z wieloma wątkami?
BrunoLM
4

Pracujemy tutaj nad podobnym dużym projektem. Foldery rozwiązań okazały się dobrym sposobem organizowania rzeczy i zwykle pozostawiamy ustawienie opcji kopiowania lokalnego na true. Każdy projekt jest kompilowany do własnego folderu, a następnie wiemy, że dla każdego projektu, który można wdrożyć, mamy w nim odpowiedni podzbiór plików binarnych.

Jeśli chodzi o czas otwierania i budowania czasu, będzie to trudne do naprawienia bez włamywania się do mniejszych rozwiązań. Możesz zbadać zrównoleglenie kompilacji (google „Parallel MS Build”, aby to zrobić i zintegrować z interfejsem użytkownika), aby poprawić tutaj szybkość. Przyjrzyj się również projektowi i zobacz, czy refaktoryzacja niektórych projektów w celu zmniejszenia ogólnej może pomóc.

David M.
źródło
3

Jeśli chodzi o złagodzenie problemów związanych z budowaniem, możesz użyć opcji „Menedżer konfiguracji…” dla kompilacji, aby włączyć lub wyłączyć tworzenie określonych projektów. Możesz mieć opcję „Projekt [n] Kompilacja”, która może wykluczać określone projekty i używać jej, gdy kierujesz reklamy na określone projekty.

Jeśli chodzi o ponad 100 projektów, wiem, że nie chcesz zostać wkurzony w to pytanie o korzyści płynące z zmniejszenia rozmiaru rozwiązania, ale myślę, że nie masz innej opcji, jeśli chodzi o przyspieszenie czasu ładowania (i wykorzystanie pamięci) programu devenv.

Michael Meadows
źródło
Hm, czy to zostało odrzucone za błąd, czy tylko za brak zgody? Mogę żyć z tym pierwszym, jeśli możesz mi powiedzieć dlaczego.
Michael Meadows,
Zgadzam się, nie lubię oddawać głosów bez komentarza, więc Michael dostaniesz moje +1, aby zrównoważyć równanie ;-)
si618
2
przy okazji, osobiście nie lubię grzebać w zarządzaniu konfiguracją w tego typu sprawach. Czemu? ponieważ jeśli przypadkowo zatwierdzisz zmodyfikowaną konfigurację, wpłynie to na serwer kompilacji lub innych programistów.
si618
Zgoda. W rzeczywistości ten sam problem dotyczy rozwiązań obejmujących zbyt wiele projektów. :)
Michael Meadows,
3

To, co zwykle z tym robię, zależy nieco od tego, jak faktycznie przebiega proces „debugowania”. Zazwyczaj jednak NIE ustawiam kopiowania lokalnego na true. Konfiguruję katalog kompilacji dla każdego projektu, aby wyprowadzić wszystko do żądanego punktu końcowego.

Dlatego po każdej kompilacji mam zapełniony folder ze wszystkimi bibliotekami dll i aplikacjami Windows / Web, a wszystkie elementy znajdują się we właściwej lokalizacji. Kopiowanie lokalne nie było potrzebne, ponieważ dll ostatecznie trafia we właściwe miejsce.

Uwaga

Powyższe działa dla moich rozwiązań, które zazwyczaj są aplikacjami internetowymi i nie miałem żadnych problemów z odwołaniami, ale może to być możliwe!

Mitchel Sellers
źródło
3

Mamy podobny problem. Rozwiązujemy to za pomocą mniejszych rozwiązań. Mamy mistrzowskie rozwiązanie, które otwiera wszystko. Ale perf. na tym jest źle. Dlatego dzielimy mniejsze rozwiązania według typu programisty. Tak więc programiści DB mają rozwiązanie, które ładuje projekty, na których im zależy, programiści usług i programiści UI to samo. Rzadko zdarza się, aby ktoś musiał otworzyć całe rozwiązanie, aby wykonać to, czego potrzebuje na co dzień. To nie jest panaceum - ma swoje wady i zalety. Zobacz „Model wielu rozwiązań” w tym artykule (zignoruj ​​część dotyczącą korzystania z usługi VSS :)

JP Alioto
źródło
2

Myślę, że przy tak dużych rozwiązaniach najlepszą praktyką powinno być ich rozbicie. Możesz myśleć o „rozwiązaniu” jako o miejscu, w którym zebrane zostaną niezbędne projekty i być może inne elementy do pracy nad rozwiązaniem problemu. Dzieląc ponad 100 projektów na wiele rozwiązań wyspecjalizowanych w opracowywaniu rozwiązań tylko dla części ogólnego problemu, możesz zająć się mniej w danym momencie, przyspieszając interakcje z wymaganymi projektami i upraszczając dziedzinę problemów.

Każde rozwiązanie dawałoby wynik, za który jest odpowiedzialne. Te dane wyjściowe powinny zawierać informacje o wersji, które można ustawić w zautomatyzowanym procesie. Gdy wynik jest stabilny, można zaktualizować odniesienia w zależnych projektach i rozwiązaniach za pomocą najnowszej dystrybucji wewnętrznej. Jeśli nadal chcesz wejść do kodu i uzyskać dostęp do źródła, możesz to zrobić za pomocą serwera symboli firmy Microsoft, którego program Visual Studio może użyć, aby umożliwić wejście do zestawów, do których istnieją odwołania, a nawet pobranie kodu źródłowego.

Równoczesne programowanie można wykonać, określając interfejsy z góry i mockując zestawy w trakcie opracowywania, gdy czekasz na zależności, które nie są kompletne, ale chcesz je opracować.

Uważam, że jest to najlepsza praktyka, ponieważ nie ma ograniczeń co do tego, jak złożony może być ogólny wysiłek, gdy rozbijesz go fizycznie w ten sposób. Umieszczenie wszystkich projektów w jednym rozwiązaniu ostatecznie osiągnie górny limit.

Mam nadzieję, że te informacje pomogą.

Blake Taylor
źródło
2

Mamy ponad 60 projektów i nie używamy plików rozwiązań. Mamy połączenie projektów C # i VB.Net. Wydajność zawsze była problemem. Nie pracujemy nad wszystkimi projektami jednocześnie. Każdy programista tworzy własne pliki rozwiązań na podstawie projektów, nad którymi pracuje. Pliki rozwiązania nie są wpisywane do naszej kontroli źródła.

Wszystkie projekty bibliotek klas byłyby kompilowane do folderu CommonBin w katalogu głównym katalogu źródłowego. Pliki wykonywalne / projekty internetowe są tworzone w ich indywidualnych folderach.

Nie używamy odwołań do projektów, zamiast tego odwołujemy się do plików z folderu CommonBin. Napisałem niestandardowe zadanie MSBuild, które będzie sprawdzać projekty i określać kolejność kompilacji.

Używamy tego od kilku lat i nie mamy żadnych skarg.

Vasu Balakrishnan
źródło
3
Czy mógłbyś udostępnić swoje niestandardowe zadanie msbuild?
andreapier
0

Wszystko to ma związek z twoją definicją i poglądem na to, czym jest rozwiązanie i projekt. Moim zdaniem rozwiązaniem jest po prostu logiczne pogrupowanie projektów, które rozwiązują bardzo specyficzne wymagania. Tworzymy dużą aplikację intranetową. Każda aplikacja w tym intranecie ma własne rozwiązanie, które może również zawierać projekty dla usług exes lub Windows. Następnie mamy scentralizowany framework z takimi rzeczami jak klasy bazowe i pomocniki oraz httphandlers / httpmodules. Podstawowa struktura jest dość duża i jest używana przez wszystkie aplikacje. Dzieląc w ten sposób wiele rozwiązań, zmniejszasz liczbę projektów wymaganych przez rozwiązanie, ponieważ większość z nich nie ma ze sobą nic wspólnego.

Posiadanie tak wielu projektów w rozwiązaniu to po prostu zły projekt. Nie powinno być powodu, aby mieć tyle projektów w ramach rozwiązania. Innym problemem, który widzę, są referencje do projektów, które w końcu mogą cię naprawdę schrzanić, zwłaszcza jeśli kiedykolwiek zechcesz podzielić swoje rozwiązanie na mniejsze.

Radzę to zrobić i opracować scentralizowaną strukturę (jeśli wolisz, własną implementację biblioteki korporacyjnej). Możesz udostępnić go GAC lub bezpośrednio odwołać się do lokalizacji pliku, aby mieć centralny magazyn. Tej samej taktyki można użyć również dla scentralizowanych obiektów biznesowych.

Jeśli chcesz bezpośrednio odwołać się do biblioteki DLL, będziesz chciał odwołać się do niej w swoim projekcie za pomocą copy local false (gdzieś na przykład c: \ mycompany \ bin \ mycompany.dll). W środowisku wykonawczym musisz dodać pewne ustawienia do pliku app.config lub web.config, aby odwoływał się do pliku, którego nie ma w GAC lub bin środowiska wykonawczego. W rzeczywistości nie ma znaczenia, czy jest to kopia lokalna, czy nie, lub czy dll trafi do bin, czy nawet w GAC, ponieważ konfiguracja zastąpi oba z nich. Myślę, że kopiowanie lokalnego i niechlujny system jest złą praktyką. Najprawdopodobniej będziesz musiał tymczasowo skopiować plik lokalny, jeśli chcesz debugować w jednym z tych zestawów.

Możesz przeczytać mój artykuł o tym, jak używać biblioteki DLL na całym świecie bez GAC. Naprawdę nie podoba mi się GAC głównie dlatego, że zapobiega wdrażaniu xcopy i nie powoduje automatycznego ponownego uruchomienia aplikacji.

http://nbaked.wordpress.com/2010/03/28/gac-alternative/

user306031
źródło
0

Ustawienie CopyLocal = false skróci czas kompilacji, ale może powodować różne problemy w czasie wdrażania.

Istnieje wiele scenariuszy, w których musisz ustawić opcję Copy Local na True, np. Projekty najwyższego poziomu, zależności drugiego poziomu, biblioteki DLL wywoływane przez odbicie.

Moje doświadczenie z ustawieniem CopyLocal = false nie powiodło się. Zobacz podsumowanie zalet i wad w moim poście na blogu „Nie zmieniaj odniesień do projektu„ Kopiuj lokalnie ”na fałszywe, chyba że rozumiesz podciągi”.

Michael Freidgeim
źródło