|
|
|||||
Регистрация: Aug 2010
Сообщений: 86
|
Как это что. Программист А специально реорганизовал класс, чтоб программисту В был кукиш. =) Пусть с нуля создает, а не спиногрызит тут.
Хотя с другой стороны программист А тоже хорош, пусть не мешает личное с делами... Уволить обоих! И нанять программистов C & D! Последний раз редактировалось honest_man; 08.05.2011 в 01:59. |
|
|||||
Modus ponens
|
Цитата:
Есть еще такой момент - я, (все еще) почему-то предполагаю, что человека, который будет использовать мой код возможно заинтересует реализация, и при наследовании он не будет делать каких-то явных глупостей. Увы, так не работает. И если необходимо получить результат не взирая на "идиотов" сотрудников, которым жалко лишний раз посмотреть чужой исходник... да, иногда наверное не помешает и final...
__________________
Hell is the possibility of sanity |
|
|||||
[+1 23.05.11]
Регистрация: Dec 2001
Сообщений: 4,159
|
К сожалению, это помогает не всегда. Качественные юнит-тесты встречаются реже, чем многие думают. Думаю, не ошибусь, если предположу, что три четверти здешнего контингента их вообще не пишет.
Где-то с год назад мне довелось поработать с кодом большого сторонника модульных тестов. Покрытие -- свыше 95%. При этом "работа над ошибками" показала, что в оставшиеся 5% аккуратно вошли разные аномальные состояния. Тесты -- работают. А если вдруг из стороннего модуля исключение прилетит -- вся система в алмазный дым обращается. А юнит-тестов при этом -- процентов на 20 больше, чем "полезного" кода. Цитата:
Цитата:
__________________
GIT d++ s++:++ a C++$ UB++ P++ L+ E+ W+++ N++ w++ O+ M V- t-- 5-- X+ R+++ tv- b+++ D++ |
|
|||||
Modus ponens
|
Да, я о другом
Вот, непридуманная ситуация, буквально пару дней назад. Был у меня класс, в котором была переменная хранившая XML. Этот класс должен был использоваться другим человеком. Если занулить / не инициализировать переменную, то были бы ошибки, и очевидно поэтому человек использовавший мой класс решил сделать следующее: _xml = new XML() (и заработало, но не совсем...). Я не предполагал, что XML в этом месте может быть не элементом, а текстом, например. Я когда увидел, чуть не заплакал. Переделал переменную в константу - стало менее удобно, но без ошибок. Ну а если я что-то поменял в моем классе, что потенциально приведет в нерабочее состояние чужой код - ну так я, чисто по-человечески должен хотя-бы в коммит-лог об этом написать. Опять же, юнит тесты с большой вероятностью покажут, что я что-то сломал, если сломал. Ну и я делаю так: public и protected, если я меняю, я дописываю [Deprecated] и оставляю так на несколько версий, пока все не переделают под новый вариант. То, что я не предполагаю, что другие будут использовать - private / internal. Если кто-то использовал internal - на свой страх и риск, и если не работает / перестало - не мои проблемы.
__________________
Hell is the possibility of sanity |
|
|||||
Цитата:
Хотя с другой стороны, эти 10 тестов, в которых ни слухом - ни духом о реальном, не замененном моком синглике - могут однажды повести себя неадекватно. Последний раз редактировалось expl; 08.05.2011 в 12:26. |
|
|||||
[+1 23.05.11]
Регистрация: Dec 2001
Сообщений: 4,159
|
...то синглетон для этого не нужен. Применяемая для этого конструкция похожа, но не имеет к синглетону никакого отношения.
__________________
GIT d++ s++:++ a C++$ UB++ P++ L+ E+ W+++ N++ w++ O+ M V- t-- 5-- X+ R+++ tv- b+++ D++ |
|
|||||
Имеете в виду статическую фабрику?
Ну да, преимуществ по сравнению с сингилком 2: Нет ограничения на количество сервисов, код сервиса свободен от выполнения обязанностей по контролю за своим инштанцированием. Но на них и забить можно - тупо _не_ запрещать синглику инштанцироваться вне getInstance() - кому второй синглик понадобится - фабрику се сделает. Последний раз редактировалось expl; 08.05.2011 в 14:01. |
|
|||||
Modus ponens
|
expl.
ОК, пример package tests { import com.***.net.tcp.NinjaEvent; import com.***.net.tcp.NinjaMethods; import com.***.net.tcp.NinjaService; import flash.events.Event; import flexunit.framework.Assert; import org.flexunit.async.Async; public class TestNinjaKillActivity { private var _activityDead:Boolean; // Падаван хотел это сделать синглотоном :) А тут внезапно их два - облом :) private var _sender:NinjaService = new NinjaService("123456", "127.0.0.1"); private var _receiver:NinjaService = new NinjaService("654321", "127.0.0.1"); public function TestNinjaKillActivity() { super(); } [Before(async)] public function before():void { this._sender.addEventListener(Event.CONNECT, this.sender_connectHandler); this._receiver.addEventListener( Event.CONNECT, this.receiver_connectHandler); this._receiver.addEventListener( NinjaEvent.GET_ACTION, this.getActionHandler); this._receiver.addEventListener( NinjaEvent.CALL_RECEIVED, this.receiver_callReceivedHandler); this._sender.addEventListener( NinjaEvent.CALL_STARTED, this.sender_callStartedHandler); Async.proceedOnEvent(this, this._receiver, "test", 10000); this._sender.connect(); this._receiver.connect(); } private function sender_connectHandler(event:Event):void { if (this._receiver.connected) this.bothConnected(); trace("sender_connectHandler"); } private function receiver_connectHandler(event:Event):void { if (this._sender.connected) this.bothConnected(); trace("receiver_connectHandler"); } private function sender_callStartedHandler(event:NinjaEvent):void { this.killActivity(); trace("sender_callStartedHandler"); } private function receiver_callReceivedHandler(event:NinjaEvent):void { (this._receiver.methods as NinjaMethods) .acceptCall(this._sender.clientId); trace("receiver_callReceivedHandler"); } public function bothConnected():void { (this._sender.methods as NinjaMethods) .startCall(this._receiver.clientId, "externalId", "a", "b", "c", "d"); trace("bothConnected"); } private function killActivity():void { (this._sender.methods as NinjaMethods) .killActivity(this._receiver.clientId); } private function getActionHandler(event:NinjaEvent):void { this._activityDead = true; this._receiver.dispatchEvent(new Event("test")); this.testReceive(); trace("getActionHandler"); } [Test(async, timeout="10000")] public function testReceive():void { Assert.assertTrue(this._activityDead); } } }
__________________
Hell is the possibility of sanity |
|
|||||
Ага, как обломали подавана, понятно (ох, как я часто от коллег слышу "А давай этот класс сделаем синглтоном" - хочется увесистой книжкой по пальцам сразу).
А вот как вы ссылки тянете на эти сервисы в клиентские классы не очень. Например есть модель: - Юзер --деревня ---грядка Главный контроллер (его я даже не пытаюсь покрыть unit-тестами - он завязан на все и вся, но сложной логики там мало, большинство делегируется его детям и модели) инштанцирует СинхронизаторВремениССервером. Если передавать его всем детям в стиле "push" получается: - надо протащить ссылки через Юзера и деревню - надо каждый раз передавать грядке синхронизатор при ее добавлении Получается лезем в тесты Юзера и деревни, чтобы добавить в конструктор этот сервис (допустим, он нужен только грядке) То что в тестах деревни может что-то зависеть от синхронизатора, который находится в Грядке - это другой вопрос. Последний раз редактировалось expl; 08.05.2011 в 20:20. |
|
|||||
Modus ponens
|
К сожалению, в реальном проекте взаимодействие между частями - это вотчина падавана (он там работает на 2 года больше меня, и мне поэтому ничего "серьезного" не доверяют... ну так вот ). На то, что там происходит без слез / смеха смотреть тяжело... Так что, как "у нас", уж наверняка лучше не делать.
Так, как я бы делал - иерархия, ребенок сообщает наверх, и не его забота кто и как обработает, даже ни на что не подписывается, когда надо будет, ему родитель "скажет" что делать.
__________________
Hell is the possibility of sanity |
Часовой пояс GMT +4, время: 20:34. |
|
« Предыдущая тема | Следующая тема » |
Теги |
final , код , скорость , функция |
Опции темы | |
Опции просмотра | |
|
|