'

Быть в 10 раз эффективнее благодаря Groovy

Понравилась презентация – покажи это...





Слайд 0

Быть в 10 раз эффективнее благодаря Groovy Евгений Компаниец


Слайд 1

Smart1: система бронирования ТВ-рекламы Вся реклама на телеканалах 1+1, 2+2, ТЕТ, CITI продается через Smart1 Месячный оборот 00 000 000 гр. Информация о 1 300 000 размещениях рекламы Сложная модель продаж - аукцион  Отчеты  Интеграция с внешними системами: GFK Mark Data Media Workstation, 1C 2 разработчика; 1,5 года; внедрено на втором месяце разработки


Слайд 2


Слайд 3

Архитектура CentOS 4.1.2 PostgreSQL 8.4.4 Tomcat 6.0.20 Hibernate 3.3.x Ehcache 2.1.0 Java 1.6 64-Bit server GWT 2.3.0 GWT 2.3.0 RPC Servlet Groovy 1.8.0 Daemon Servlets


Слайд 4

Разработка Java 1.6 64-Bit server IntelliJ IDEA 10 GIT Maven 2 Jetbrains TeamCity 6.0.3 Selenium 1.0.2 710 Тестов Время сборки 40 мин Установка на рабочий сервер 2 раза в неделю


Слайд 5

Производительность Денормализация структуры БД Тяжелые отчеты обновляются по расписанию Ряд задач выполняется только ночью   HP Proliant DL360G6 2xQuad CPU 12G RAM Пиковая нагрузка 40 gwt rpc запросов в секунду


Слайд 6

Строки кода


Слайд 7

От Java к Groovy Smart1 - наш второй groovy проект До перехода сомнения: что такого принципиального может дать groovy? зачем терять часть возможностей IDE? огромный тормоз После перехода: сожаление, что gwt не позволяет использовать groovy, чтобы полностью отказаться от java


Слайд 8

Опрос: Насколько Groovy эффективнее Java? 4-6 раз, коллеги Я бы сказал 2-3 раза, Алекс Ткачман Я обычно продуктивнее в 2 с лишним. Иногда groovy действительно упрощает проблему и я становлюсь в 3-5 раз продуктивнее. Давид Кларк Моя продуктивность легко достигает 10 раз. Jochen Theodorou  


Слайд 9

Groovy - это гораздо больше, чем убрать из Java ; и типы! значительно меньше кода код значительно читабельнее значительно выше повторное использование легко создаются DSL не нужен псевдокод


Слайд 10

Коротко и выразительно! Взять все проходящие размещения и отсортировать сначала по цене, потом по дате создания placements.findAll { it.booked } .sort {p1, p2 ->          p2.wPrice <=> p1.wPrice ?:              p1.creationDate <=> p2.creationDate }


Слайд 11

List bookedPlacements = new ArrayList(); for (Placement placement : placements) { if (placement.isBooked()) {        bookedPlacements.add(placement);       } } Collections.sort(bookedPlacements, new Comparator<Placement>() {             public int compare(Placement p1, Placement p2) {                 int r = p1.getwPrice().compareTo(p2.getwPrice());                 if (r == 0) {                     r = p1.getCreationDate() .compareTo(p2.getCreationDate());                 }                 return r;             } });


Слайд 12

Коротко и выразительно! Вернуть короткие названия бюджетных месяцев def monthNames = budgets*.month*.shortName List monthNames = new ArrayList(); for (MonthBudget budget: budgets) { monthNames.add(budget.getMonth().getShortName()); }


Слайд 13

Коротко и выразительно! Эфирное время конца программы – это время начала первого из послепрограмных блоков, либо время конца программы blocks.findAll { it.position == AFTER }*.startTime.min() ?: endTime


Слайд 14

List afterBlocks = new ArrayList (); for (Block block : blocks) { if (block.getPosition() == AFTER) { afterBlocks.add(block); } } if (afterBlocks.isEmpty()) { return endTime; } Time minTime = new Time(0); for (Block block : afterBlocks) { if (block.getStartTime().isBefore(minTime)) { minTime = block.getStartTime(); } } return minTime;


Слайд 15

Коротко и выразительно! Если плательщик задан, то вернуть его, иначе взять плательщика из прошлого периода. Если в прошлом периоде нет плательщиков, то взять любого из агентства. payee ?: prevInYear?.payee ?: (agency.payees as List)[0]


Слайд 16

if (payee != null) { return payee; } if (getPrevInYear() != null && getPrevInYear().getPayee() != null) { return prevInYear.getPayee(); } return getAgency().getPayees().iterator().next();


Слайд 17

Немного сложнее? Взять размещения из самой популярной категории placements.groupBy { it.category }.collect {it}                 .sort {it.value.size()}.last().value


Слайд 18

Java, с использованием «библиотечных» groupBy и last: List groupsList = new ArrayList((Util.groupBy(placements, new GroupSelector<CopyCategory, Placement>() { public CopyCategory getProperty(Placement p) { return p.getCopyCategory(); } })).entrySet()); Collections.sort(groupsList, new Comparator<Map.Entry<CopyCategory, List<Placement>>>() { public int compare(Map.Entry<CopyCategory, List<Placement>> o1, Map.Entry<CopyCategory, List<Placement>> o2) { return ((Integer) o1.getValue().size()) .compareTo(o2.getValue().size()); } }); return (List<Placement>) ((Map.Entry) Util.last(groupsList)).getValue();


Слайд 19

Java, прямая реализация: Map<CopyCategory, List<Placement>> categoryPlacements = new HashMap<CopyCategory, List<Placement>>(); for (Placement placement : placements) { List _placements = categoryPlacements.get(placement.getCategory()); if (_placements == null) { _placements = new ArrayList(); categoryPlacements.put(placement.getCategory(), _placements); } _placements.add(placement); } CopyCategory popularCategory = null; int maxSize = 0; for (CopyCategory category : categoryPlacements.keySet()) { if (categoryPlacements.get(category).size() > maxSize) { maxSize = categoryPlacements.get(category).size(); popularCategory = category; } } return categoryPlacements.get(popularCategory);


Слайд 20

Сила Closure Настоящие возможности открываются, когда мы понимаем что такое Closure sort, findAll, groupBy и т.п – все навсего методы принимающие Closure и мы можем делать такие свои


Слайд 21

Сила Closure Получить Map время, на название (названия уникальны для времени) placements.mapUnique(‘time’) { it.name } Map<Time, String> timePlacements = new HashMap<Time, String>(); for (GfkPlacement placement: placements) { timePlacements.put(placement.time, placement.name); }


Слайд 22

Расширение существующих классов Мы можем добавлять методы и поля к уже написанным классам без наследования. Наш mapUnique можно вызывать на любой коллекции robot.grp = 22.centi scheduleMonth.month = 2009.jan block.startTime = /17:59/.time


Слайд 23

Расширение существующих классов Методы у Object дают нам следующий синтаксис: transaction { new User(‘New User’).dbStore() }


Слайд 24

Расширение существующих классов Сделаем немного удобнее Hibernate Criteria API: def clientGroups = RobotGroup.dbQuery.with { eq('deleted', false) createCriteria('copy').eq('_client', client) }.list()


Слайд 25

DSL делается легко count = 0 new SwingBuilder().edt { frame(title: 'Frame', size: [300, 300], show: true) { borderLayout() textlabel = label(text: "Click the button!", constraints: NORTH) button(text: 'Click Me', actionPerformed: { count++ textlabel.text = "Clicked ${count} time(s)." }, constraints: SOUTH) } }


Слайд 26

JFrame frame = new JFrame("Frame"); frame.setSize(300, 300); frame.setLayout(new BorderLayout()); final JLabel label = new JLabel("Click the button"); frame.add(label, NORTH); final JButton button = new JButton("Click Me"); final int[] counter = {0}; button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { counter[0]++; label.setText("Clicked " + counter[0] + “ time(s)."); } }); frame.add(button, SOUTH); frame.setVisible(true);


Слайд 27

DSL делается легко shopList(client, 2011, 'Test ShopList', primePercent: 70) {        discount(offPrime: -10.disc)        channelSl(channel, lowDiscount: -30.disc) {             monthSl(JAN, seasonal: -30.disc) {                 stdSl(100.centi)                 lowSl(400.centi)             }        } }


Слайд 28

Selenium junit тест void testPlace_SpotClient() { runTest(    agent, {        chooseCampaigns 'XC'          placeClick getBlock(1), 'XC'          waitForError 'No Shop List for Volvo in 2009'       },       sale, clients, {        changeToPerSpot 'Volvo'       },       ... ) }


Слайд 29

Динамика Динамическое программирование позволяет нам понять что такое повторное использование по настоящему! Например давайте перестанем каждый раз делать одно и тоже для Bidirectional Association и Lazy Initialization:


Слайд 30

Bidirectional Association class Program { @OneToMany (mappedBy = "_program")     Set<Block> _blocks = [] } class Block { @ManyToOne     Program _program }


Слайд 31

Bidirectional Association И теперь мы сразу можем работать: def p = new Program() def b = new Block() p << b p.addBlock(b) p.removeBlock(b) //valid properties: p.blocks (unmodifiable set), b.program


Слайд 32

Bidirectional Association Этого писать не нужно: class Program { ... void addBlock(Block b) {   b._program = this  }    void removeBlock(Block b) {    b._program = null } } class Block { ... void setProgram(Program p) { if (_program != null) {    _program.friendBlocks .remove(this)   }   _program = p   if (_program != null) {    _program.friendBlocks .add(this)     } } }


Слайд 33

Lazy initialization Этого писать не нужно: class MonthBudget {  ...  Centi __actualBudget() {     ...  calculation  } } class MonthBudget { ...  Centi _actualBudget  def getActualBudget() {    if (_actualBudget == null) {       _actualBudget = ...      }  } } println new MonthBudget().actualBudget


Слайд 34

Но не все так хорошо Скорость? IDE?


Слайд 35

Реально тормоз! Groovy работает в 10 раз медленнее Java


Слайд 36

Benchmark Groovy, Grovy++, Java https://github.com/alextkachman/fib-benchmark


Слайд 37

Но на этом можно работать Groovy работает также как Python, Ruby, PHP и т.п.


Слайд 38

Benchmark Java, Python, Ruby http://shootout.alioth.debian.org/


Слайд 39

Скорость Groovy не забываем, что часто узкое место база данных любой фрагмент можно переписать на java любой фрагмент можно переписать сделать Groovy++


Слайд 40

Groovy++ Статически типизированное расширение Groovy По скорости выполнения почти не уступает Java Может рассматриваться как альтернатива Scala Пишется небольшой группой энтузиастов (один хакер?), мало используется


Слайд 41

IDEA IDEA в целом очень хорошо поддерживает groovy: Для работы с динамическими методами и полями в IDEA есть Dynamic properties Работает выведение типов, в основном ? Тем не менее: Для динамики мы теряем автоматический рефакторинг и высокоуровневый поиск (findUsages) В отладчике иногда сильно тормозит Step Into


Слайд 42

Спасибо evgenyk@gmail.com


×

HTML:





Ссылка: