Obecnie zarządzam biblioteką, która ma wiele zastosowań publicznych, i miałem pytanie dotyczące wersji semantycznej . Chcę refaktoryzować jedną dość ważną część biblioteki, która jest niepoprawnie zaimplementowana - i zawsze była niepoprawnie zaimplementowana. Ale zrobienie tego oznaczałoby zmiany w publicznym interfejsie API, co jest poważną decyzją.
Zmiana, którą chcę wprowadzić, dotyczy sposobu używania iteratorów. Obecnie użytkownicy muszą to zrobić:
while ($element = $iterator->next()) {
// ...
}
Co jest niepoprawne, przynajmniej w natywnym interfejsie Iteratora PHP . Chcę to zastąpić:
while ($iterator->valid()) {
$element = $iterator->current();
// ...
$iterator->next();
}
który jest analogiczny do:
foreach ($iterator as $element) {
// ...
}
Jeśli spojrzysz na przewodnik Toma dotyczący wersjonowania semantycznego, wyraźnie stwierdza, że wszelkie zmiany w publicznym interfejsie API (tj. Te, które nie są kompatybilne z poprzednimi wersjami), powinny uzasadniać ważną wersję. Tak więc biblioteka przeskakuje z wersji 1.7.3 do 2.0.0, co dla mnie jest krokiem za daleko. Mówimy tylko o naprawieniu jednej funkcji.
Mam plany, aby ostatecznie wydać 2.0.0, ale myślałem, że to wtedy, gdy całkowicie przepisałeś bibliotekę i zaimplementowałeś wiele publicznych zmian API. Czy wprowadzenie tego refaktoryzacji wymaga wydania ważnej wersji? Naprawdę nie widzę, jak to działa - czuję się bardziej komfortowo, wypuszczając go jako 1.8.0 lub 1.7.4. Czy ktoś ma jakieś rady?
next()
metoda służy do pobrania bieżącego elementu ORAZ przesunięcia wewnętrznego wskaźnika do przodu. Co jest złe.next()
powinien przesunąć wskaźnik icurrent()
służy do wyszukiwania ...next()
tylko za to, że przesuwa wskaźnik, to naprawdę nie psuje kompatybilnościOdpowiedzi:
Wahasz się, ponieważ nie chcesz tworzyć wersjonowania semantycznego, chcesz zrobić „reklamy obsługujące wersjonowanie”. Oczekujesz, że numer wersji „2.0” poinformuje świat, że masz teraz w bibliotece wiele nowych fajnych funkcji, a nie to, że zmieniłeś interfejs API. Zgadza się (robi to wiele firm i / lub programistów). IMHO masz następujące opcje:
next
, po prostu dodaj funkcjevalid
icurrent
). Następnie możesz użyć „1.8.0” jako kolejnego numeru wersji. Jeśli uważasz, że zmiana zachowanianext
jest naprawdę ważna, zrób to w 2.0.0.źródło
next()
o robienie dalej. Aby poprawnie zaimplementować tę funkcję, musi zrobić coś inaczej. Więc jeśli sprawię, że będzie on kompatybilny wstecz - nowa funkcjonalność / poprawka również będzie błędna i podważy cały sens zmiany.next()
metody, aby wykonać wszystkie nowe funkcje, a także to, co było potrzebne, aby zapewnić kompatybilność wsteczną. To trochę okropne, że muszę niszczyć nowe funkcje w ten sposób, ale hej, ho.Trzymaj się przewodnika Toma po wersjach semantycznych.
Wszelkie istotne zmiany w publicznym interfejsie API muszą być wykonane w jednym z dwóch punktów:
Nawiasem mówiąc, mój głos jest pierwszy. Ale potwierdzam, że jest odpowiedni tylko do drobiazgów.
Problemem jest utrzymanie kompatybilności wstecznej i upewnienie się, że nie psujesz rzeczy poprzednim użytkownikom interfejsu API.
Zasadniczo tworzysz błąd indeksowania dla użytkowników, którzy nie są świadomi zmiany. Wymuszenie takiej zmiany zmusza wszystkich użytkowników do wykonania następujących czynności:
Może to potencjalnie wymagać dużego wysiłku, zwłaszcza gdy weźmie się pod uwagę, jak niewiele projektów ma wdrożone przypadki testowe, aby zweryfikować takie zmiany. Nakład pracy jest większy, gdy weźmie się pod uwagę liczbę dalszych użytkowników, którzy będą musieli również zaktualizować swoje instalacje.
W przypadku czegoś tak małego pozwoliłbym temu odejść i nie zawracałem sobie tym głowy.
Jeśli naprawdę Ci to przeszkadza (co najwyraźniej tak robi lub nie zapytałbyś), zrobiłbym następujące.
Release Notes
wyprzedzeniem, że nadchodzi zmianaA potem uzbrój się w cierpliwość, ponieważ zgromadzenie innych rzeczy uzasadniających uaktualnienie numeru wersji do nowej wersji głównej zajmie trochę czasu. Zaawansowane powiadomienie (część 3) daje czas na otrzymanie informacji zwrotnych od użytkowników końcowych, aby dowiedzieć się, jaki wpływ będzie miała ta zmiana.
Alternatywnym rozwiązaniem jest dodanie nowej funkcji, która działa tak, jak chcesz.
Jeśli tak, należy
foo()
utworzyćfooCorrect()
, aby zapewnić poprawkę, ale także w pełni zachować zgodność z poprzednimi wersjami. W pewnym momencie możeszfoo()
przestać działać, aby inni mogli wiedzieć, że go nie używasz.Wyzwaniem jest, że znajdziesz coś innego, w
fooCorrect()
co wymaga To aktualizacji i skończy sięfooCorrectedCorrect()
albo jakaś inna głupie bzdury.Jeśli naprawdę chcesz to teraz naprawić, to alternatywne podejście jest prawdopodobnie najlepszą trasą. Należy pamiętać o tworzeniu wielu dodatkowych funkcji w ten sposób, ponieważ utrudnia to pracę z interfejsem API. I ta świadomość może wystarczyć, aby zapobiec najgorszemu z tego rodzaju problemów.
Ale może to być „najmniej złe” podejście do rozważenia w przypadku czegoś małego.
źródło
next()
NienextCorrect()
). Zobaczę, czy mogę zmodyfikować next (), aby był kompatybilny wstecz ORAZ działa podczas implementacjiIterator
interfejsu.