Мне кажется знание алгоритмов и структур данных — одна из основ, которую не знать нельзя, опять же IMHO большим плюсом является профиль на github с какими-либо проектами — можно сразу посмотреть как человек пишет. Насчет публикаций в научных журналах — не знаю, никогда не встречался.
>> Либо можно забить на то, что при определенных обстоятельствах вдруг родится не один экземпляр а целых два.
Неа, нельзя так забивать, тем более когда много потоков — можно таких чудесных багов поиметь, что потом будет очень больно. Представьте, что у вас 100 000 потоков, которые делают банковскую транзакию сол счета пользователя на ваш счет с разными суммами, и вот представьте, что из-за неправильной инициализации всего 3 потока взяли неправильный номер счета(для простоты NULL), и вот у вас 99 997 транзакция по копейке, а 3 транзакции по 100 000 денег — ушли в никуда.
Я не очень понял про DI, объясните пожалуйста что именно в имеете в виду, архитектурный принцип или средства управления зависимостями? Какие средства используете вы для внедрения зависимостей?
Sorry, никогда не встречался с таким отношением. По моему опыту: либо проект летит вообще без тестов(ну исторически так сложилось), либо тесты пиуштся более-менее адекватно и по делу.
Подход «тесты вперед» приводит к чрезмерно сложной структуре посреднических объектов и окольных путей
Нет, не ведет. Используем моки, для всегор того, что не можем дернуть явно. В языках со динамической типизацией проблем прослоек и окольных путей — нет(пример Groovy), в языках со трогой типизацией 1< фреймворков для тестирования, которые реализуют моки.
В итоге мы приходим к созданию монструозной архитектуры
Ну лучший код — пустая строка, ни багов, ни проблем с производительностью… вообще ничего. Ну да хватит филосовствовать.
Мне кажется, TDD — просто инструмент, как микроскоп — хочешь бактерии рассматривай, не хочешь — гвозди забивай. И каждый инструмент где-то востребован — в стртапе, когда ни денег, ни времени, а альфа-релиз может косячить(и это нормально!) на тесты ни времени, ни сил нет. А вот если пишем биржевое приложение и в случае ошибки рискуем большими деньгами, будьте добры напишите тесты, до или после — сами решайте.
Простите, а как же интеграционные тесты? Я понимаю, что и они всего не покрывают, но увеличивают надежность. Мне кажется нельзя гворить о работоспособности всего приложения, исходя только из того, что работают модульные тесты(у меня лично были ситуации, когда код проходит все юнит-тесты на ура и с хорошим покрытием, а в конфигурации понаписано такое, что оно просто никак не может работать). И мне кажется, создавая код, которые работает с «чужим» приложением (как пример — внешнее API), нельзя не писать интеграционных тестов.
Для меня ситуация с Максов очень странная и непонятная. Что значит сказал своему разработчику? Получается, если менеджеров несколько, Макс должен учить наизусть, то что ему говорят все менеджеры, и такая ошибка очень распространена в среде менеджмента. В не правильной, не точной постановке всегда виноват менеджер. Работа программиста — писать код. Работа менеджера — ставить задачи(формализовать требования бизнеса, объяснить задачу исполнителю, проконтролировать сроки выполнения, корректировать и консультировать исполнителя) и если он с этой работой не справился — обвинять в чем-либо программиста не правильно. Программист может подойти и уточнить, что же именно необходимо бизнесу. Но ему не за это платят деньги.
Попробую распутать:
a) Rhino разбирает js на лексемы и строит из них java-код. Генерирует обертку в которой они исполняются.
b) groovyc — делает из .groovy -> .java и компилирует.
с), d) конечно, иначе оно не исполняется в jvm.
отличный юмор. Только вот теперь полезем в дебри и разберемся, а что же делает Rhino, такого, чего не делает Groovy.
Rhino может работать в 2х режимах рассмотрим первый — кодогенерация:
Нас больше всего интересует внутрянка, а именно класс org.mozilla.javascript.optimizer.Codegen.
Рассмотрим метод org.mozilla.javascript.optimizer.Codegen.compile(CompilerEnvirons, ScriptNode, String, boolean)
И заметим, что здесь формируется имя класса как
Далее пропустим стэк вызовов и перейдем сразу к самой интересной части — к методу org.mozilla.javascript.optimizer.Codegen.generateCode(String);
Здесь, по коду, создается переменная ClassFileWriter cfw, которая по сути и отвечает за преобразованный код.
И далее происходит самая интересная магия в методе org.mozilla.classfile.ClassFileWriter.addInvoke(int, String, String, String), исходя из кода этого метода мы можем увидеть что в описание класса добавляются:
hasTopCall(.....), doTopCall(.....) — который и будет содрежать скомпилированный код, если мы вызываем исполняемый скрипт.
далее вызывается метод org.mozilla.javascript.optimizer.Codegen.generateResumeGenerator(ClassFileWriter), который добавляет
resumeGenerator(...) не всегда, но добавляет
Далее метод org.mozilla.javascript.optimizer.Codegen.generateNativeFunctionOverrides(ClassFileWriter, String)
Который добавит еще кучку методов.
Далее возьмем для документацию компилятора Groovy:
… Each groovy class then just becomes a normal Java class you can use inside your Java code if you wish.
Indeed the generated Java class is indistinguishable from a normal Java class, other than it implements the
...
Таким образом код:
alert('Я люблю троллить людей');
преобразуется во что-то типа такого
class org.mozilla.javascript.gen.GenScript_123125 implements org.mozilla.javascript.Script {
public void exec()
public Object doTopCall(Object... params ) {
......
alert('Я люблю троллить людей');
......
}
public boolean hasTopCall(.....) {
return true;
}
// Остальные методы здесь
}
public class GroovyClass extends GroovyObject {
public Object message() {
System.out.println(''Я люблю троллить людей'');
return null;
}
}
Таким образом, чтобы не путаться в первом случае мы имеем.
1. Преобразование исходников.
2. Создание псевдокласса.
3. Компиляция исходников в Java-код.
4. Создание псевдокласса и из всех исходников в java-класс.
Во втором случае мы имеем
1. Преобразование Groovy-класса в Java-класс.
2. Компиляция Java-класса.
В первом случае можно говорить о преобразовании кода из одного языка в другой. Причем первый не работает в JVM.
Во втором случае мы говорим о компиляции, только о компиляции
Неа, нельзя так забивать, тем более когда много потоков — можно таких чудесных багов поиметь, что потом будет очень больно. Представьте, что у вас 100 000 потоков, которые делают банковскую транзакию сол счета пользователя на ваш счет с разными суммами, и вот представьте, что из-за неправильной инициализации всего 3 потока взяли неправильный номер счета(для простоты NULL), и вот у вас 99 997 транзакция по копейке, а 3 транзакции по 100 000 денег — ушли в никуда.
Нет, не ведет. Используем моки, для всегор того, что не можем дернуть явно. В языках со динамической типизацией проблем прослоек и окольных путей — нет(пример Groovy), в языках со трогой типизацией 1< фреймворков для тестирования, которые реализуют моки.
Ну лучший код — пустая строка, ни багов, ни проблем с производительностью… вообще ничего. Ну да хватит филосовствовать.
Мне кажется, TDD — просто инструмент, как микроскоп — хочешь бактерии рассматривай, не хочешь — гвозди забивай. И каждый инструмент где-то востребован — в стртапе, когда ни денег, ни времени, а альфа-релиз может косячить(и это нормально!) на тесты ни времени, ни сил нет. А вот если пишем биржевое приложение и в случае ошибки рискуем большими деньгами, будьте добры напишите тесты, до или после — сами решайте.
a) Rhino разбирает js на лексемы и строит из них java-код. Генерирует обертку в которой они исполняются.
b) groovyc — делает из .groovy -> .java и компилирует.
с), d) конечно, иначе оно не исполняется в jvm.
Rhino может работать в 2х режимах рассмотрим первый — кодогенерация:
Нас больше всего интересует внутрянка, а именно класс org.mozilla.javascript.optimizer.Codegen.
Рассмотрим метод org.mozilla.javascript.optimizer.Codegen.compile(CompilerEnvirons, ScriptNode, String, boolean)
И заметим, что здесь формируется имя класса как
Далее пропустим стэк вызовов и перейдем сразу к самой интересной части — к методу org.mozilla.javascript.optimizer.Codegen.generateCode(String);
Здесь, по коду, создается переменная ClassFileWriter cfw, которая по сути и отвечает за преобразованный код.
И далее происходит самая интересная магия в методе org.mozilla.classfile.ClassFileWriter.addInvoke(int, String, String, String), исходя из кода этого метода мы можем увидеть что в описание класса добавляются:
hasTopCall(.....), doTopCall(.....) — который и будет содрежать скомпилированный код, если мы вызываем исполняемый скрипт.
далее вызывается метод org.mozilla.javascript.optimizer.Codegen.generateResumeGenerator(ClassFileWriter), который добавляет
resumeGenerator(...) не всегда, но добавляет
Далее метод org.mozilla.javascript.optimizer.Codegen.generateNativeFunctionOverrides(ClassFileWriter, String)
Который добавит еще кучку методов.
Далее возьмем для документацию компилятора Groovy:
Таким образом код:
преобразуется во что-то типа такого
А код в Groovy
Превратиться в
Таким образом, чтобы не путаться в первом случае мы имеем.
1. Преобразование исходников.
2. Создание псевдокласса.
3. Компиляция исходников в Java-код.
4. Создание псевдокласса и из всех исходников в java-класс.
Во втором случае мы имеем
1. Преобразование Groovy-класса в Java-класс.
2. Компиляция Java-класса.
В первом случае можно говорить о преобразовании кода из одного языка в другой. Причем первый не работает в JVM.
Во втором случае мы говорим о компиляции, только о компиляции