あるプログラマの日記

プログラマのメモ、出来事、考えたこと、勉強とかの雑記

SAXパーサーの parseメソッドに渡した InputStream の後始末

org.xml.sax.helpers.XMLReaderFactory.createXMLReader() で返されるパーサーの parseメソッドにInputSourceの引数で渡している InputStream が
処理後、closeしていなかったので、リソースが解放されていない可能性を調べてみた。

 lsof -p プロセスID|grep ファイル名

オープンしていたファイルはしばらくして表示されなくなったので close されているようだ。

XMLReaderFactory.createXMLReader() で返されるパーサーの実態クラスは org.apache. xerces . parsers.SAXParser

念のため parseメソッドを呼び出して処理後に InputStream の read をしてみると "Stream Closed" の IOException が発生した。

このパーサーオブジェクトの parseメソッドにInputSourceの引数として渡した InputStream はparseメソッド内で close されているので、呼び出し側はcloseする必要がなかった。

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

    // ...

    File file = new File(fileName);

    InputStream input = null;
    try {
        input = new FileInputStream(file);

        XMLReader xmlRaeder = XMLReaderFactory.createXMLReader();
        xmlReader.parse(new InputSource(input));
        // ...
    }
    catch(IOException x) {
        // ...
    }
    catch(SAXException x) {
        // ...
    }
    finally {
        // 正常時は xmlReader.parseで InputStrem は close されている。
        if (input != null) {
            try { input.close(); } catch(IOException x) { .. }
        }
    }

※ java のバージョンは1.6.0_26

プログラマをする前

プログラマ・SEをする前はIT関係の営業を4年半やっていました。

大学は文系でプログラミングの経験はなく、ITとはまったく無縁の学生生活を送っていました。

なので、プログラマ・SEになることは就活の時点でまったく考えていませんでした。

最初に就職した会社には、就活期間の後半になんとか内定を頂けた次第で
この時は自分の学生生活を振り返り、後悔しきりでした。

営業の仕事は、ルート営業ではなく、新規に顧客を開拓してシステムを販売することです。
他に本社関連の案件でシステム導入した地方の客先に出張して現調・システム導入の立会いを
やっていました。

上司はバリバリの営業叩き上げのドスの聞いた声の強面部長でした。
入社してから3年くらいまでは部長によく怒られていました。

慣れるまでは楽な仕事ではなかったのですが、徐々に契約がとれてお客様が増えていくと、
日々の仕事は、上司からの苦言もなくなり自由にやらせてもらうことができるようになりました。

仕事は充実していったのですが年度評価に対して納得いかないことや疑問に思う事があり、
ある事がきっかけでソフトウェアを開発する違う企業に転職しました。

ある事というのは、仕事上でのちょっとした出来事です。

Debian 9 に Maven をインストール 、その後、動作確認

1. Debian 9 に Maven をインストールする。

# apt-get install maven 

..snip..

maven (3.3.9-4) を設定しています ...
update-alternatives: /usr/bin/mvn (mvn) を提供するために自動モードで /usr/share/maven/bin/mvn を使います

2. インストール後に Maven のバージョンを確認

# mvn -version
Apache Maven 3.3.9
Maven home: /usr/share/maven
Java version: 1.8.0_25, vendor: Oracle Corporation
Java home: /usr/lib/jvm/jdk1.8.0_25/jre
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "4.9.0-9-686-pae", arch: "i386", family: "unix"

3. プロジェクトの作成
途中、'groupID': は com.myapp を、'artifactId': は myapp を入力、それ以外は Enter を入力

$ mvn archetype:generate
[INFO] Scanning for projects...
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom (4 KB at 0.9 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-plugins/22/maven-plugins-22.pom

..snip..

Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 1470: 
 
Choose org.apache.maven.archetypes:maven-archetype-quickstart version: 
1: 1.0-alpha-1
2: 1.0-alpha-2
3: 1.0-alpha-3
4: 1.0-alpha-4
5: 1.0
6: 1.1
7: 1.3
8: 1.4
Choose a number: 8: 

.. snip ..

Define value for property 'groupId': com.myapp
Define value for property 'artifactId': myapp
Define value for property 'version' 1.0-SNAPSHOT: : 
Define value for property 'package' com.myapp: : 
Confirm properties configuration:
groupId: com.myapp
artifactId: myapp
version: 1.0-SNAPSHOT
package: com.myapp
 Y: : 
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: maven-archetype-quickstart:1.4
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: com.myapp
[INFO] Parameter: artifactId, Value: myapp
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: com.myapp
[INFO] Parameter: packageInPathFormat, Value: com/myapp
[INFO] Parameter: package, Value: com.myapp
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: groupId, Value: com.myapp
[INFO] Parameter: artifactId, Value: myapp
[INFO] Project created from Archetype in dir: /home/xxxx/project/work/myapp

.. snip ..

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 19:50 min
[INFO] Finished at: 2020-01-26T15:45:40+09:00
[INFO] Final Memory: 13M/61M
[INFO] ------------------------------------------------------------------------

4. 検証する。

$ cd myapp

$ mvn validate
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building myapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.977 s
[INFO] Finished at: 2020-01-26T15:48:00+09:00
[INFO] Final Memory: 4M/15M
[INFO] ------------------------------------------------------------------------

5. コンパイルする。

$ mvn compile
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building myapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-resources-plugin/3.0.2/maven-resources-plugin-3.0.2.pom

..snip..

Downloaded: https://repo.maven.apache.org/maven2/com/thoughtworks/qdox/qdox/2.0-M9/qdox-2.0-M9.jar (310 KB at 34.4 KB/sec)
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/xxxx/project/work/myapp/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:22 min
[INFO] Finished at: 2020-01-26T15:50:49+09:00
[INFO] Final Memory: 14M/37M
[INFO] ------------------------------------------------------------------------

6. テストする。

~/project/work/myapp$ mvn test
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building myapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-surefire-plugin/2.22.1/maven-surefire-plugin-2.22.1.pom

..snip..

Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-junit4/2.22.1/surefire-junit4-2.22.1.jar (83 KB at 48.7 KB/sec)
[INFO] 
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.myapp.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.369 s - in com.myapp.AppTest
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 56.263 s
[INFO] Finished at: 2020-01-26T16:04:26+09:00
[INFO] Final Memory: 16M/40M
[INFO] ------------------------------------------------------------------------

7. パッケージを生成する。

~/project/work/myapp$ mvn package
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building myapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-jar-plugin/3.0.2/maven-jar-plugin-3.0.2.pom

..snip..

[INFO] Building jar: /home/xxxx/project/work/myapp/target/myapp-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 28.561 s
[INFO] Finished at: 2020-01-26T16:08:19+09:00
[INFO] Final Memory: 12M/97M
[INFO] ------------------------------------------------------------------------

8. フォルダ構成を確認する。

$ tree
.
├── pom.xml
├── src
│   ├── main
│   │   └── java
│   │       └── com
│   │           └── myapp
│   │               └── App.java
│   └── test
│       └── java
│           └── com
│               └── myapp
│                   └── AppTest.java
└── target
    ├── classes
    │   └── com
    │       └── myapp
    │           └── App.class
    ├── generated-sources
    │   └── annotations
    ├── generated-test-sources
    │   └── test-annotations
    ├── maven-archiver
    │   └── pom.properties
    ├── maven-status
    │   └── maven-compiler-plugin
    │       ├── compile
    │       │   └── default-compile
    │       │       ├── createdFiles.lst
    │       │       └── inputFiles.lst
    │       └── testCompile
    │           └── default-testCompile
    │               ├── createdFiles.lst
    │               └── inputFiles.lst
    ├── myapp-1.0-SNAPSHOT.jar
    ├── surefire-reports
    │   ├── TEST-com.myapp.AppTest.xml
    │   └── com.myapp.AppTest.txt
    └── test-classes
        └── com
            └── myapp
                └── AppTest.class

28 directories, 13 files

9. pom.xml を変更する。
pom.xml のバックアップを取ってから、編集する。

$ cp -aiv pom.xml pom.xml.`date +%Y%m%d`
'pom.xml' -> 'pom.xml.20200126'

$ vi pom.xml
$ diff -u pom.xml.`date +%Y%m%d` pom.xml
--- pom.xml.20200126	2020-01-26 15:45:40.525060334 +0900
+++ pom.xml	2020-01-26 16:56:36.444269386 +0900
@@ -51,6 +51,15 @@
         <plugin>
           <artifactId>maven-jar-plugin</artifactId>
           <version>3.0.2</version>
+          <configuration>
+            <archive>
+              <manifest>
+	        <addClasspath>true</addClasspath>
+                <classpathPrefix>lib/</classpathPrefix>
+                <mainClass>com.myapp.App</mainClass>
+              </manifest>
+	    </archive>
+          </configuration>
         </plugin>
         <plugin>
           <artifactId>maven-install-plugin</artifactId>

10. パッケージを再生成する。
clean してから package を作成する。

$ mvn clean
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building myapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/3.1.0/maven-clean-plugin-3.1.0.pom

$ mvn package
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building myapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ myapp ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
..snip..

[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ myapp ---
[INFO] Building jar: /home/xxxx/project/work/myapp/target/myapp-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 16.653 s
[INFO] Finished at: 2020-01-26T16:59:54+09:00
[INFO] Final Memory: 12M/99M
[INFO] ------------------------------------------------------------------------

11. 動作を確認
作成後の jar ファイルを実行して動作を確認する。

$ LANG=C java -jar target/myapp-1.0-SNAPSHOT.jar
Hello World!

Debian 9 へ OpenJDK をインストール

Debian 9 へOpenJDKをインストールする。

# apt-get update

# apt-get install default-jdk


複数のバージョンがインストールされている場合は、
下のコマンドでバージョンを切り替える。

 # update-alternatives --config java

 
切り替えたjava のバージョンを確認する。

# java -version

openjdk version "1.8.0_232"
OpenJDK Runtime Environment (build 1.8.0_232-8u232-b09-1~deb9u1-b09)
OpenJDK Server VM (build 25.232-b09, mixed mode)

# javac -version
javac 1.8.0_232


http://openjdk.java.net

レトロコードの不吉な匂い

最近の仕事は、過去に java で開発したシステムのバージョンアップを行っていますが
java のバージョンは過去のままで行っています。(レトロ)

10年くらい前に開発していたシステムですが、今見直すとリファクタリングした方が良いと思うコードがところどころあります。コードの「不吉な匂い」が...

 

数年前の自分は、もはや他人。
過去に自分が書いたコードも、現時点で見直すと「何か変」ということもあったりします。

コードが属人化してしまっているのを見ると他のプログラマーからの介入を防ぐためか、リファクタリングを避けて障壁を築いているのかと思ってしまうことがある...
(勘繰りが過ぎると!)

属人化は、長期的にみてプロジェクトチームや企業の損失なります。
他の人で対応できないため特定の個人だけで対応することになり
内部の問題が顕在化しないため、導入後に問題が発生したりするなど様々な弊害がでます。


改めて「リファクタリング」というのは
外部的な振る舞いを保ちつつ、内部構造を改善すること。
外部の動作や機能は変化しないままで、

内部コードの設計や構造を変更して改善すること。

 

「内部構造を改善すること」とは、

すぐ理解できるような構造にすること。

コードを見てその目的がわかるようにすること。

 

人が理解しづらいコードは、コードを見てもその目的がわからないため
コードが読みにくく変更や追加を行うのに時間がかかり、
かつバグを作りこんでしまうリスクも高くなります。

 

プログラムは完成した後も頻繁に仕様が変更されたり

機能が追加されたりするものです。
将来の仕様変更に備えてコードの修正箇所を正確に速く見つけてることができ

るようにしておくと作業効率が良くなり、バグが入り込む余地も少なくなります。


なので、常に、変更・追加がしやすいように理解しやすく見通しがよいコードに
保っておく必要があります。
オブジェクト指向プログラミングの利点を活かせるようにしておくことが重要です。
ポイントは
 ・可読性
 ・再利用性
 ・柔軟性


リファクタリングの目的
 ・設計の向上
 ・設計の劣化防止
 ・理解しやすいコードを保つ
 ・バグの特定
 ・プログラミングの迅速化

 

リファクタリングを始める前に、対象コードに対するテストコードを

書くことが必須です。

人の手が入るとどうしてもバグが入り込む余地がでてくるので
小さなステップでリファクタリングを繰り返して、その都度、自動テスト(JUnitなど)を行うようにするのが安全です。


リファクタリングのタイミング

 ・過去に作成したときに良いと思えた設計が現時点で

  見直すとミスマッチであると認識できた時点でリファクタリングを行う。

 ・重複コードを発見した時
  コードの重複部部をなくす。メソッド化する。
  それによって結果的にコード量を減らすことができます。

 ・コードを理解するときにリファクタリングを行う。

 

新年、明けましておめでとうございます。

あけましておめでとうございます。

今年もよろしくお願いします。

昨年の前半は以前から携わっていたシステムへの追加機能の開発と、後半は
過去に開発したシステムをベースに違うバージョンのシステムを開発していました。

今年も昨年後半の案件を継続して行う予定です。

 

「2020年の抱負」は、もっと多くの方とかかわれるようなことをやること。
今の仕事は継続して続けて行きたいのですが、さらに、もっと多くの方と

かかわる仕事もすることです。

 

昨年は、体調面では体の故障や不調が続きました。
左手のテニス肘、右ふくらはぎ肉離れ、肋骨の骨折、謎の発熱と神経痛…
整形外科と内科に頻繁に行きました。特に整形外科の込み具合は半端なかった。
午前9時に整形外科に行ったのだが午後を過ぎても診察の順番がまわってこなかった。
この時、もうここの整形外科のお世話にはなりたくないものだとつくづく思いました。


この間、仕事は休むこともなく続けていました。
肉離れした時は、松葉杖で出勤しましたが、かなり大変だった。
職場に着いたときはくたくた、怪我していない左足が筋肉痛になってしまった。

 

最近は右手でつっぱたり、右の手首を回すと痛くて
腱鞘炎なのかと思っていましたが、調べてみると症状が
三角線維軟骨複合体(TFCC)というのに似ています。

 

今年は、健康面でもっと注意する必要がありそうです。
普段の生活で無理しないようにするのと、もっと体を鍛えようと思います。

最近のお仕事

近況ですが、java での開発から C/C++, JavaScript を使った開発が今はメインになっています。

現在、ざっくりとした要求仕様から、[基本仕様]-[詳細仕様] が確定していない状態で開発するスタイルが板に付いています。実装(コーディング)前の設計段階で、曖昧な仕様箇所を redmine のチケットにあげています。曖昧な箇所は、レアケースな処理やイレギュラーなイベントが起こった場合の処理がほとんどです。エラーが発生した場合、内部でどのように処理を行うか、処理を継続するか、終了するか。外部ではユーザーにどのようにエラーイベントの内容を伝えるか。エラーメッセージを表示するか。初期状態にもどすか、など。

仕様が決まる過程で、いろいろと意見をいったり、仕様に納得できないときは、仕様の根拠を突き詰めて追及してしまうため、煙たがられる面もありますが恣意的で不合理な仕様に対しては、できるかぎり抵抗しています。

過去の仕事では、仕様確定の進め方・過程で考えさせられることが多かったです。要求仕様を出す側も、それを元に開発を進める側も、どの仕様がベストなのかがわからない場合いくつかの選択肢を抽出して、その内容をお互いで共有した後、内容について議論し合ってから要求仕様を出す側で仕様を決定してもらうというのがベストだと考えています。