我的奶奶

有人说没人记得自己祖上三代,这话还真对。我奶奶的父母姓甚名谁,我是一概不知。她有几个兄弟姐妹,我也从未见过。一个世道有一个世道的故事。悲欢离合比电影还强烈,到了我这一代就丢失了很多细节,导致我知道的东西很少。

我奶奶有一个哥哥还是弟弟,是在本县,去世的很早,我没有见过,只见过其儿子及其家人。奶没过世前,我几乎很少意识到这层亲戚关系。真是一代人有一代人的成长环境和亲戚朋友,隔了几代的亲戚对人而言就没那么亲。

我奶奶还有一个姐姐,在隔壁县,现在有九十多岁,还健在,也是个劳碌命,听说八十几岁还能种田。她们姐妹似乎是从小分离,估计几十年没有见过了。两人互相见了,估计也不认识。我也没有见到她们见面时的场景。关于见面时的场景,或者亲姐妹之间想不想见,我也不能和我奶奶考证了。

所以,我奶她们一共 3 个兄弟姐妹。

我奶出生于 1941 年的 a 村,在那个年代,家里穷苦,没有饭吃。好像是说,我奶很早就被抱走到了现在的 b 村。至于我奶的父亲,听说是战争时期被抓壮丁了,被哪个党派抓走,我也不知道。只是战争结束后,也没有回来,也没有收到组织的牺牲通知,不了了之。我奶母亲的故事,我没有听到一个字。

我奶是刚出生被抱到现在的 b 村的,她爸应该是姓周,给别人做女儿就改姓了曾。说到抓壮丁,曾姓有个长辈也是被抓壮丁,后面跟着去了台湾,90 年代死之前回来过大陆寻亲,好像还送了我曾祖母一个黄金手镯。可惜他不识字,也没有妻儿,一生孤苦,最后应该也是死在了台湾。我见过他的照片,这次奶奶去世,不知道这张照片有没有火化掉。

至于我的奶童年时期,青春时期的故事,我是没有听过,全然不知。她们那个时候嫁人很早,嫁给我爷之后,去本县的 c 村子里生活过一段时间。后来好像是和某位妯娌矛盾太大,生活不下去,又回到 b 村。我爷原本姓李,给我曾祖父做了儿子后,改姓曾。如果仔细考究起来,我的曾祖父母和外曾祖父母就有点多。

影视剧里说吕布是三姓家奴,我奶他们只是为了活下去。

告别

印象里非常深刻,电影《少年派的奇幻漂流》的一句台词:人生就是不断地分离,只是我们还没来得及好好告别。

我奶奶是很怕死的,在他老人家觉得老年委屈的时候,时常和我说,人一念到死就没有味道。你想想人死了,四肢僵硬,躺在棺材里,埋在土里,泥土多么冰凉,石头多么硌人。这时候她要流眼泪。身处壮年的我总要代入自己,觉得人固有一死,内心里有点嗤之以鼻。

活人谈死亡,总觉得遥不可及,不会放在心上。毕竟目前所有的文字音视频材料都是活人留下的,人没有真正经历的东西,谈出来的总是有点肤浅。

继续阅读“告别”

【深圳】【非远程】【持续招聘中】国产电气工业软件 ecad 招聘前端工程师 20-30k

简历发送:zenghaixia#sz-jlc.com

产品体验:https://jlc-ecad.com/editor

技术栈:React、canvas 2d、webgl、自建 UI 组件库

一、岗位职责:

负责 ecad 绘图软件的 UI 交互、基础组件搭建、核心 api 的设计;
负责绘图功能的完善、性能调优、内存泄漏排查;
设计开发者工具,优化团队的开发者体验,提升项目的稳定性、健壮性。

二、任职要求:

本科及以上学历,有 React 项目开发经验;
熟练掌握 React 及其相关生态,如 jotai、zustand、ant design 等;
精通 HTML5、CSS3,熟悉 ES6 + 语法,能够手写高性能的前端代码;
了解 Vite 等前端构建工具,能够进行基本的配置与优化;
具备良好的问题解决能力,能够独立分析和解决前端技术难题;
具有较强的学习能力和创新精神,能够快速掌握新技术并应用到项目中;
良好的团队协作精神,能够与不同部门的人员有效沟通与合作;
有大型前端项目架构设计经验者优先,维护过开源 UI 组件者优先。

为什么说生活的仪式感来自于去菜市场买菜?

现在手机买菜很方便,手机点一点,菜就送上门了,但是完全失去了生活的灵魂。我们就像被圈养在钢筋水泥里的牛马一样,等着食物上门。人的活性在于需要去外面觅食。

所以我更倾向于去菜市场。

春天能在菜市场买到什么,和秋天能在菜市场买到什么,肯定不同。为了能感受到这份生活感,去菜市场买菜,就很有必要。去一趟菜市场,听一听菜商的叫卖,和砍价声的来来回回,在城市里生活,才能感受到这份久违的生活气息。这远比吃预制菜,网上买菜更有烟火气。

继续阅读“为什么说生活的仪式感来自于去菜市场买菜?”

面试不过的前端简历都有这 10 个特征

2025 年团队多出了两个名额,加上原有团队成员变动,导致这一年几乎都有面试。刚开始初次面试,还有点新鲜感,面到后面,只觉身心俱疲,难怪喊老板面,老板都不想参与。

经过一年的面试,我发现具有以下特点的简历都不能通过面试,不是说简历没有写好面试不能过,而是因为本身的素质导致写出了这样的简历。

继续阅读“面试不过的前端简历都有这 10 个特征”

我已经很久不用洗发水和沐浴露

用洗发水和沐浴露是小时候就养成的习惯了,从来没有思考过,为什么要用。我也没有去考究洗发水这种东西是什么开始流行的,一直觉得这个得必须用。直到 2022 年,一次洗发水用完了,我再也没有买。

一开始不用洗发水是觉得自己可能要秃顶了,得排查一下原因,先控制一下变量。刚开始几天,确实有点不习惯,觉得头洗不干净,有点油。过不了 2-3 个月,就适应了。人体是很神奇的系统,会自我调节,自己控制出油量。以前 2 天不洗头,黏糊糊的感觉似乎能造出任意发型了。现在 2 天不洗头,也不会觉得很油,脑袋感觉还是很清爽。

继续阅读“我已经很久不用洗发水和沐浴露”

从几个单词聊香港大火

《红楼梦》的英文译名,有几种译法,一种是《A Dream of Red Mansions》,一种是《A Dream of Red Chamber》。我特意去查了一下,mansion 和 chamber 这 2 个单词是什么意思,用的字典是《牛津高阶英汉双解词典》。

mansion:a large,impressive house。中文译为公馆,宅邸。大而漂亮的房子,很符合贾家的大门大户。

chamber:a hall in a public building that is used for formal meetings。中文译为会议厅,这个翻译似乎不是很妥当,没有上面的贴切。

自然而然,我也联想到了 house 和 building 是什么。我们也来一起查一下。

house:a building for people to live in,usually for one family。房屋,住宅。只针对一家一户的。

building:a structure such as a house or school that has a roof and walls。建筑物,楼房。这个单词更偏向建筑,不一定指代是家,还有更多钢筋水泥的味道。

继续阅读“从几个单词聊香港大火”

A monad demo given by AI

// Generic Monad structure
class Monad {
  constructor(value) {
    this.value = value;
  }

  // Bind: chains computations that return a Monad
  bind(fn) {
    return fn(this.value);
  }

  // Unit: wraps a value in the Monad
  static of(value) {
    return new Monad(value);
  }

  // For debugging
  get() {
    return this.value;
  }
}

// Example: Maybe Monad
class Maybe extends Monad {
  bind(fn) {
    if (this.value == null) {
      return new Maybe(null);
    }
    return fn(this.value);
  }

  static of(value) {
    return new Maybe(value);
  }

  getOrElse(defaultValue) {
    return this.value == null ? defaultValue : this.value;
  }
}

// Demo: chaining computations with Monad
const double = x => Monad.of(x * 2);
const increment = x => Monad.of(x + 1);

const result = Monad.of(5)
  .bind(double)      // 10
  .bind(increment);  // 11

console.log(result.get()); // Output: 11

// Demo: chaining with Maybe Monad
const safeDivide = x => x === 0 ? Maybe.of(null) : Maybe.of(10 / x);

const maybeResult = Maybe.of(2)
  .bind(safeDivide)       // 10 / 2 = 5
  .bind(x => Maybe.of(x + 3)); // 8

console.log(maybeResult.getOrElse("fail")); // Output: 8

const maybeFail = Maybe.of(0)
  .bind(safeDivide)       // null
  .bind(x => Maybe.of(x + 3));

console.log(maybeFail.getOrElse("fail")); // Output: "fail"

maybe functor

class Maybe {
  constructor(value) {
    this.value = value;
  }

  // Functor map: applies a function if value is not null/undefined
  map(fn) {
    if (this.value === null) {
      return new Maybe(null);
    }
    return new Maybe(fn(this.value));
  }

  // getOrElse: safely extract value with a fallback
  getOrElse(defaultValue) {
    return this.value === null ? defaultValue : this.value;
  }

  // static helpers for convenience
  static of(value) {
    return new Maybe(value);
  }

  static nothing() {
    return new Maybe(null);
  }
}

// Example usage:
const maybeNumber = Maybe.of(5)
  .map(n => n * 2)
  .map(n => n + 1);

console.log(maybeNumber.getOrElse(0)); // Output: 11

const maybeNull = Maybe.of(null)
  .map(n => n * 2);

console.log(maybeNull.getOrElse(0)); // Output: 0