image

От переводчика: эта статья — перевод материала, написанного программистом Аластером Парагасом (Alastair Paragas) из Apple.Он работал с такими языками программирования, как Javascript, Python, PHP, Java, Scala, Haskell, Swift и Rust. Аластер делится собственными размышлениями на тему выбора и изучения «своего» языка, ведь этот вопрос актуален как для новичков, так и для профессионалов, которые хотят выбрать новый инструментарий.

Изучаете ли вы язык программирования ради трудоустройства или повышения квалификации или же это чистой воды хобби, рано или поздно вам придется выбирать между ними. Как это сделать? Вопрос непростой, но ответить на него можно так: каждый день это делают тысячи программистов. Чтобы облегчить себе задачу, стоит следовать нескольким принципам.

Skillbox рекомендует: Практический курс «Профессия Веб?разработчик».
Напоминаем: для всех читателей Хабра — скидка 10 000 рублей при записи на любой курс Skillbox по промокоду «Хабр»
.

Сравнительные показатели


Уровни абстракции

Если сильно обобщить, можно сказать, что современные языки программирования разделяются на три типа:

  1. «Быстрые», которые используются для оперативного создания приложений или их прототипов.
  2. «Инфраструктурные», которые помогают оптимизировать или дорабатывать отдельные части уже написанного приложения для того, чтобы повысить его производительность.
  3. Так называемые системные языки программирования, использование которых позволяет получить в свое распоряжение полноценный контроль над памятью устройства.

Конечно, реальное разделение на типы среди языков программирования менее строгое: есть промежуточные, гибридные варианты различных типов.

Если говорить об изучении языков, то сначала стоит попробовать первый тип — «быстрые» языки: они позволяют сразу видеть результат работы и учиться на собственных ошибках. В первую очередь это PHP, Javascript, Ruby и Python. Порог входа здесь минимален, и научиться основам можно за короткий срок. У этих языков стандартные библиотеки, которые позволяют добавлять большое количество функций в приложение, а спектр их возможностей достаточно велик.

from concurrent.futures import ThreadPoolExecutor
from http.client import HTTPException
from urllib import request
from typing import Union, Dict, Any, List 
def get_request_task(url: str) -> Union[List[Dict[str, Any]], None]:
  try:
    contents = None
    with request.urlopen(url) as response:
      contents = response.read()
    return contents
  except HTTPException:
    return None
with ThreadPoolExecutor() as executor:
  for result in executor.map(get_request_task, [
    "https://jsonplaceholder.typicode.com/posts",
    "https://jsonplaceholder.typicode.com/comments",
    "https://jsonplaceholder.typicode.com/albums"
  ]):
    if result is None:
      print("Something terrible has happened!")
    else:
print(result)

Реализация многопоточных HTTP-запросов в Python со статической типизацией. Многопоточность предусматривает возможность чередования трех задач (назовем их задачами A, B и C). В то время как одна задача (скажем, задача A) выполняет некоторую операцию с привязкой к I / O (и, следовательно, не выполняет какую-либо работу по вычислению), одновременно с ней выполняются и другие задачи.

Что касается «инфраструктурных» языков, то это Java, Kotlin, Scala, Clojure, а также GoLang, Swift и Haskell. Назвать их удобными можно с натяжкой, но зато они позволяют создавать производительные приложения. К числу сложностей относится меньшее число элементов «из коробки», точный синтаксис и т.п. Эти языки хороши тем, что позволяют производить тонкую настройку приложения. Если вам необходима скорость работы, попробуйте написать приложение на одном из них.

import Foundation
import Dispatch
func getRequestTask(url: String, dispatchGroup: DispatchGroup) {
  dispatchGroup.enter()
   let request = URLRequest(url: URL(string: url)!)
  let task = URLSession(configuration: URLSessionConfiguration.default).dataTask(
    with: request,
    completionHandler: {
      (data, response, error) in
      if let data = data {
        if let dataAsString = String(data: data, encoding: .utf8) {
          print(dataAsString)
          dispatchGroup.leave()
          return
        }
      }
      print("Something terrible has happened!")
      dispatchGroup.leave()
    }
  )
   task.resume()
}
let requestDispatchGroup = DispatchGroup()
for url in [
  "https://jsonplaceholder.typicode.com/posts",
  "https://jsonplaceholder.typicode.com/comments",
  "https://jsonplaceholder.typicode.com/albums"
] {
  getRequestTask(url: url, dispatchGroup: requestDispatchGroup)
}
requestDispatchGroup.wait()

Аналогичная задача уже решалась выше при помощи Python. Теперь в деле — Swift.

Системные языки программирования — С, С++, Rust. Они дают максимальный контроль над приложением, включая управление потреблением памяти. Также эти языки отлично подходят для программирования микроконтроллеров, компьютеров с нестандартной архитектурой процессора и других систем. Низкоуровневые языки до сих пор важны и скорее всего, будут оставаться актуальными и в ближайшем будущем.

Функциональность

Как известно, языки служат средством «общения» между компьютером и программистом. Для того чтобы это общение шло гладко, стоит изучить синтаксис языка в деталях. В частности, специалист должен знать наиболее часто используемые структуры данных и понимать, как можно модифицировать определенные элементы своего приложения.

module Main where
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Resource (runResourceT)
import Data.Conduit (($$+-), ($=+), runConduit)
import Data.Conduit.List (mapM_, map, filter, catMaybes)
import Data.Text (unpack)
import Data.Maybe (fromJust)
import Web.Twitter.Types
  (StreamingAPI(SStatus, SRetweetedStatus)
  , Status(Status), statusText, statusLang
  , RetweetedStatus(RetweetedStatus), rsRetweetedStatus
  )
import Web.Twitter.Conduit.Stream (stream)
-- Filters Twitter tweets that are written only in English
filterEnglishTweets :: StreamingAPI -> Bool
filterEnglishTweets tweet =
  let
    langIsEnglish (Status {statusLang=language}) = case language of
      Just "en" -> True
      _ -> False
  in case tweet of
    SStatus statusObj -> langIsEnglish statusObj
    SRetweetedStatus (RetweetedStatus {rsRetweetedStatus=statusObj}) ->
      langIsEnglish statusObj
    _ -> False
 -- Filters Twitter tweets that are original posts
tweetParser :: StreamingAPI -> Maybe String
tweetParser tweet = case tweet of
  SStatus (Status {statusText=status}) -> Just $ unpack status
  SRetweetedStatus (RetweetedStatus {rsRetweetedStatus=rstatus}) ->
    Just $ unpack $ statusText rstatus
  _ -> Nothing
main :: IO ()
main = do 
    -- a bunch of connection setup details to Twitter
    {-
      Imagine a stream/production line of continually incoming Twitter tweets
      out of this stream, non-English tweets are removed
      each remaining tweet then gets packaged into one of two forms
        - one for original tweets
        - one for non-original tweets (retweets and whatnot)
      We then only grab packaged forms of original tweets and display them!
    -}
    in runResourceT $ do
      stream <- stream twitterInfo connectionManager apiRequest
      stream $=+
        Data.Conduit.List.filter filterEnglishTweets $=+
        Data.Conduit.List.map tweetParser $=+
        Data.Conduit.List.catMaybes $$+-
Data.Conduit.List.mapM_ (liftIO . putStrLn)

Haskell — строгий функциональный язык программирования. Он может проверять входящие структуры данных и работать с ними, если они соответствуют определенным требованиям.

Среда выполнения — необходимо знать, как ваше приложение будет работать на различных системах. Нужен ли языковой интерпретатор (например, Python, NodeJS, PHP)? Генерируется ли зависимый от архитектуры системы бинарник (например, Swift и GoLang)? Использует ли выбираемый язык сочетание первого и второго варианта, например, приложение компилируется и запускается на некоторой виртуальной машине (Java, Scala, Clojure)?
Кстати, на пути к совершенству очень рекомендуется изучить и начать использовать Docker плюс обязательно разобраться с принципами администрирования Linux.

Библиотеки — каждый язык хорошо подходит в определенных ситуациях. Например, Java соответствует множеству требований оркестровки и сетевой логистики, включая поддержку баз данных через стандартизацию интерфейса JDBC и проекты, подобные тем, которые подпадают под поддержку Apache Foundation. То же самое касается Python — он идеален для анализа данных и статистических подсчетов, — а также Haskell с его грамматиками, регулярными выражениями и компиляторами. Популярность языка и размер его сообщества — еще два аргумента, которые говорят в пользу использования определенного средства программирования в своем проекте. Если коммьюнити невелико, то на скорую развернутую помощь его участников рассчитывать не стоит. И, наоборот, чем больше сообщество и популярнее язык программирования, тем быстрее можно решить сложную задачу или получить совет от коллег.

Garbage Collection

«Сборка мусора» — одна из форм автоматического управления памятью. Специальный процесс, называемый garbage collector, периодически освобождает память, удаляя объекты, которые уже не будут востребованы приложениями. Каждый язык программирования выполняет это по-своему.

Python реализует подсчет ссылок посредством алгоритма «stop-the-world». Он приостанавливает выполнение программы, запускает и выполняет сборку мусора, затем возобновляет выполнение основного процесса. В ходе «уборки» фигурирует 3 отдельных «поколения» — комплекта «мусорных куч». Нулевое содержит самые «свежие» объекты, затем идут поколения 1 и 2.

import gc
import ctypes
gc.set_debug(gc.DEBUG_SAVEALL)
class PyObject(ctypes.Structure):
    _fields_ = [("refcnt", ctypes.c_long)]
object1 = {}
object2 = {}
object3 = {}
object1['reference_to_2'] = object2
object2['reference_to_1'] = object1
object3['some_key'] = 1
object1_memory_address = id(object1)
object2_memory_address = id(object2)
object3_memory_address = id(object3)
print "Before garbage collection --->"
print "Refcount for object1: {count}".format(
  count=PyObject.from_address(object1_memory_address).refcnt
)
print "Refcount for object2: {count}".format(
  count=PyObject.from_address(object2_memory_address).refcnt
)
print "Refcount for object3: {count}".format(
  count=PyObject.from_address(object3_memory_address).refcnt
)
del object1, object2, object3
gc.collect()
print "After garbage collection --->"
print "Refcount for object1: {count}".format(
  count=PyObject.from_address(object1_memory_address).refcnt
)
print "Refcount for object2: {count}".format(
  count=PyObject.from_address(object2_memory_address).refcnt
)
print "Refcount for object3: {count}".format(
  count=PyObject.from_address(object3_memory_address).refcnt
)
print "Objects that cannot be cleaned up by reference counting: --->"
for x in gc.garbage:
print x

Реализация garbage collector на Python


Результаты работы программного кода, указанного выше

В PHP (начиная с версии PHP5.3) используется еще один вариант сборки мусора наряду с подсчетом ссылок. Здесь этот процесс при необходимости выполняется вместе с программой. Подграфы, которые не могут быть достигнуты из корня, устраняются.

Swift также использует подсчет ссылок, иных способов сборки мусора здесь нет. Ниже показывается кейс, когда «сильный» счетчик объекта целиком доходит до 0 и очищается Person (поскольку он слабо соотносится с Apartment).

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}
 
class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }



Примеров механизмов сборки мусора, реализованных в других языках, множество. Они могут как затрагивать общую производительность приложения, так и работать без влияния на выполнение основной задачи.

Повторяющиеся концепции


Создание пакетов и управление ими

Знакомьтесь с механизмами хранения и отслеживания зависимостей, а также способами поддержания информации о «сборке» (описание пакета, порядок запуска модульных тестов, настройки и подготовки среды и т.п.).

Python использует pip in tandem with a requirements.txt file для управления зависимостями и setup.py для управления настройками окружения, Haskell работает с Cabal для решения обеих задач, у Java есть Maven и Gradle, в случае Scala работает SBT, PHP использует Composer, NodeJS — npm? и т.п.

Обязательно нужно определиться с локализацией окружения разработки — возможно, вы захотите запустить разные версии языков программирования в зависимости от проекта. Phpbrew для PHP, pyenv для Python и nvm для NodeJS дают возможность это сделать.


Используя pyenv, можно работать с разными версиями Python.

В частных случаях бывает так, что библиотека, использованная в одном проекте, автоматически устанавливается в другие. Это актуально, в частности, для языков вроде Python и Haskell. Чтобы избежать этой проблемы, стоит использовать virtualenv/venv для Python, virtphp для PHP и Cabal Sandboxes для Haskell.



Асинхронный ввод/вывод

Это возможность увеличить производительность ввода-вывода данных приложения. При этом каждый тред работает с собственным набором регистров и информации о стеке.



const https = require("https");
const urlList = [
  "https://reqres.in/api/users?page=1",
  "https://reqres.in/api/users?page=2",
  "https://reqres.in/api/users?page=3"
];
function getSiteContents(url) {
  return new Promise(function (resolve, reject) {
    https.get(url, function (res) {
      var bodyData = "";
      res.on("data", function (chunk) {
        bodyData += chunk;
      });
      res.on("end", function () {
        resolve(bodyData);
      });
      res.on("error", function (error) {
        reject(error.message);
      });
    });
  });
}
 // One way we can proceed with execution
// Make one Promise out of a list of Promises
Promise.all(urlList.map(getSiteContents))
  .then(function (siteContents) {
    console.log("Promise based execution --->");
    console.log(siteContents);
  });
 // Another way we can proceed with execution
// "async" is an ES7 feature that makes our Promise/async I/O code look
// more synchronous
async function main () {
  const siteContents = await Promise.all(urlList.map(getSiteContents))
  console.log("Main() based execution --->");
  console.log(siteContents);
}
main();
// As Promises will happen in some future time, this will happen first
console.log("This console.log will most likely happen first");

Реализация асинхронного I/O с использованием Javascript

Функциональное программирование

Функциональное программирование позволяет «рассказать» компьютеру на высоком уровне, что вы от него, собственно, хотите. Большинство языков сегодня имеют самые базовые возможности для реализации этого: через map, filter, reduce for lists и т.п. Но это все равно стоит использовать. Ниже показан пример функционального программирования на языке, который вроде бы не предполагает такой возможности.

<?php
// Accumulator gets passed around for reuse - function as a value
$accumulator = function (
  string $accumulated_string,
  string $mapped_list_element
) {
  return $accumulated_string . $mapped_list_element . "\n";
};
// Notice how array_map, array_filter and array_reduce
// accept functions as parameters - they are higher order functions
$mapped_array = array_reduce(
  array_map(
    function (int $list_element): string {
      return "A list element: " . $list_element;
    },
    [1, 2, 3, 4]
  ),
  $accumulator,
  ""
);
echo "Mapped Array: \n";
echo $mapped_array;
$filtered_array = array_reduce(
  array_filter(
    [1, 2, 3, 4],
    function (int $list_element): bool {
      return $list_element > 2;
    }
  ),
  $accumulator,
  ""
);
echo "Filtered Array: \n";
echo $filtered_array;
// Closures "enclose" over their surrounding state
// The $closure_incrementer function here returns a function
// making it a higher order function.
echo "Closure Incrementer: \n";
$closure_incrementer = function () {
  $internal_variable = 0;
  return function () use (&$internal_variable) {
    return $internal_variable += 1;
  };
};
$instance = $closure_incrementer();
echo $instance() . " is equal to 1\n";
echo $instance() . " is equal to 2\n";

Обучение


Первый этап — поиск необходимой информации на специализированных ресурсах и создание небольшого проекта после того, как базовая подготовка пройдена. В большинстве случаев можно воспользоваться статьями вроде «Выучи Х за Y дней», многие из них весьма хороши. Во многих случаях есть интерактивные примеры для обучения: A Tour of GoLang и GoLang by example (для GoLang), NodeSchool Command Line exercises (для Javascript, а именно NodeJS), Scala Exercises (для Scala), Python Koans (для Python) и т.п.

Начинать с чего-то сложного не стоит. Создание небольших приложений и скриптов — то, что нужно новичку. Общее количество строк кода в таких опытах не превышает 300–400. Главное, что необходимо на этом этапе, — получить базовую информацию, научиться программировать со сколь-нибудь нормальной скоростью и самое важное — понимать, что вы делаете.

func containedClosureIncrementer() -> (() -> Int) {
    var anInt = 0
    func incrementer() -> Int {
        anInt = anInt + 1
        return anInt
    }
    return incrementer
}
func containedClosureIncrementer2() -> () -> Int {
    var anInt = 0
    return {
        anInt = anInt + 1
        return anInt
    }
}
 
let closureIncrementer = containedClosureIncrementer()
print("containedClosureIncrementer call - should be 1: \(closureIncrementer() == 1)")
print("containedClosureIncrementer call - should be 2: \(closureIncrementer() == 2)")
 
var someOptionalValue: Optional<String> = nil;
print("Optional - someOptionalValue is null: \(someOptionalValue == nil)")
someOptionalValue = "real value"
print("Optional - someOptionalValue is 'real value' \(someOptionalValue == "real value")")
 
(["real value", nil] as Array<Optional<String>>).forEach({
    someOptionalValue in
    if let someValue = someOptionalValue {
        if someValue.hasPrefix("real") {
            print("someValue: has real")
        } else {
            print("someValue: doesn't have real")
        }
    } else {
        print("someValue: has nil")
    }
})
 
if (someOptionalValue ?? "").hasPrefix("real") {
    print("Has real 2")
} else {
    print("Doesn't have real")
}
 
let numbersList: [Int] = Array(1...10)
print("List of numbers 1 to 10: \(numbersList)")
let numbersListTimes2 = numbersList.map({
    (someNumber: Int) -> Int in
    let multiplicand = 2
    return someNumber * multiplicand
})
let numbersListTimes2V2 = numbersList.map({
    number in number * 2
})
let numbersListTimes2V3 = numbersList.map {
    $0 * 2
}
print("List of numbers * 2: \(numbersListTimes2)")
print("V1, V2 Map operations do the same thing: \(numbersListTimes2 == numbersListTimes2V2)")
print("V1, V3 Map operations do the same thing: \(numbersListTimes2 == numbersListTimes2V3)")
 
func testGuard() {
    let someOptionalValue: Optional<String> = nil;
    guard let someOptionalValueUnwrapped = someOptionalValue else {
        print("testGuard: Thrown exception - nil value")
        return
    }
    print("testGuard: no exception - non-nil value: \(someOptionalValueUnwrapped)")
}
testGuard()
class RuntimeError: Error {}
[{throw RuntimeError()}, {1} as () throws -> Int].forEach {
    let returnValue = try? $0()
    if let returnValueUnwrapped = returnValue {
        print("List of closures: A normal value was returned \(returnValueUnwrapped)")
    } else {
        print("List of closures: An error was thrown")
    }
}

Пример начального скрипта, который дает представление начинающему программисту о том, как работает его код

Второй этап — более глубокое изучение языка, создание полноценного проекта, который уже нельзя назвать «детским». Во многих случаях необходимо знакомиться с официальной документацией. Для Javascript это Mozilla Developer Docs, для Swift — Swift Official Docs, для Java — Java Learning Trails, для Python — Python Official Docst. Особое внимание стоит обратить на онлайн-курсы с хорошими преподавателями.

Кроме того, стоит изучить другие проекты с открытым кодом. Ресурсы вроде Annotated jQuery source или Annotated BackboneJS source дают представление о том, как конкретный язык программирования и дополнительные библиотеки используются в профессиональных проектах.

Все это поможет создать собственный серьезный проект, например, десктопное приложение, веб-приложение, мобильную программу. Старайтесь использовать внешние библиотеки, когда вам нужны дополнительные инструменты и функции.



Не забывайте о производительности своего приложения, всегда старайтесь черпать информацию из новейших источников. Возможности обучения бесконечны, совершенствоваться можно вечно. Но в конце концов вы можете почувствовать, как из новичка стали профессионалом — и лучшего ощущения в мире просто нет.
Skillbox рекомендует:

Комментарии (34)


  1. Mishkun
    28.08.2018 14:59

    Большинство языков сегодня имеют самые базовые возможности для реализации этой возможности: через карту, фильтр, сокращение для списков и т.п.

    Аж передернуло от такого перевода. Пользуйтесь техническим словарём, термины в ФП взяты из математики. map, кроме того что это карта, еще переводится как «отображение», а reduce правильно перевести как «свёртка», но лучше на самом деле оставить эти три слова без перевода, ведь это устоявшиеся названия операций над списками


  1. saag
    28.08.2018 15:57
    +2

    Можно вставить мои пять копеек по выбору ЯП? Выбор языка программирования это как выбор женщины, представьте вы вошли в бар «Последний приют» и перед вами стоят: Быстрая, Красивая, Словоохотливая, Румяная, Одноглазая, Молодая, Силиконовая, Добрая, Транжира, В очках, Гламурная, Мутантка, Старая, Ведьма выберите свой идеал и вы поймете какой язык программирования вам нужен.:-)


    1. claygod
      28.08.2018 17:50

      Ну очевидный выбор-то, «силиконовая» (ака кремниевая) же))


      1. kost
        28.08.2018 23:40

        silicone != silicon


    1. sergof
      28.08.2018 17:55

      Быстрая Румяная Мутантка. Очевидно же!


      1. Vadem
        28.08.2018 17:58
        +2

        С++?


      1. saag
        28.08.2018 18:03

        C + 1C + Objective-C


        1. Vadem
          28.08.2018 18:06

          Румяная это Rust ещё может быть.


      1. franzose
        29.08.2018 03:43

        Старая Гламурная Ведьма В очках)))


        1. saag
          29.08.2018 07:12

          Ассемблер + Swift + Perl + Python


    1. Free_ze
      28.08.2018 18:25

      Хорошо, что не под цвет галстука. Что важно: блуд здесь идет только на пользу.


    1. kaichou
      28.08.2018 18:34

      Умной нет?


      1. saag
        28.08.2018 18:42

        Они все умные, в разной степени конечно.:-) Точнее каждая по своему:-)


      1. roscomtheend
        29.08.2018 11:14

        Вы пришли не первым.


    1. usbstor
      29.08.2018 12:20

      можно расшифровать, что они означают? C# например кто?


      1. saag
        29.08.2018 16:06

        Добрая


    1. PlatinumThinker
      29.08.2018 13:48

      По хорошему ЯП выбирается под задачу, т.к. это всего лишь инструмент. Программисты не должны так сильно привязываться к одному языку


  1. 1Fedor
    28.08.2018 16:21

    Я сильно извиняюсь, но не понял, что есть «три совета»?


  1. aikixd
    28.08.2018 16:57

    Есть 3 языка: объектный, функциональный и С++ (возможно Раст тоже, но я только по наслышке). Все остальное детали реализации.


    1. scg
      28.08.2018 17:23

      Есть еще стековый, вроде Forth :)


      1. BalinTomsk
        28.08.2018 19:00

        SQL же


    1. 0xd34df00d
      28.08.2018 20:10

      В какой класс отнести лисп, в какой класс отнести какой-нибудь из современных ML-подобных, и насколько они близки друг к другу?


      1. geher
        28.08.2018 22:14

        Лисп — функциональный вроде. Но еще пролог есть.


        1. aidarchikable
          29.08.2018 10:01

          Пролог не функциональный. Пролог (англ. Prolog) — язык и система логического программирования, основанные на языке предикатов математической логики дизъюнктов Хорна, представляющей собой подмножество логики предикатов первого порядка.


          1. geher
            29.08.2018 10:40

            Так и я и не утверждал, что пролог функциональный.
            Лисп был предложен ранее в качестве языка, не попадающего в предложенную еще ранее классификацию. В этом качестве я и предложил пролог вместо лиспа.


  1. Terras
    28.08.2018 19:58
    +1

    А где языки платформы .net, или аппле конфликтует с Microsoft?


    1. venom280
      29.08.2018 03:47

      В Apple как и в других компаниях, у каждой команды свой стек технологий, просто конкретно в этой .Net не используют.
      Автор статьи — это инженер первой категории после стажировки, судя по технологиям он скорее всего работает в отделе IS&T (Information services and technology). Как раз там можно встретить PHP, jQuery и другие подобные штуки.


  1. javax
    28.08.2018 22:39
    +2

    Человек, который поймет этот текст сам разберется, какой язык ему нужен


  1. KoToSveen
    29.08.2018 05:57

    Интересно будет кому-то и ли нет, но я опишу свою историю выбора ЯП:

    • В школе преподавали Basic, на нём и писал программы в рамках школьной программы.
    • Курсы оператора ПК: Clipper, Pascal. Выпускная работа была написана на Clipper.
    • Университет: С++, Ассемблеры. Позже не использовал никак.
    • 1-е место работы: HTML, PHP, SQL по собственной инициативе.
    • Текущее место работы: в обязанности входит поддержание и развитие кучи легаси, написанного на: Clipper, C++ Builder 6, VisualBasic 6.0, Delphi. Периодически читаю учебники по C#, Java, JavaScript, но увеличивать уже существующий зоопарк особого желания нет. Есть идея переписать всё, но это нереально и бессмысленно.


    1. VolCh
      29.08.2018 08:20

      И давно текущее место работы? Нет опасений, что рано или поздно это всё закончится по каким-то причинам и надо будет искать новую работу на открытом рынке? Навскидку вакансий по Clipper, C++ Builder 6, VisualBasic 6.0, Delphi практически нет.


      1. KoToSveen
        29.08.2018 08:28

        На текущем месте третий год работаю.

        Нет опасений, что рано или поздно это всё закончится по каким-то причинам
        по Clipper, C++ Builder 6, VisualBasic 6.0 можно сделать вывод, что предприятие работает уже не первый десяток лет.
        Навскидку вакансий по Clipper, C++ Builder 6, VisualBasic 6.0
        Было бы странным, если бы они были. Про Delphi такого не скажу.


        1. VolCh
          29.08.2018 11:49

          можно сделать вывод, что предприятие работает уже не первый десяток лет.

          Можно сделать и другие выводы, например, что недавно одно предприятие было (или скоро будет) как неконкурентное (в том числе и из-за консервативности в области ИТ) поглощено другим и вполне реалистичен переход на стандарты (в том числе в области ИТ) новых хозяев. Часто это сопровождается массовыми увольнениями, как их не называй, сокращениями, оптимизациями или ещё как. Ну или просто решат купить "коробку" или облачное какое решение.


          В рыночных условиях десятки лет работы лишь уменьшают вероятности резких изменений различных политик компаний, да и самого её существования.


          Было бы странным, если бы они были.

          Ну вот решите вы всё-таки чему-то новому научиться и уйдёте куда-то где новые навыки более востребованы — и появится минимум одна :)


      1. roscomtheend
        29.08.2018 11:27

        Delphi всё ещё встречаются — объём кодовой базы проектов (вполне живых и развивающихся) такой, что попытки переписать на чём-то современном обычно стухают в начале (добавить туда часто отсутствие документации по многим моментам из-за древности и, зачастую, институтского проекта 20+ летней давности как затравки этого монстра), да ещё часть команды соттвутствуют возрасту проекта и не готовы к новому. Тут должно сильно припереть для перехода, да ещё и ресурсы в наличии не помешают (денежные и временнЫе). Переход с Clipper, VB, Builder, файловых БД(dbf/pdx) был легче из-за меньших объёмов и меньшего срока жизни к моменту перехода (и то он происходил несколько лет). Выкатить замену за пару месяцев зачастую нельзя, а пользователи не очень хотять делать пол-работы в старом софте, а половину — в новом, начальство же подобных контор не готово вкладываться в долгую перспективу, «как полгода не будет видно результата? А за что мне платить тогда?».


  1. domix32
    29.08.2018 13:50

    Асинхронный != многопоточный. Весь абзац про асинхронность порезан и некорректен.