V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
coffeygao
V2EX  ›  PHP

来一波"laravel 黑",其实是个人问题。并非为框架本身

  •  
  •   coffeygao · 2018-09-29 16:29:00 +08:00 · 6327 次点击
    这是一个创建于 2248 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这几天领导让我增加一个公众号推送消息的功能,看了下同事以前写的一套,惨不忍睹,这并非优雅的 laravel,我是个 symfonyer。见到这种代码,很想打人。所有的方法统一写在了 wechatService 里。不管有无关联

    这是控制器,功能是得到微信的种种信息,然后针对恢复回复消息。自己体会吧。框架毫无意义

        /**
         * 微信初始化接口.
         */
        public function serve(Request $request)
        {
            if (config('wechat.wechat_signature')) {
                // 获取到微信请求里包含的几项内容
                $echoStr = $_GET['echostr'];
                $signature = $_GET['signature'];
                $timestamp = $_GET['timestamp'];
                $nonce = $_GET['nonce'];
                // 是我在微信后台手工添加的 token 的值
                $token = config('wechat.token');
    
                // 加工出自己的 signature
                $our_signature = array($token, $timestamp, $nonce);
                sort($our_signature, SORT_STRING);
                $our_signature = implode($our_signature);
                $our_signature = sha1($our_signature);
                // 用自己的 signature 去跟请求里的 signature 对比
                if ($our_signature != $signature) {
                    return false;
                } else {
                    echo $echoStr;
                    exit;
                }
            } else {
                $response = $this->wechatService->serve();
                $response->send();
            }
        }
    

    这是后台对应页面,目的是根据匹配用户自定义参数针对回复

    Markdown

    这是处理的方法:这个倒还 OK,但是为啥要写在一个好无关联的方法内???

        /**
         * @param $data
         *
         * @return object
         */
        public function customQrCode($data)
        {
            $fileName = time();
            $fileName = $this->createImgName('custom_', $fileName);
            $directory = $this->createDir();
            $this->checkDirectory($directory);
            $url = $this->getImgContent($data['custom_name']);
            $img = $directory.DIRECTORY_SEPARATOR.$fileName;
            file_put_contents($img, $url);
            $result = $this->uploadMaterial($img);
            $data['media_id'] = $result['media_id'];
            $data['remote_url'] = $result['url'];
            $data['local_url'] = $img;
            $data['type'] = 0;
            $obj = Material::query()->create($data);
    
            return $obj;
        }
    

    这是微信推送的方法,为啥不把素材跟消息单独封装在一个类的。写入用户信息为何不拿出来封装一下。

    /**
         * @author  hepengfei
         *
         * 文档说明 3.x 版 https://www.easywechat.com/docs/3.x/zh-CN/server
         *
         * 微信初始化入口
         *
         * @return response
         */
        public function serve()
        {
            $app = $this->app;
            $server = $app->server;
            $server->setMessageHandler(function($message) use($app){
                // 注意,这里的 $message 不仅仅是用户发来的消息,也可能是事件
                // 当 $message->MsgType 为 event 时为事件
                $user_openid = $message->FromUserName ;
                if ($message->MsgType == self::MSGTYPE_EVENT) {
                    switch ($message->Event) {
                        case self::EVENT_SUBSCRIBE:
                            # 如果关注 注册用户信息
                            $user_info['openid'] = $user_openid;
                            $userService = $app->user;
                            $user = $userService->get($user_info['openid']);
                            $user_info['subscribe_time'] = $user['subscribe_time'];
                            $user_info['unionid'] = $user['unionid'];
                            $user_info['nickname'] = filterEmoji($user['nickname']);
                            $user_info['avatar'] = $user['headimgurl'];
                            $user_info['sex'] = $user['sex'];
                            $user_info['province'] = $user['province'];
                            $user_info['city'] = $user['city'];
                            $user_info['country'] = $user['country'];
                            $user_info['is_subscribe'] = 1;
                            # 微信自带前缀 qrscene_ 拆分获取 homeworkid
                            if (empty($message['EventKey'])) {
                                # 搜索关注用户来源
                                $user_info['source'] = 1;
                                if ($this->weixin_model->addDate($user_info)) {
                                    Log::info('添加用户信息成功');
                                } else {
                                    Log::error('添加用户信息失败');
                                }
                                return '欢迎关注答题通小学版的公众号!';
                            } else if($message['EventKey'] == 'qrscene_客服') {
                                # 客服二维码用户来源
                                $user_info['source'] = 2;
                                if ($this->weixin_model->addDate($user_info)) {
                                    Log::info('添加用户信息成功');
                                } else {
                                    Log::error('添加用户信息失败');
                                }
                                return '答题通人工客服的工作时间为 08:30 至 20:30,如需帮助或反馈意见,欢迎在此发送消息给我们';
                            } else {
                                # 习题二维码用户来源
                                $user_info['source'] = 3;
                                $result = explode('qrscene_',$message['EventKey']);
                                $homework = Homework::query()->find($result[1]);
                                $title = $this->newsName($homework->volume,$homework->grade_id,$homework->lesson);
                                $url = $this->newsUrl($homework->homework_version_id,$homework->grade_id,$homework->day);
                                $news = new News([
                                    'title'       => $title,
                                    'url'         => $url,
                                    'image'       => getScheme($path = '/[email protected]'),
                                    // ...
                                ]);
                                if ($this->weixin_model->addDate($user_info)) {
                                    Log::info('添加用户信息成功');
                                } else {
                                    Log::error('添加用户信息失败');
                                }
                                return $news;
                            }
    
                            break;
    
                        case self::EVENT_UNSBUSCRIBE:
                            # 取消关注更改关注状态 1 关注 0 未关注
                            $user_info['openid'] = $user_openid;
                            $user_info['is_subscribe'] = 0;
                            $this->weixin_model->addDate($user_info);
                            return 'bye';
                            break;
    
                        case self::EVENT_SCAN:
                            #带参二维码中的数值
                            if ($message['EventKey'] == '客服') {
                                return '答题通人工客服的工作时间为 08:30 至 20:30,如需帮助或反馈意见,欢迎在此发送消息给我们';
                            } else {
                                $homework = Homework::query()->find($message['EventKey']);
                                $title = $this->newsName($homework->term,$homework->grade_id,$homework->lesson);
                                $url = $this->newsUrl($homework->homework_version_id,$homework->grade_id,$homework->day);
                                $news = new News([
                                    'title'       => $title,
                                    'url'         => $url,
                                    'image'       => getScheme($path = '/[email protected]'),
                                    // ...
                                ]);
                                return $news;
                            }
                            break;
    
                        default:
                            # code...
                            return "hello";
                            break;
                    }
                } elseif ($message->MsgType == self::MSGTYPE_TEXT) {
                    # 发送客服消息必须实例化响应的类 Text Image News Article
                    $img = new Image(['media_id' => 'abIQFxsaJtMdCSbMwa_Ntj9fFvF39rl2Osa2KwiTVqI']);
                    $text = new Text(['content' => '我在写代码']);
                    # 客服发送小程序卡片
                    $miniprogrampage = new Raw('{"touser":"'.$user_openid.'",
                            "msgtype":"miniprogrampage",
                            "miniprogrampage":
                            {
                                "title":"小程序卡片测试",
                                "appid":"wx1e078baea0622aa4",
                                "pagepath":"pages/index/index",
                                "thumb_media_id":"abIQFxsaJtMdCSbMwa_Ntj9fFvF39rl2Osa2KwiTVqI"
                            }
                    }');
                    $app->staff->message($miniprogrampage)->to($user_openid)->send();
                    $app->staff->message($img)->to($user_openid)->send();
                    $app->staff->message($text)->to($user_openid)->send();
                    $news = new News([
                        'title'       => '测试',
                        'description' => '...',
                        'url'         => 'http://www.baidu.com',
                        'image'       => getScheme($path = '/[email protected]'),
                        // ...
                    ]);
                    $news1 = new News([
                        'title'       => '测试 1',
                        'description' => '...',
                        'url'         => 'http://www.baidu.com',
                        'image'       => getScheme($path = '/[email protected]'),
                        // ...
                    ]);
    
                    return [$news,$news1];
                } elseif ($message->MsgType == self::MSGTYPE_IMAGE) {
                    return '图片信息';
                } elseif ($message->MsgType == self::MSGTYPE_VOICE){
                    return '声音信息';
                } elseif ($message->MsgType == self::MSGTYPE_VIDEO){
                    return '视频信息';
                } elseif ($message->MsgType == self::MSGTYPE_LINK) {
                    return '链接信息';
                } elseif ($message->MsgType == self::MSGTYPE_LOCATION) {
                    return '位置信息';
                } else {
                    return '你在干什么';
                }
    
            });
    
            $response = $server->serve();
            return $response;
        }
    

    如果卡死在客服身上,为何要后台添加自定义参数????真是日了狗了。发发牢骚,然后自己改吧。。。。。。。

    第 1 条附言  ·  2018-09-30 11:48:24 +08:00
    更改之后的代码在这里 https://www.v2ex.com/t/494110#reply0
    70 条回复    2018-10-02 12:11:32 +08:00
    xiqingongzi
        1
    xiqingongzi  
       2018-09-29 16:36:34 +08:00   ❤️ 1
    这种程序员,感觉把 rails 给他,也是写出和 shit 一样的代码....
    coffeygao
        2
    coffeygao  
    OP
       2018-09-29 16:38:43 +08:00
    @xiqingongzi 是的,跟他去讲这些东西也不是很清楚。自己做的东西自己都不清楚逻辑,让找个方法半天也找不到。我跟他说什么????
    anyforever
        3
    anyforever  
       2018-09-29 16:39:17 +08:00   ❤️ 2
    这是人的问题,给他什么也拯救不了。。
    GTim
        4
    GTim  
       2018-09-29 16:40:15 +08:00
    楼主,第一个你吐槽的是 $_GET 吧? 最后一个,吐槽的是代码太长?
    qqjt
        5
    qqjt  
       2018-09-29 16:40:17 +08:00
    easywechat 了解一下
    coffeygao
        6
    coffeygao  
    OP
       2018-09-29 16:40:20 +08:00
    @anyforever 对啊。框架的东西其实也没用。get post 也是用的原生
    GTim
        7
    GTim  
       2018-09-29 16:41:12 +08:00
    错了,最后一个是可以把不同类型划分为小函数的
    coffeygao
        8
    coffeygao  
    OP
       2018-09-29 16:42:07 +08:00
    @GTim 是的。但并非吐槽代码长。开发过程中难免会遇到长代码。但这么写,把啥功能都塞进一个方法里。着实让人头疼。
    coffeygao
        9
    coffeygao  
    OP
       2018-09-29 16:42:58 +08:00
    @qqjt 他已经用户了 easywechat........但是污染了 laravel & easywechat!
    mokeyjay
        10
    mokeyjay  
       2018-09-29 16:50:27 +08:00
    想知道你出于什么想法非要把 Laravel 扯上,明明你也知道不是框架的问题
    coffeygao
        11
    coffeygao  
    OP
       2018-09-29 16:51:51 +08:00
    @mokeyjay 没有什么框架问题。只因他用了 laravel,所以有一层意思是说他不善用框架本身方法
    097ecom
        12
    097ecom  
       2018-09-29 16:58:07 +08:00
    这锅 laravel 不背
    way2create
        13
    way2create  
       2018-09-29 17:04:29 +08:00
    问他:你在干什么?
    way2create
        14
    way2create  
       2018-09-29 17:06:38 +08:00   ❤️ 3
    个人对 laravel 比较没什么感觉,但是不太喜欢动不动写个什么都要扯优雅,也反感个别 php 基础都没学好就跟风学 laravel 的,对人, 不对框架
    skdyk
        15
    skdyk  
       2018-09-29 17:11:17 +08:00
    起码还知道用 service,见过所有代码全部放在 Controller 里的吗?毫无封装的意识,上千行代码一个 action 全部撸下来,见到这种代码,入职第一天就像跑路
    jowan
        16
    jowan  
       2018-09-29 17:11:24 +08:00
    我觉得 laravel 很好用 但从来不会跟别人说:来 看我这代码 优雅不!
    coffeygao
        17
    coffeygao  
    OP
       2018-09-29 17:13:05 +08:00
    @097ecom 总要有个背锅侠😂
    coffeygao
        18
    coffeygao  
    OP
       2018-09-29 17:14:40 +08:00
    @way2create 优不优雅咱不说,哪怕代码写一万行写在一个方法里。能不能给方法说明。。。注释之类的。。
    coffeygao
        19
    coffeygao  
    OP
       2018-09-29 17:15:18 +08:00
    @skdyk 没办法。我爱这家公司😂。我还是耐下性子大概改动下。
    coffeygao
        20
    coffeygao  
    OP
       2018-09-29 17:15:35 +08:00
    @jowan 这样会被打是不
    coffeygao
        21
    coffeygao  
    OP
       2018-09-29 17:16:50 +08:00
    最可气的是,明明是他写的。author 的时候 写的是 coffey.....日了狗
    LuffyGu
        22
    LuffyGu  
       2018-09-29 17:31:21 +08:00
    封装一下多好
    Felldeadbird
        23
    Felldeadbird  
       2018-09-29 17:33:52 +08:00
    每个人水平不一样,要解决这个问题的终极方法:和水平一样的人一起工作。
    coffeygao
        24
    coffeygao  
    OP
       2018-09-29 17:39:48 +08:00
    @LuffyGu 最怕多年以后此人看到这代码还是无感
    coffeygao
        25
    coffeygao  
    OP
       2018-09-29 17:40:25 +08:00
    @Felldeadbird 在理,可能别的水平高的人看了我写的代码。也会发出这样的声音。
    xfcy
        26
    xfcy  
       2018-09-29 18:02:18 +08:00 via Android
    @way2create 对头,“优雅”这词看到吐😂
    silenM
        27
    silenM  
       2018-09-29 18:03:37 +08:00
    语音框架无罪 锅在于人
    nosay
        28
    nosay  
       2018-09-29 18:08:54 +08:00 via iPhone
    我猜接下来楼主该祭出 Notadd 重构了😂
    coffeygao
        29
    coffeygao  
    OP
       2018-09-29 18:10:01 +08:00
    @nosay notadd 关我啥事。作者只是我朋友而已。
    madaima
        30
    madaima  
       2018-09-29 18:15:14 +08:00
    talk is cheap show me the code
    ben1024
        31
    ben1024  
       2018-09-29 18:19:28 +08:00
    开发是个复杂的事情,从人员招聘,培训,约定,规范等
    ooh
        32
    ooh  
       2018-09-29 18:29:55 +08:00 via Android
    你都说了这是个 service 了 还无脑喷
    whyiyhw
        33
    whyiyhw  
       2018-09-29 18:44:08 +08:00 via Android
    怎么说呢,$_GET 就说明这个要不,不习惯 laravel,要不就是不习惯框架,如果这个代码是赶时间写出来的不奇怪,但是一般空一点点的时候,我都会把自己赶时间写的东西再封装整理一遍… 其实就和现在看我以前写的代码,我自己都嫌弃,但写代码本身就是一个不断改进学习的方式,我觉得可以多沟通下,不然以后更心烦
    coffeygao
        34
    coffeygao  
    OP
       2018-09-29 23:59:22 +08:00
    @whyiyhw 是的,我中秋收假耐下心来跟他沟通过之后。让他有时间优化。并没有。于是我就开始优化了。不尽人意的是好像有些人并不喜欢听意见。
    coffeygao
        35
    coffeygao  
    OP
       2018-09-29 23:59:46 +08:00
    @ooh 我感觉你就是个大菠萝喷子
    coffeygao
        36
    coffeygao  
    OP
       2018-09-30 00:02:42 +08:00
    @madaima 这两天这块优化完以后会再补充
    Z1076
        37
    Z1076  
       2018-09-30 01:13:07 +08:00 via iPhone
    改了他的代码出问题会要你背锅不? 他 pull 下来发现代码被你改了会发飙不 感觉还是沟通下好,尝试下指出他的问题,或者反馈给部门老大
    illuminate
        38
    illuminate  
       2018-09-30 04:51:15 +08:00
    Laravel 黑其实黑的是他从 `public/index.php` 进入后所执行步骤之多,导致 100 多 ms,都在 bootstrap 阶段,后面才走到你的业务。

    [[教程] Laravel 深入浅出指南 —— 祝大家国庆节快乐]( https://www.v2ex.com/t/494009#reply0)
    msg7086
        39
    msg7086  
       2018-09-30 06:33:05 +08:00   ❤️ 1
    @xiqingongzi 我司就有把 Rails 写上天的大佬……看代码看到吐血……
    xuanbg
        40
    xuanbg  
       2018-09-30 06:38:51 +08:00
    脑子是个好东西,可惜有的人他就是没有。。。没脑子的人写程序简直就是灾难,无论是对别人还是对他自己。我遇上这种人一般都是劝退,去做点不需要脑子的事情比写程序有前途多了。
    xiqingongzi
        41
    xiqingongzi  
       2018-09-30 07:57:25 +08:00
    @msg7086 #39
    MntCw
        42
    MntCw  
       2018-09-30 08:33:37 +08:00 via Android
    这段代码是跑起来效率低?还是写得不够好看?还是用的 API 不对?
    xuanbg
        43
    xuanbg  
       2018-09-30 08:56:00 +08:00
    @MntCw 结构不对,你理解为不够好看也可以。毕竟代码还是要维护的,这种代码没法维护,非要维护就得全部删除重写。
    MntCw
        44
    MntCw  
       2018-09-30 08:59:05 +08:00 via Android
    @xuanbg OK 明白啦!仔细看了下 注释写得太少。
    coffeygao
        45
    coffeygao  
    OP
       2018-09-30 09:05:03 +08:00
    @Z1076 他知道我改他代码。我指出让他修改。然而并没用。他 git 不是很熟。经常 git pull 冲突
    coffeygao
        46
    coffeygao  
    OP
       2018-09-30 09:06:12 +08:00
    @xuanbg 没必要劝退他。只能告诉他如何才会对他提升有帮助。具体怎么做还是看个人
    coffeygao
        47
    coffeygao  
    OP
       2018-09-30 09:07:31 +08:00
    @MntCw 注释是一部分。改封装抽离的方法也没。全部塞在一个方法了。可读性特别差,维护性特别差,框架对此人来说毫无作用
    Seanfuck
        48
    Seanfuck  
       2018-09-30 09:15:59 +08:00
    这才多少行,并没什么问题,优雅不是用什么框架什么结构,是清晰易读。
    sagaxu
        49
    sagaxu  
       2018-09-30 09:26:55 +08:00 via Android
    适度封装就好,后续有需求可以不断提炼重构。

    注释只要指出几个关键点,或者反直觉的思路,多了就是啰嗦。
    coffeygao
        50
    coffeygao  
    OP
       2018-09-30 09:27:43 +08:00
    @Seanfuck 其实此代码本身无关框架。主要还是自身 code style,你没感觉这段不是很长的代码维护性可读性特别差吗
    falcon05
        51
    falcon05  
       2018-09-30 09:29:14 +08:00 via iPhone
    这个标题逻辑就很混乱啊
    coffeygao
        52
    coffeygao  
    OP
       2018-09-30 09:29:25 +08:00
    @sagaxu 是的。我本身也是一个初学者,我正常尝试提炼代码。部分已经进行封装。我发现很多人并不是很喜欢听别人的建议,总把它当成意见。
    Yuansir
        53
    Yuansir  
       2018-09-30 09:32:55 +08:00
    吐槽代码就行了,带上 Laravel 确实不太好
    coffeygao
        54
    coffeygao  
    OP
       2018-09-30 09:34:52 +08:00
    @Yuansir 受教了。其实我也开头说了无关框架本身。
    sagaxu
        55
    sagaxu  
       2018-09-30 09:41:30 +08:00 via Android
    @coffeygao 因为别人的意见不总是对的,也不一定是自己认同的。即使是自己的意见,也不见得会采纳,比如我觉得某个模块代码质量下降了,应该要重构了,我也不一定会做,我要评估成本和风险,以及给我自身带来的收益。

    代码优雅和眼前的快速迭代之间如何取舍?管理层更注重工期还是代码优雅?

    你贴的代码虽然不优雅,还有很大改进余地。但平心而论,可读性并不差啊,我完全不懂你们业务的情况下,也能比较顺畅的读懂。
    coffeygao
        56
    coffeygao  
    OP
       2018-09-30 09:50:28 +08:00
    @sagaxu 那在可读性这块是我理解错了。还有参数命名。有下划线有驼峰??
    phpcxy
        57
    phpcxy  
       2018-09-30 09:53:27 +08:00
    重构下代码吧
    okjb
        58
    okjb  
       2018-09-30 09:59:32 +08:00
    你的下面还有吐槽安卓的 [滑稽]
    kearone
        59
    kearone  
       2018-09-30 10:10:07 +08:00
    用了 easywechat,那么可以写专门的 handler 去处理不同的消息类型的
    imagecap
        60
    imagecap  
       2018-09-30 10:23:48 +08:00
    LZ 贴下自己的代码,我就不信没人喷,^_^
    iRiven
        61
    iRiven  
       2018-09-30 10:48:59 +08:00 via Android
    默默的把自己带入那个被喷的人。。。
    sagaxu
        62
    sagaxu  
       2018-09-30 11:10:46 +08:00 via Android
    @coffeygao 可读和优雅是不同纬度的指标,有时甚至是对立的。广场舞大妈们觉得凤凰传奇好还是莫扎特好?

    混用驼峰和下划线难道不是 php 的传统么?标准库里就有大量混用的例子,有人为了优雅重构掉 php 的这种混乱吗?

    命名风格是不是一致,{要不要新起一行写,这类都是 style 或者口味问题,并不会影响可读性。如果重视这个事情,口头约定是没用的,写入公司编码规范也是徒劳的,甚至 review 都解决不了这个问题。比较有用的是把规则检查写到 vcs 的 hook 里,不符合规范的代码,提交入库的时候自动拒绝。
    sobigfish
        63
    sobigfish  
       2018-09-30 11:30:07 +08:00
    回消息全是写死了测试,应该会重构的吧,应该只是测试用的代码吧? 不要告诉我是上线的😂
    coffeygao
        64
    coffeygao  
    OP
       2018-09-30 11:45:45 +08:00
    @sobigfish 这是已经上线了的东西。只是这次另外一个新任务指给我。我就得在这基础进行修改。 修改后的代码在这 https://www.v2ex.com/t/494110
    coffeygao
        65
    coffeygao  
    OP
       2018-09-30 11:46:53 +08:00
    @sagaxu 感谢指导。我做了一些简单的优化在我的另外一篇主题
    jswh
        66
    jswh  
       2018-09-30 14:04:07 +08:00
    这种代码,在 review 的时候应该不予通过
    coffeygao
        67
    coffeygao  
    OP
       2018-09-30 14:21:53 +08:00
    @jswh 我们没有 review 这个缓解
    yogogo
        68
    yogogo  
       2018-09-30 16:07:44 +08:00
    这是个人的问题吧~我还遇到过一个函数 1000 行~_(:ェ 」∠)_
    jswh
        69
    jswh  
       2018-09-30 16:57:52 +08:00
    @coffeygao 我最近在组里强推 fork + pull request 的流程。必须要有 code review 才能合并代码。而且说好了,代码是写的人和 review 的人的共同责任。不过我们组比较小,比较好沟通。

    想要每个人都认真写代码有时候是不太现实的。不是每个人都要强迫症,比如一个函数不超过 20 行或者 if 嵌套不超过三层之类的。也不是每个人都那么有追求的,写好写坏只要功能正常,工资又不会少。所以我个人是觉得,除了对自己要求之外,代码质量这种东西只能从制度上来保障。

    基本的代码质量保障,要么写 UT (代码写得渣 UT 没法写),要么 code review,两个都没有,开发自己也会在业务压力下慢慢松懈。如果没有“传统”的话,UT 的推广难度,比 review 要难的多,毕竟 UT 是自己监督自己,review 是别人监督自己。所以如果有条件的话,可以推一下。基于 fork + pr 的代码集成流程下,强制 review 加一下还比较简单。

    除了自己写自己的代码,团队的代码质量好不好,本质上是个管理问题。

    刚睡醒,胡乱说几句。
    mingyun
        70
    mingyun  
       2018-10-02 12:11:32 +08:00
    @jswh code review 用的什么工具,推行起来会增加工作量,可能有点困难
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1001 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 19:10 · PVG 03:10 · LAX 11:10 · JFK 14:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.