去日企当程序员是什么体验?

文章讨论了一位收到COBOLOffer的人的纠结,分析了COBOL的历史地位、前景、与Java的对比,鼓励在面临不确定时,接受offer作为跳板,同时强调持续学习的重要性。

微信上收到一条私信,大致的情况是这样的:他接到了一家日企的 Offer,COBOL 方向的。他去网上查了一下,大部分都是劝退的。他很担心干了几年 COBOL,再转 Java 会因为没有项目经验,而找不到新的工作。。

图片

考虑到应该还有个别小伙伴有类似这样的疑惑:接到的 offer 不是很满意,也没有其他更好的选择,那这个 offer 是接还是不接呢?

我把自己的想法整理了一下,希望能给需要的小伙伴一点点启发和帮助~

一、COBOL 的前世今生

讲真,这位球友有这样的疑惑确实是情理之中,我估计在座的各位有很多听都没有听过 COBOL。

COBOL 可以说是编程语言中的“上古卷轴”了,第一个正式版发布于1960年4月。COBOL 标准的制定者之一——格蕾丝·霍珀是一位女博士,历史上第一个计算机程序的“BUG”就是由她发现并记载下来的。

图片

六十年下来,COBOL 程序已经形成庞大的规模,从社会保障卡信息存储和处理,到 ATM 机,COBOL 的身影无处不在。由于更新系统的成本实在太过高昂,再加上审批流程等非技术性原因,导致这些遗留系统一直没能更新换代。

我看了一下 2023 年最新的 TIOBE 编程语言排行榜,COBOL 竟然还能排在第 24 位,比我经常听到的 Lua、Perl、Julia、Scala、Lisp 还要靠前。。

图片

我只能说,COBOL 实在是太无情了,60 多年还能榜上有名。。你叫其他小弟情何以堪?

二、COBOL 的前景和学习资源

干过银行相关的技术岗的话,应该对 COBOL 比较熟悉,甚至会觉得 COBOL 严重缺人。只要你肯去做,愿意全国各地跑一跑,哪怕是 0 经验,都会有公司要。

虽然随着时间的推移,COBOL 程序员会越来越少,但就目前来看,确实还是有工作机会的,并且在学历上也不会卡的非常严苛,薪资待遇还算是说得过去。

图片

如果现阶段没有其他更好的 offer 选择,我认为 COBOL 不是不可以接受。

三、COBOL VS Java

COBOL 属于小众编程语言,Java 属于主流编程语言。两者直接进行 battle,多少有些不太公平。

如果你有更好的 offer,并且还是 Java 岗,那就不用选择,无脑冲 Java 就对了;如果只有一个 offer,没得选,我觉得 COBOL 还是可以缓冲一下的。

现实中,总有很多不尽如人意的事情发生,那我们所能做的,就是欣然接受,然后以此为跳板,去追求更好的。光有理想没有实力肯定是无法落地的,与其空谈不如脚踏实地地干。

拿这位球友的情况来说吧。

我问他手头还有其他 offer 可选吗?他说目前只有这家日企的 COBOL 岗。那我又问他,还能继续投简历继续参加面试吗?

他说还能,如果其他的面不上我是不是可以选择这个?

我的理解是选择小众领域的岗位意味着没有 Java 岗那么卷。再加上日企比较追求极致的稳定,这个选择其实没那么想象中那么坏。日企虽然在技术上不热衷于追求前沿,但福利也是比较到位的,除了五险一金,甚至高温补贴这种也给的很大方。

另外,如果有机会去国外出差的话,差旅费是非常可观的。

再者说,8 小时谋生存,8 小时谋发展。

选择了 COBOL 岗,并不意味着私下里没法学 Java 啊

即便是那些看起来只是靠工作和你拉开差距的同事,或者只是靠课堂和你拉开差距的同学,如果你肯细致观察的话,保准他在私底下付出了很多你不曾看到的努力和汗水。

我之前在一家外企的时候,情况也是类似。新人嘛,一开始的工作免不了打杂,经常被安排的任务是写一写 ruby 小程序、搞一搞 SQL 语句、甚至撸一撸 shell 脚本,但是私底下,我一直在研究公司新兴的技术框架,不仅能在这个技术框架的基础上造一些小轮子,甚至还能扒一扒源码解决一些核心问题。

等到时机成熟后,直接就晋升为 Team Leader 成为团队的中坚力量了。

所以,完全不用担心从小众编程语言切换到主流编程语言后项目经验为 0 的问题,除非是你自己放弃了技术上的求索。

四、不要只局限于某一门编程语言

再次给大家强调一下,永远不要把自己局限于某一门编程语言之上,即便 Java 现在是顶流,也要尝试去拥抱其他的编程语言,尤其是要重视计算机基础的学习。

Java 之父 Gosling 曾说过的一句话:“语言只是实现目标的工具,而不是目标本身。”

就像很多人会误认为 .NET 只能在 Windows 上跑,但其实 .NET 也是一个跨平台应用程序开发框架,不仅支持 Windows,还支持 macOS 以及 Linux,并且微软前几年已经把它开源了。

对于我们程序员来说,不应该存在任何偏见,学这个的看不起学那个的,某厂看不起某厂的,应该针对自身的情况,做出最有利于自己的选择,因为每一种编程语言都有自己的应用领域,而每个人的能力又千差万别。

对于我们国内的开发环境来说,Java 的势头的确很猛,我个人也是 Java 的重度使用者,但我私底下也在学习其他的编程语言,每种编程语言只要能发挥出它最大的优势,就是值得我们去学习和使用的。

人生如果没有更好的选择,就欣然接受,然后逆袭。。

package jp.or.jaf.syg.feature.jafrsho99.jafrsho99130 import jp.or.jaf.syg.core.common.base.JafViewModel import jp.or.jaf.syg.core.common.event.JafAction import jp.or.jaf.syg.core.common.event.JafEvent import jp.or.jaf.syg.core.common.ext.utils.DateUtils import jp.or.jaf.syg.domain.message.Message import jp.or.jaf.syg.feature.jafrsho99.jafrsho99010.Jafrsho99010Routes import jp.or.jaf.syg.feature.jafrsho99.jafrsho99050.JAFRSHO99050Model import jp.or.jaf.syg.feature.jafrsho99.jafrsho99130.mappers.createInitialUiStateData import jp.or.jaf.syg.feature.jafrsho99.jafrsho99130.mappers.generateCalendarData import jp.or.jaf.syg.feature.jafrsho99.jafrsho99130.mappers.generateSelectDayList import jp.or.jaf.syg.feature.jafrsho99.jafrsho99130.mappers.generateSelectMonthList import java.io.Serializable import javax.inject.Inject /** * 【機能ID: JAFRSHO99】業務共通機能 * 【画面ID: JAFRSHO99130】カレンダーポップアップ * * カレンダーポップアップのViewModel実装 * 年月日入力時に使用するポップアップである。 */ class JAFRSHO99130ViewModel @Inject constructor() : JafViewModel<JAFRSHO99130UiStateData>() { /** * システムイベント処理 * JafUiStateHostが自動的に呼び出すイベント処理 */ private var monthSelectResult: Pair<Any, Any>? = null private var daySelectResult: Pair<Any, Any>? = null override fun onEvent(event: JafEvent) { when (event) { JafEvent.Companion.Initialize -> { // パラメータなしの場合はデフォルト初期化 launchReplaceContent { onPopupDisplay("カレンダー", null, InputControlType.NO_SEIGEN) } } is JafEvent.Companion.InitializeWithParameters<*> -> { val params = event.params as? CalendarPopupParams launchReplaceContent { onPopupDisplay( params?.itemName ?: "カレンダー", params?.date, params?.inputControlType ?: InputControlType.NO_SEIGEN ) } } } } /** * Actionハンドリング * 各ActionIDは処理仕様のEYY形式と対応 */ override fun onAction(action: JafAction) { when (action) { is JAFRSHO99130Action.OnMonthSelect -> onMonthSelect() is JAFRSHO99130Action.OnDaySelect -> onDaySelect() is JAFRSHO99130Action.OnMonthScrollLeft -> onMonthScrollLeft() is JAFRSHO99130Action.OnMonthScrollRight -> onMonthScrollRight() is JAFRSHO99130Action.OnCalendarInput -> onCalendarInput(action.selectedDay) is JAFRSHO99130Action.OnClear -> onClear() is JAFRSHO99130Action.OnConfirm -> onConfirm() is JAFRSHO99130Action.OnClose -> onClose() is JAFRSHO99130Action.OnWindowClose -> onWindowClose() } } /** * 【処理仕様: JAFRSHO99130E001】画面表示 * カレンダーポップアップを作成する。 */ private fun onPopupDisplay( itemName: String, date: String?, inputControlType: Int ): JAFRSHO99130UiStateData { return createInitialUiStateData(itemName, date, inputControlType) } /** * 【処理仕様: JAFRSHO99130E002】月-選択 * 選択する候補月をプルダウン形式で表示する。 */ private fun onMonthSelect() { val currentData = getCurrentData() ?: return val currentDay = currentData.selectedDay val selectMonthList = generateSelectMonthList( currentDay,currentData.yearMonth.substring(0,4).toInt()) val monthParamList = selectMonthList.map { month -> Pair(first = "${month}月", second = month) } // 選択月リストの設定 val defaultSelectedMonth = if (currentData.selectedMonth.isNotEmpty()) { Pair( first = "${currentData.selectedMonth}月", second = currentData.selectedMonth ) } else { null } val params = JAFRSHO99050Model( listNameParam = monthParamList, listCountParam = monthParamList.size, listBoxSelectParam = defaultSelectedMonth, onConfirmCallBack = { result -> monthSelectResult = result val selectedMonth = result.second.toString() val currentYear = currentData.yearMonth.substring(0, 4) val targetDay = if (currentData.selectedDay.isNotEmpty()) { val maxDayOfNewMonth = generateSelectDayList( month = selectedMonth.padStart(2, '0'), year = currentYear, ).size val currentDayInt = currentData.selectedDay.toInt() if (currentDayInt > maxDayOfNewMonth) maxDayOfNewMonth else currentDayInt } else { 1 } val newYearMonth = "${currentYear}${selectedMonth.padStart(2, '0')}" val newCalendarData = generateCalendarData(newYearMonth, targetDay) updateSuccess { data -> data.copy( yearMonth = newYearMonth, selectedMonth = selectedMonth.padStart(2, '0'), selectedDay = targetDay.toString(), calendarData = newCalendarData, isMonthScrollLeftEnabled = newYearMonth != "190001", isMonthScrollRightEnabled = newYearMonth != "209912" ) } } ) navigate( route = Jafrsho99010Routes.LIST_SELECT, params = params as Serializable ) } /** * 【処理仕様: JAFRSHO99130E003】日-選択 * 選択する候補日をプルダウン形式で表示する。 */ private fun onDaySelect() { val currentData = getCurrentData() ?: return val currentYear = currentData.yearMonth.substring(0, 4) val currentMonth = currentData.yearMonth.substring(4, 6) val selectDayList = generateSelectDayList(currentMonth, currentYear) val dayParamList = selectDayList.map { day -> Pair(first = "${day}日", second = day) } // 選択日リストを設定 val defaultSelectedDay = if (currentData.selectedDay.isNotEmpty()) { Pair( first = "${currentData.selectedDay}日", second = currentData.selectedDay ) } else { null } val params = JAFRSHO99050Model( listNameParam = dayParamList, listCountParam = dayParamList.size, listBoxSelectParam = defaultSelectedDay, onConfirmCallBack = { result -> daySelectResult = result val selectedDay = result.second.toString() val newCalendarData = generateCalendarData( yearMonth = currentData.yearMonth, selectedDay = selectedDay.toInt() ) updateSuccess { data -> data.copy( selectedDay = selectedDay, calendarData = newCalendarData ) } } ) navigate( route = Jafrsho99010Routes.LIST_SELECT, params = params as Serializable ) } /** * 【処理仕様: JAFRSHO99130E004】月スクロール左-押下 * 月を1つ前に移動する。(例:202505⇒202504) */ private fun onMonthScrollLeft() { val currentData = getCurrentData() ?: return val currentMonth = currentData.yearMonth.substring(4, 6).toInt() val currentYear = currentData.yearMonth.substring(0, 4).toInt() val dayTmp = currentData.selectedDay val (newYear, newMonth) = if (currentMonth == 1) { Pair(currentYear - 1, 12) } else { Pair(currentYear, currentMonth - 1) } val newYearMonth = "$newYear${newMonth.toString().padStart(2, '0')}" val targetDay = if (dayTmp.isNotEmpty()) { val maxDayOfMonth = generateSelectDayList(newMonth.toString().padStart(2, '0'), newYear.toString()).size if (dayTmp.toInt() > maxDayOfMonth) maxDayOfMonth else dayTmp.toInt() } else { 1 } // カレンダー入力領域リフレッシュ val newCalendarData = generateCalendarData(newYearMonth, targetDay) updateSuccess { data -> data.copy( yearMonth = newYearMonth, selectedMonth = newMonth.toString().padStart(2, '0'), selectedDay = targetDay.toString(), calendarData = newCalendarData, isMonthScrollLeftEnabled = newYearMonth != "190001", isMonthScrollRightEnabled = newYearMonth != "209912" ) } } /** * 【処理仕様: JAFRSHO99130E005】月スクロール右-押下 * 月を1つ次に移動する。(例:202505⇒202506) */ private fun onMonthScrollRight() { val currentData = getCurrentData() ?: return val currentMonth = currentData.yearMonth.substring(4, 6).toInt() val currentYear = currentData.yearMonth.substring(0, 4).toInt() val dayTmp = currentData.selectedDay val (newYear, newMonth) = if (currentMonth == 12) { Pair(currentYear + 1, 1) } else { Pair(currentYear, currentMonth + 1) } val newYearMonth = "$newYear${newMonth.toString().padStart(2, '0')}" val targetDay = if (dayTmp.isNotEmpty()) { val maxDayOfMonth = generateSelectDayList(newMonth.toString().padStart(2, '0'), newYear.toString()).size if (dayTmp.toInt() > maxDayOfMonth) maxDayOfMonth else dayTmp.toInt() } else { 1 } val newCalendarData = generateCalendarData(newYearMonth, targetDay) updateSuccess { data -> data.copy( yearMonth = newYearMonth, selectedMonth = newMonth.toString().padStart(2, '0'), selectedDay = targetDay.toString(), calendarData = newCalendarData, isMonthScrollLeftEnabled = newYearMonth != "190001", isMonthScrollRightEnabled = newYearMonth != "209912" ) } } /** * 【処理仕様: JAFRSHO99130E006】カレンダー入力領域-押下 * カレンダー表示領域での日付選択処理 */ private fun onCalendarInput(selectedDay: Int) { val currentData = getCurrentData() ?: return val currentSelectedDay = currentData.selectedDay.toIntOrNull() ?: 0 // 同じ日が選択された場合は処理終了 if (selectedDay == currentSelectedDay) { return } // 項目定義を設定 val monthTmp = currentData.yearMonth.substring(4, 6) // 日にち強調表示設定 val newCalendarData = generateCalendarData(currentData.yearMonth, selectedDay) updateSuccess { data -> data.copy( selectedDay = selectedDay.toString(), selectedMonth = monthTmp.padStart(2, '0'), calendarData = newCalendarData ) } } /** * 【処理仕様: JAFRSHO99130E007】クリア-押下 * 入力された日付をクリアする */ private fun onClear() { val today = DateUtils.getCurrentFormatString(DateUtils.TYPE_5) val yearMonth = today.substring(0, 6) val selectedMonth = today.substring(4, 6).toInt().toString() val selectedDay = today.substring(6, 8).toInt() val newCalendarData = generateCalendarData(yearMonth, selectedDay) updateSuccess { data -> data.copy( yearMonth = yearMonth, selectedMonth = selectedMonth.padStart(2, '0'), selectedDay = selectedDay.toString(), calendarData = newCalendarData, isMonthScrollLeftEnabled = yearMonth != "190001", isMonthScrollRightEnabled = yearMonth != "209912" ) } } /** * 【処理仕様: JAFRSHO99130E008】確定-押下 * 選択された日付を確定して呼び出し元に返却 */ private fun onConfirm() { val currentData = getCurrentData() ?: return if (currentData.selectedMonth.isNotEmpty() ||currentData.selectedDay.isNotEmpty()) { val year = currentData.yearMonth.substring(0, 4) val month = currentData.selectedMonth.padStart(2, '0') val day = currentData.selectedDay.padStart(2, '0') val dateTmp = "$year/$month/$day" onConfirmCallback(dateTmp) }else{ showMessage( Message.JAFRSHO99010IC00230.id, listOf("") ) } navigateBack() } /** * コールバックメソッド */ fun onConfirmCallback(dateTmp: String) = Unit /** * 【処理仕様: JAFRSHO99130E009】閉じる-押下 * ポップアップを閉じる */ private fun onClose() { navigateBack() } /** * 【処理仕様: JAFRSHO99130E010】×(閉じる)-押下 * ウィンドウの×ボタンでポップアップを閉じる */ private fun onWindowClose() { navigateBack() } } /** * カレンダーポップアップの初期パラメータ */ data class CalendarPopupParams( /** 項目名 */ val itemName: String, /** 年月日 */ val date: String?, /** 入力制御種別 */ val inputControlType: Int ) 在onConfirm方法中加一个check IF (inputControlType(入力制御種別) == FUTURE_SEIGEN) ❘ ❘ IF (dateTmp(年月日) > (LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE))) ❘ ❘ ❘ ❘ 業務共通部品(メッセージダイアログ)を呼び出し、エラーメッセージ「未来日の入力はできません。」を表示する。 ❘ ❘ 呼び出し関数名 【画面表示】メッセージダイアログ ❘ ❘ 処理ID JAFRSHO99020 ❘ ❘ 引数 メッセージID "JAFRSHO99010EC00161" ❘ ❘ メッセージパラメータ なし ❘ ❘ 戻り値 なし ❘ ❘ ❘ ❘ 「OK」ボタンを押下すると、処理を終了する。 ❘ ❘ ❘ END IF ❘ ELSE IF (inputControlType(入力制御種別) ==PAST_SEIGEN) ❘ ❘ IF (dateTmp(年月日) < (LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE))) ❘ ❘ ❘ ❘ 業務共通部品(メッセージダイアログ)を呼び出し、エラーメッセージ「過去日の入力はできません。」を表示する。 ❘ ❘ 呼び出し関数名 【画面表示】メッセージダイアログ ❘ ❘ 処理ID JAFRSHO99020 ❘ ❘ 引数 メッセージID "JAFRSHO99010EC00098" ❘ ❘ メッセージパラメータ なし ❘ ❘ 戻り値 なし ❘ ❘ ❘ ❘ 「OK」ボタンを押下すると、処理を終了する。 ❘ ❘ ❘ END IF ❘ END IF
最新发布
09-26
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值